Eu tinha um monte de mudanças em estágios e não em estágios e queria mudar rapidamente para outro branch e depois voltar.
Então, preparei minhas alterações usando:
$ git stash push -a
(Olhando para trás, provavelmente poderia ter usado em --include-untracked
vez de --all
)
Então, quando fui abrir o estoque, recebo uma série de erros do tipo:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
Não parece haver nenhuma alteração restaurada do stash.
Eu também tentei, $ git stash branch temp
mas mostra os mesmos erros.
Eu descobri uma maneira de contornar isso que era usar:
$ git stash show -p | git apply
Desastre evitado por enquanto, mas isso levanta algumas questões.
Por que esse erro aconteceu em primeiro lugar e como posso evitá-lo na próxima vez?
git stash show -p | git apply --3
git stash show
e que os arquivos de resgate, um por um:$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Isso irá obter o arquivo do stash e salvá-lo com um nome diferente. Agora você está seguro para experimentar os métodos de resgate adequados (veja as respostas abaixo). Se as coisas derem errado, você sempre terá seus arquivos resgatados como último recurso.Respostas:
Como um pouco de explicação adicional, note que
git stash
faz dois commits ou três commits. O padrão é dois; você ganha três se usar qualquer grafia das opções--all
ou--include-untracked
.Esses dois ou três commits são especiais de uma maneira importante: eles não estão em nenhum branch. Git os localiza por meio do nome especial
stash
. 1 A coisa mais importante, entretanto, é o que o Git permite - e o faz - fazer com esses dois ou três commits. Para entender isso, precisamos olhar o que está nesses commits.O que há dentro de um esconderijo
Cada commit pode listar um ou mais commits pais . Eles formam um gráfico, onde os commits posteriores apontam para os anteriores. O stash normalmente contém dois commits, que eu gosto de chamar
i
para o conteúdo da área de teste / índice ew
para o conteúdo da árvore de trabalho. Lembre-se também de que cada commit contém um instantâneo. Em uma confirmação normal, este instantâneo é feito do índice / conteúdo da área de teste. Portanto, oi
commit é de fato um commit perfeitamente normal! Simplesmente não está em qualquer ramo:Se você está fazendo um estoque normal, o
git stash
código o fazw
copiando todos os seus arquivos da árvore de trabalho rastreados (em um índice auxiliar temporário). Git configura o primeiro pai destew
commit para apontar para oHEAD
commit e o segundo pai para apontar para o commiti
. Por último, ele definestash
para apontar para estew
commit:Se você adicionar
--include-untracked
ou--all
, o Git fará um commit extra,,u
entre fazeri
ew
. O conteúdo do instantâneou
são aqueles arquivos que não são rastreados, mas não são ignorados (--include-untracked
), ou arquivos que não são rastreados, mesmo que sejam ignorados (--all
). Esteu
commit extra não tem pai, e então quandogit stash
é feitow
, ele configuraw
o terceiro pai para esteu
commit, de forma que você obtém:Git também, neste ponto, remove todos os arquivos da árvore de trabalho que terminaram no
u
commit (usandogit clean
para fazer isso).Restaurando um estoque
Ao restaurar um estoque, você tem a opção de usá-lo
--index
ou não. Isso dizgit stash apply
(ou qualquer um dos comandos que usa internamenteapply
, comopop
) que deve usar oi
commit para tentar modificar seu índice atual. Essa modificação é feita com:(mais ou menos; há um monte de detalhes essenciais que atrapalham a ideia básica aqui).
Se você omitir
--index
,git stash apply
ignora completamente oi
commit.Se o stash tiver apenas dois commits,
git stash apply
agora pode aplicar ow
commit. Ele faz isso chamandogit merge
2 (sem permitir que ele comprometa ou trate o resultado como uma mesclagem normal), usando o commit original no qual o stash foi feito (i
o pai de, ew
o primeiro pai de) como a base de mesclagem,w
como o--theirs
commit, e seu commit atual (HEAD) como o alvo da fusão. Se a fusão for bem-sucedida, tudo estará bem - bem, pelo menos Git pensa assim - e ogit stash apply
próprio sucesso. Se você costumavagit stash pop
aplicar o stash, o código agora descarta o stash. 3 Se a fusão falhar, o Git declara que a aplicação falhou. Se você usougit stash pop
, o código retém o stash e entrega o mesmo status de falha degit stash apply
.Mas se você tiver aquele terceiro commit - se houver um
u
commit no stash que você está aplicando - então as coisas mudam! Não há opção de fingir que ou
commit não existe. 4 Git insiste em extrair todos os arquivos de queu
cometeu, na obra-árvore atual. Isso significa que os arquivos não devem existir ou ter o mesmo conteúdo dou
commit.Para fazer isso acontecer, você pode usar
git clean
você mesmo - mas lembre-se de que arquivos não rastreados (ignorados ou não) não têm outra existência dentro de um repositório Git, portanto, certifique-se de que todos esses arquivos possam ser destruídos! Ou você pode criar um diretório temporário e mover os arquivos para segurança - ou até mesmo fazer outrogit stash save -u
ougit stash save -a
, já que esses serão executadosgit clean
para você. Mas isso só deixa você com outrou
estoque de estilo para lidar mais tarde.1 Isso é de fato
refs/stash
. Isso é importante se você criar um branch chamadostash
: o nome completo do branch érefs/heads/stash
, portanto, eles não estão em conflito. Mas não faça isso: o Git não se importará, mas você se confundirá. :-)2 Na
git stash
verdade, o código usagit merge-recursive
diretamente aqui. Isso é necessário por vários motivos e também tem o efeito colateral de garantir que o Git não o trate como uma mesclagem quando você resolver conflitos e enviar commit.3 É por isso que recomendo evitar
git stash pop
, em favor degit stash apply
. Você tem a chance de revisar o que foi aplicado e decidir se foi realmente aplicado corretamente. Se não, você ainda tem seu estoque, o que significa que pode usargit stash branch
para recuperar tudo perfeitamente. Bem, supondo a falta daqueleu
commit irritante .4 Realmente deveria haver:
git stash apply --skip-untracked
ou algo assim. Também deve haver uma variante que significa colocar todos osu
arquivos de commit em um novo diretório , por exemplogit stash apply --untracked-into <dir>
, talvez.fonte
--index
:git stash apply --index
?git stash save --all
, depois fiz imediatamentegit stash apply
, mas alguns arquivos estavam faltando porque eu os renomei e criei novamente (antes de armazenar). O que ajudou foi:git checkout stash@{0} -- .
não vou nem me preocupar com issogit checkout stash^3 -- .
porque agora tudo parece bem. É uma pena não ter tempo de realmente entender o que estava acontecendo. Obrigado.u
commit contenha um arquivo chamadopath/to/file
(com algum conteúdo). Suponha ainda que sua árvore de trabalho já contenha um arquivo nomeadopath/to/file
. Extrair o conteúdo dou
commit substituiria o conteúdo do arquivo existente por um novo conteúdo, destruindo qualquer trabalho que você tivesse no arquivo nomeadopath/to/file
. Então Git não fará isso. Você terá que destruir esses conteúdos primeiro (removendo o arquivo inteiramente) ou removê-los do caminho (movendo o arquivo).Consegui recriar seu problema. Parece que se você armazena arquivos não rastreados e os cria (em seu exemplo
foo.txt
ebar.txt
), então você tem alterações locais em arquivos não rastreados que seriam substituídos quando você aplicassegit stash pop
.Para contornar esse problema, você pode usar o seguinte comando. Isso substituirá todas as alterações locais não salvas, portanto, tome cuidado.
Aqui estão mais algumas informações que encontrei no comando anterior .
fonte
--all
/-a
incluirá arquivos ignorados , então isso pode ser relevante.git merge --squash --strategy-option=theirs stash
abordagem seja melhor neste caso).already exists, no checkout
), verifique minha resposta abaixo.Para expandir a resposta de Daniel Smith : esse código apenas restaura os arquivos rastreados , mesmo se você usou
--include-untracked
(ou-u
) ao criar o stash. O código completo necessário é:git checkout stash -- . git checkout stash^3 -- . git stash drop # Optional to unstage the changes (auto-staged by default). git reset
Isso restaura totalmente o conteúdo rastreado (entrada
stash
) e o conteúdo não rastreado (entrada ) estash^3
, em seguida, exclui o estoque. Algumas notas:git checkout
faz com que todos sejamgit reset
testados automaticamente, então adicionei tudo para remover o estágio.stash@{0}
estash@{0}^3
, em meus testes, funciona da mesma forma com ou sem@{0}
Fontes:
stash^3
commit mágico )fonte
além de outras respostas, fiz um pequeno truque
git stash apply
(pode usar qualquer comando, por exemplo, aplicar, pop etc.)fonte