Git stash: "Não é possível aplicar a uma árvore de trabalho suja, faça as alterações necessárias"

133

Estou tentando aplicar as alterações que eu escondi anteriormente git stash pope recebo a mensagem:

Cannot apply to a dirty working tree, please stage your changes

Alguma sugestão sobre como lidar com isso?

avernet
fonte

Respostas:

196

Quando tenho de aplicar alterações ocultas em uma cópia de trabalho suja, por exemplo, retire mais de um conjunto de alterações do stash, uso o seguinte:

$ git stash show -p | git apply -3 && git stash drop

Basicamente

  1. cria um patch
  2. tubos que ao comando aplicar
  3. se houver algum conflito, ele precisará ser resolvido por meio da mesclagem de 3 vias
  4. se aplicar (ou mesclar) for bem-sucedido, ele solta o item de stash aplicado apenas ...

Eu me pergunto por que não há -fopção (força) para a git stash popqual deveria se comportar exatamente como o one-liner acima.

Enquanto isso, você pode adicionar esse one-liner como um alias do git:

$ git config --global --replace-all alias.unstash \
   '!git stash show -p | git apply -3 && git stash drop'
$ git unstash

Agradecemos ao @SamHasler por apontar o -3parâmetro que permite resolver conflitos diretamente por meio da mesclagem de 3 vias.

muhqu
fonte
É git stash show -p | git applydiferente de git stash apply?
Factor Mystic
1
Jo Factor, git stash applynão aplicará as alterações ocultas se você tiver uma cópia de trabalho suja. Então você pode ver git stash show -p | git applycomo se aplica algum tipo de esconderijo forçado.
21411 muhqu
1
não ajuda Mas ajuda: git redefine HEAD e desinstala as alterações depois disso.
Roger estrangeiro
4
Recebo "erro: o patch falhou ... o patch não se aplica" para um dos arquivos. Eu gostaria que isso desse um conflito de mesclagem.
Aleksandr Dubinsky
1
Esta solução não funcionou para mim, falhou error: <file> does not match indexem todos os arquivos modificados. No entanto, outra solução funcionou.
Silvenon
57

Eu faço assim:

git add -A
git stash apply

e então (opcionalmente):

git reset
Sergii Mostovyi
fonte
2
+1! Isso é mais simples do que as outras soluções que envolvem a geração de patches ou consolidações e mantém as alterações locais isoladas com segurança das alterações de stash aplicadas até que você tenha certeza de que as alterações foram mescladas corretamente.
Peterflynn
Eu recebo erro "... já existe, não check-out ... Não foi possível restaurar arquivos untracked do esconderijo"
Aleksandr Dubinsky
2
Eu usei git add -u, que é como, -Aexceto que não adiciona arquivos não rastreados.
Brad Cupit
9

Você pode fazer isso sem precisar esconder suas alterações atuais, exportando o esconderijo que deseja como um arquivo de patch e aplicando-o manualmente.

Por exemplo, suponha que você queira aplicar stash @ {0} a uma árvore suja:

  1. Exporte stash @ {0} como um patch:

    git stash show -p stash @ {0}> Stash0.patch

  2. Aplique manualmente as alterações:

    git aplica Stash0.patch

Se a segunda etapa falhar, você precisará editar o arquivo Stash0.patch para corrigir os erros e tentar o git apply novamente.

Ishan
fonte
Isso é prático e viável para o caso em que fiz refatoração em um diretório (removi-o e criei um link simbólico com seu nome). Git não sabia dizer quais eram minhas alterações na cópia de trabalho.
yclian 16/07/10
1
Isso funcionou muito bem. Não consegui aplicar um stash, embora tenha certeza de que minha árvore de trabalho está limpa.
Shiki
Sim, tive que remover linhas sobre um arquivo binário.
Dorian
8

Limpe seu diretório de trabalho com git reset, confirme as alterações ou, se você deseja ocultar as alterações atuais, tente:

$ git stash save "descrição das alterações atuais"
$ git stash pop stash @ {1}

Isso esconderá as alterações atuais e, em seguida, exibirá o segundo esconderijo da pilha escondida.

William Pursell
fonte
5
Mas esse cara quer os dois esconderijos aplicados!
Elazar Leibovich 04/04
@ Elazar Você está lendo a pergunta. O OP apenas deseja aplicar um estoque anterior. Se você estiver certo de que as alterações atuais devem ser mantidas, a solução pode ser repetida: pop, commit, repeat.
William Pursell
Eu acho que ele quer que os dois não se comprometam. Mas, novamente, ele pode confirmar duas vezes e compactá-las em uma única confirmação.
Elazar Leibovich
Eu recebo erro "... já existe, não check-out ... Não foi possível restaurar arquivos untracked do esconderijo"
Aleksandr Dubinsky
6

A solução de Mathias é definitivamente a mais próxima de um pop stash do git --force (e realmente, vamos devs do Git, vamos pegar essa opção já!)

No entanto, se você quiser fazer o mesmo usando apenas os comandos git, poderá:

  1. git commit -a -m "Fixme"
  2. git stash pop
  3. git commit -a --amend
  4. git reset HEAD ~

Em outras palavras, faça um commit (que nunca iremos enviar) de suas alterações atuais. Agora que seu espaço de trabalho está limpo, coloque seu estoque. Agora, confirme as alterações do stash como uma emenda ao seu commit anterior. Feito isso, agora você tem os dois conjuntos de alterações combinados em uma única confirmação ("Fixme"); apenas redefina (--soft NOT --hard para que nada seja realmente perdido) seu checkout para "um antes desse commit", e agora você tem os dois conjuntos de alterações completamente não confirmados.

** EDIT * *

Acabei de perceber que é realmente ainda mais fácil; você pode pular completamente a etapa 3, então ...

  1. git commit -a -m "Fixme"
  2. git stash pop
  3. git reset HEAD ~

(Confirme as alterações atuais, retire as alterações ocultas, redefina a primeira confirmação para obter os dois conjuntos de alterações combinados em um estado não confirmado.)

machineghost
fonte
4

Nenhuma dessas respostas realmente funciona se você se encontrar nessa situação como eu fiz hoje. Independentemente de quantos git reset --hardeu fiz, isso não me levou a lugar algum. Minha resposta (não oficial de forma alguma foi):

  1. Descobrir o uso de hash do stash git reflog --all
  2. Mesclar esse hash com o ramo em que você está interessado
Dan Rosenstark
fonte
1
Muito obrigado Yar. Fiquei frustrado com a forma como o Git se comportou estranhamente no meu repositório local agora, o mesmo problema que você descreveu.
yclian
4

Também achei a solução de Mathias Leppich excelente, então adicionei um alias para ela no meu arquivo .gitconfig global

[alias]
        apply-stash-to-dirty-working-tree = !git stash show -p | git apply && git stash drop

Agora eu posso apenas digitar

git apply-stash-to-dirty-working-tree

o que funciona muito bem para mim.

(Sua milhagem pode variar com esse longo nome alternativo. Mas eu gosto de uma dose de verbosidade quando se trata de conclusão do bash.)

3 rotações
fonte
3

Você pode aplicar um stash a uma árvore "suja" fazendo um git addpara realizar as alterações feitas, limpando a árvore. Em seguida, você pode git stash popaplicar as alterações ocultas, sem problemas.

Chris Vandevelde
fonte
2

Você tem arquivos que foram modificados, mas não confirmados. Ou:

git reset --hard HEAD (to bring everything back to HEAD)

ou, se você quiser salvar suas alterações:

git checkout -b new_branch
git add ...
git commit
git checkout -b old_branch
git stash pop
brool
fonte
1
@ MikeCooper - Eu acho que ele apenas quis adicionar o que você deseja adicionar antes de cometer.
Sscirrus
0

Eu tive o mesmo problema, mas o git tinha zero arquivos alterados. Acontece que eu tinha um arquivo index.lock que estava por aí. A exclusão resolveu o problema.

encaixotado
fonte
0

Não consegui fazer a maioria delas funcionar; por alguma razão, sempre acha que tenho alterações locais em um arquivo. Não consigo aplicar um stash, os patches não se aplicam checkoute reset --hardfalham. O que finalmente funcionou foi salvar o esconderijo como um ramo e git stash branch tempbranchname, em seguida, fazer uma mesclagem normal de ramos: git checkout mastere git merge tempbranchname. Em http://git-scm.com/book/en/Git-Tools-Stashing :

Se você quiser uma maneira mais fácil de testar as alterações armazenadas novamente, execute o branch git stash, que cria um novo branch para você, verifique o commit em que estava quando você armazenou seu trabalho, aplique-o novamente e solte o botão esconder se for aplicado com sucesso

rwilson04
fonte