git stash blunder: git stash pop e acabou com conflitos de mesclagem

200

Eu fiz um git stash pope acabei com conflitos de mesclagem. Eu removi os arquivos do sistema de arquivos e fiz um git checkoutcomo mostrado abaixo, mas ele acha que os arquivos ainda não foram alterados. Eu tentei substituir os arquivos e fazer o git checkoutmesmo resultado. Eu tentei forçá-lo com -fbandeira. Qualquer ajuda seria apreciada!

chirag-patels-macbook-pro:haloror patelc75$ git status
app/views/layouts/_choose_patient.html.erb: needs merge
app/views/layouts/_links.html.erb: needs merge
# On branch prod-temp
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   db/schema.rb
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       unmerged:   app/views/layouts/_choose_patient.html.erb
#       unmerged:   app/views/layouts/_links.html.erb

chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
Chirag Patel
fonte
Nota: restaurar o estado antes do git stash apply/popdeve ser mais fácil com Git 2,5 (Q2 2015), já que a árvore de trabalho agora precisa ser limpa: ver minha resposta abaixo
VonC

Respostas:

219

Veja man git merge ( COMO RESOLVER CONFLITOS ):

Depois de ver um conflito, você pode fazer duas coisas:

  • Decida não mesclar. As únicas limpezas necessárias são redefinir o arquivo de índice para o commit HEAD para reverter 2. e limpar as alterações na árvore de trabalho feitas por 2. e 3 .; git-reset --hard pode ser usado para isso.

  • Resolva os conflitos. O Git marcará os conflitos na árvore de trabalho. Edite os arquivos em forma e git adicione-os ao índice. Use git commit para selar o acordo.

E em TRUE MERGE (para ver o que 2. e 3. se refere):

Quando não é óbvio como reconciliar as alterações, acontece o seguinte:

  1. O ponteiro HEAD permanece o mesmo.

  2. A referência MERGE_HEAD está configurada para apontar para a outra cabeça de ramificação.

  3. Os caminhos que foram mesclados corretamente são atualizados no arquivo de índice e na sua árvore de trabalho.

  4. ...

Portanto: use git reset --hardse você deseja remover as alterações de stash da sua árvore de trabalho ou git resetse deseja apenas limpar o índice e deixar que os conflitos na sua árvore de trabalho sejam mesclados manualmente.

Em man git stash ( OPTIONS, pop ), você pode ler além disso:

A aplicação do estado pode falhar com conflitos; nesse caso, não é removido da lista stash. Você precisa resolver os conflitos manualmente e chamar o git stash drop manualmente posteriormente.

tanascius
fonte
9
De fato, mesmo depois que você solta um stash, ainda é possível (embora mais difícil) recuperá-lo novamente, porque o conjunto de alterações ainda existe no repositório. stackoverflow.com/search?q=git+recover+dropped+stash
phils
3
@ nalply: isso é bom ou ruim? Você está convidado a melhorar a minha resposta, onde você não o entendeu, em primeiro lugar ...
tanascius
1
Eu acho que a revisão do código fonte é um domínio complexo do problema. É fácil ficar confuso. Ainda acho que sua resposta é boa porque reconfirmou minha abordagem.
N /
1
Não só me ajudou muito a perceber que o esconderijo não foi removido como eu supunha que tinha, mas isso explica por que o meu esconderijo continuou crescendo, mesmo quando eu tinha certeza de que não tinha esquecido de recuperar coisas dele.
Thor84no
11
"A aplicação do estado pode falhar com conflitos; nesse caso, não é removido da lista stash." Esta é a parte mais importante do post, na minha opinião. Considere editar sua resposta para colocá-la na frente, juntamente com as palavras NÃO ENTRE EM PÂNICO em letras grandes e amigáveis. (+1 já.) Obrigado.
Patrick M
42

Aconteceu uma coisa parecida comigo. Eu não queria preparar os arquivos ainda por isso, então os adicionei git adde o fiz git reset. Basicamente, isso acabou de adicionar e desestabilizar minhas alterações, mas limpou os caminhos não mesclados.

Aaron
fonte
4
Parece ser melhor do que usar, reset --hardporque não substitui seus arquivos (exceto aqueles com problemas de mesclagem). Obrigado!
sinelaw
Ainda não queria preparar os arquivos, por isso os adicionei - o addconteúdo da árvore de trabalho não está no índice? Acho que não entendo por que sua resposta funciona a partir da descrição.
de Drew Noakes
2
git addos git resetencena, mas , o que eu faço imediatamente depois, os desestabiliza. Essencialmente, ele limpa os caminhos não imersos e me devolve à minha árvore de trabalho normal, falsificando o git.
Aaron
3
Você não precisa git addse vai git reset. O git resetefetivamente "desfaz" o git add. git reset( --mixed<- padrão) efetivamente não toca no diretório de trabalho, portanto, exatamente o que estava no seu diretório de trabalho, mescla conflitos e tudo, é deixado em paz. Porém, o índice (e tecnicamente o cabeçalho da ramificação) é redefinido (sem uma ref, eles são redefinidos novamente HEAD, o que provavelmente significa que não há alterações para a cabeça da ramificação e desfaz efetivamente qualquer git addfeito no índice, além de limpar o estado dos caminhos não imersos) .
BamBams
3
A seqüência , editar / determinação , git resete git stash dropfunciona bem. Faz o que git stash popteria feito sem conflitos. Parece que o git addnão é necessário; embora seja útil, você tem muitos arquivos com conflitos. À medida que cada um é resolvido , eles podem ser adicionados e git statusos acompanha.
ruído artless 31/03
13

Se, como eu, o que você normalmente deseja sobrescrever o conteúdo do diretório ativo pelo dos arquivos ocultos, e você ainda tiver um conflito, o que você deseja é resolver o conflito usando git checkout --theirs -- .a raiz.

Depois disso, você pode git resettrazer todas as alterações do índice para o diretório de trabalho, pois, aparentemente, em caso de conflito, as alterações em arquivos não conflitantes permanecem no índice.

Você também pode querer correr git stash drop [<stash name>]depois, para se livrar do esconderijo, porque git stash popnão o exclui em caso de conflitos.

Pedro Gimeno
fonte
2

Observe que Git 2.5 (segundo trimestre de 2015) um futuro Git pode tentar tornar esse cenário impossível.

Consulte commit ed178ef por Jeff King ( peff), 22 de abril de 2015.
(Mesclado por Junio ​​C Hamano - gitster- no commit 05c3967 , 19 de maio de 2015)

Nota: Isso foi revertido. Veja abaixo .

stash: requer um índice limpo para aplicar / pop

Problema

Se você preparou o conteúdo em seu índice e executou " stash apply/pop", podemos entrar em conflito e colocar novas entradas no índice.
A recuperação para o seu estado original é difícil nesse ponto, porque ferramentas como "git reset --keep" acabam com tudo o que é encenado .

Em outras palavras:

" git stash pop/apply" esqueceu de garantir que não apenas a árvore de trabalho esteja limpa, mas também o índice esteja limpo.
O último é importante, pois um aplicativo stash pode entrar em conflito e o índice será usado para a resolução de conflitos.

Solução

Podemos tornar isso mais seguro, recusando a aplicação quando houver alterações em etapas.

Isso significa que se houvesse mesclagens antes por causa da aplicação de um stash em arquivos modificados (adicionados mas não confirmados), agora eles não seriam mesclados porque o stash apply / pop pararia imediatamente com:

Cannot apply stash: Your index contains uncommitted changes.

Forçar você a confirmar as alterações significa que, em caso de mesclagens, é possível restaurar facilmente o estado inicial (antes git stash apply/pop) com a git reset --hard.


Consulte commit 1937610 (15 de junho de 2015) e commit ed178ef (22 de abril de 2015) por Jeff King ( peff) .
(Mesclado por Junio ​​C Hamano - gitster- na confirmação bfb539b , 24 de junho de 2015)

Essa confirmação foi uma tentativa de melhorar a segurança da aplicação de uma ocultação, porque o processo do aplicativo pode criar entradas de índice conflitantes, após as quais é difícil restaurar o estado do índice original.

Infelizmente, isso afeta alguns fluxos de trabalho comuns em torno de " git stash -k", como:

git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

Se você "git commit" entre as etapas (3) e (4), isso simplesmente funciona. No entanto, se essas etapas fizerem parte de um gancho de pré-confirmação, você não terá essa oportunidade (precisará restaurar o estado original, independentemente de os testes terem sido aprovados ou falhados).

VonC
fonte