Como resolver o conflito do git stash sem confirmar?

495

Conforme solicitado nesta pergunta , também quero saber como resolver um conflito git stash popsem adicionar todas as modificações a um commit (assim como "git stash pop" sem conflito).

Minha abordagem atual é muito descolada porque faço dessa maneira:

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[Update] Uma maneira de reproduzi-lo:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

27/06/2016: Adicionado um novo arquivo chamado 'terceiro' ao exemplo para mostrar que soluções alternativas, como a solução de scy, funcionam apenas para HEADs vazios, mas não corrigem o problema inicial de que o HEAD não tem o mesmo conteúdo como para um git stash popsem conflito.

Sven
fonte
Então você git addarquiva seus arquivos de conflito, organizando-os efetivamente no índice e deseja não tê-los em nosso índice?
Romain
Sim está certo. Eu só quero o comportamento que git stash popocorre quando nenhum conflito ocorre (mas com a notificação de quais arquivos precisam ser mesclados).
Sven
2
Parece que a resposta para isso está aqui: stackoverflow.com/questions/3945826/git-stash-questions . Na resposta escolhida, no quarto comentário, Adam explica por que o git faz isso.
1011 Patrick
@Patrick Obrigado por essa informação - por isso parece que não haverá solução disponível porque a sua "by design"
Sven

Respostas:

509

Não siga outras respostas

Bem, você pode segui-los :). Mas eu não acho que fazer uma confirmação e redefinir a ramificação para remover essa confirmação e soluções alternativas sugeridas em outras respostas sejam a maneira limpa de resolver esse problema.

Solução limpa

A solução a seguir parece ser muito mais limpa para mim e também é sugerida pelo próprio Git - tente executar git statusno repositório com um conflito:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

Então, vamos fazer o que o Git sugere (sem fazer nenhum commit inútil):

  1. Manualmente (ou usando alguma ferramenta de mesclagem , veja abaixo) resolva os conflitos.
  2. Use git resetpara marcar conflitos como resolvidos e desestabilizar as alterações. Você pode executá-lo sem nenhum parâmetro e o Git removerá tudo do índice. Você não precisa executar git addantes.
  3. Finalmente, remova o esconderijo com git stash drop, porque o Git não faz isso em conflito.

Traduzido para a linha de comando:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Explicação do comportamento padrão

Existem duas maneiras de marcar conflitos como resolvidos: git adde git reset. Enquanto git resetmarca os conflitos como resolvidos e remove arquivos do índice, git addtambém marca os conflitos como resolvidos, mas mantém os arquivos no índice.

A adição de arquivos ao índice após a resolução de um conflito é intencional. Dessa forma, você pode diferenciar as alterações do estoque anterior e as alterações feitas após a resolução do conflito. Se você não gostar, pode sempre usar git resetpara remover tudo do índice.

Ferramentas de mesclagem

Eu recomendo o uso de qualquer uma das ferramentas de mesclagem de três vias para resolver conflitos, por exemplo , KDiff3 , Meld etc., em vez de fazê-lo manualmente. Geralmente, ele resolve todos os conflitos ou a maioria dos conflitos automaticamente. É uma enorme economia de tempo!

David Ferenczy Rogožan
fonte
32
@kamalpal parece ser necessário quando git stash popfalha com conflitos.
Emile Bergeron
21
@kamalpal sim, o Git até notifica que o estoque não foi descartado em caso de conflito. E a pergunta era sobre esse caso, então você realmente precisa executar, agit stash drop menos que queira manter esse estoque.
David Ferenczy Rogožan
@ DavidFerenczyRogožan Git não me notificou de que não descartou a entrada de stash. Versão 2.17.1 aqui.
Robert Siemer
298

Suponha que você tenha esse cenário em que esconde suas alterações para obter da origem. Possivelmente porque suas alterações locais estão apenas debug: trueem algum arquivo de configurações. Agora você puxa e alguém introduziu uma nova configuração lá, criando um conflito.

git status diz:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

OK. Decidi seguir o que Git sugeria: resolvi o conflito e cometi:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

Agora minha cópia de trabalho está no estado que desejo, mas criei um commit que não quero ter. Como me livrar desse commit sem modificar minha cópia de trabalho? Espere, há um comando popular para isso!

git reset HEAD^

Minha cópia de trabalho não foi alterada, mas a confirmação WIP se foi. Era exatamente o que eu queria! (Observe que não estou usando --softaqui, porque, se houver arquivos mesclados automaticamente no seu stash, eles serão organizados automaticamente e, portanto, você acabará com esses arquivos sendo organizados novamente depois reset.)

Mas resta mais uma coisa: a página de manual git stash popnos lembra que "A aplicação do estado pode falhar com conflitos; nesse caso, não é removida da lista stash. Você precisa resolver os conflitos manualmente e ligar git stash dropmanualmente depois". Então é exatamente isso que fazemos agora:

git stash drop

E feito.

assustador
fonte
34
Há muita feiúra herdada em ter que deliberadamente redefinir HEAD ^ ... para algo que deve afetar apenas a árvore de trabalho.
6
Por que não apenas resolver os conflitos e depois git add <resolved conflict files>seguidos git reset HEAD?
BoltzmannBrain
Obrigado pela sugestão, mas isso não resolve o problema inicial de que esse não é o mesmo comportamento git stash popsem um conflito. Basta adicionar outro arquivo ao HEAD antes de fazer o conflito git stash pope você git commit -a -m WIPtambém adicionaria o novo arquivo ao commit. Mas sem um conflito, apenas o novo arquivo permaneceria em HEAD, mas não os git stash poparquivos.
Sven
7
Não acho que seja necessário confirmar primeiro e depois desfazer o commit. Simplesmente repor de resposta Dawid Ferenczy vai fazer o mesmo
vladkras
3
Para usuários do Windows, o ^é usado como uma continuação de linha especial e o deixará sentado em um ponto Mais? prompt em vez de executar o comando. Em vez disso usar: git reset --soft HEAD~1. Veja como faço para excluir-unpushed-git-commits?
Mrfelis 07/07
87

Em vez de adicionar as alterações feitas para resolver o conflito, você pode usá-lo git reset HEAD filepara resolvê-lo sem organizar as alterações.

Você pode ter que executar este comando duas vezes, no entanto. Uma vez para marcar o conflito como resolvido e uma vez para desestabilizar as mudanças encenadas pela rotina de resolução de conflitos.

É possível que exista um modo de redefinição que faça as duas coisas simultaneamente, embora não exista agora.

ComputerDruid
fonte
2
O modo de redefinição é o que eu procuro - outras soluções alternativas são as que eu descrevi e não são práticas para mais de 5 arquivos.
Sven
25
E use "git stash drop" depois para finalizar o "git stash pop".
David Liu
2
Embora a pergunta não solicite isso explicitamente, pode ser útil atualizar a resposta para incluir "git stash drop", pois o stash não é descartado automaticamente no caso de um conflito.
Abhishek Pathak
29
git checkout stash -- .

trabalhou para mim.

Nota : isso pode ser perigoso, pois não tenta mesclar as alterações do stash na sua cópia de trabalho, mas substitui -o pelos arquivos stash . Assim, você pode perder suas alterações não confirmadas.

Stevenspiel
fonte
Isso ajudou quando "git pull --autostash" introduz confirmações indesejadas de mesclagem e git checkout stash -. incondicionalmente substitui conflitos de esconderijo
Alec Istomin
11
git add .
git reset

git add . preparará TODOS os arquivos informando ao git que você resolveu o conflito

git reset desestabilizará TODOS os arquivos em etapas sem criar uma confirmação

Aaron Goldman
fonte
Esta não é realmente uma resposta ruim, é muito bonito como git add -uentãogit reset
ebob
4

Parece que esta é a resposta que você está procurando. Ainda não tentei isso pessoalmente, mas parece que pode fazer o truque. Com este comando, o GIT tentará aplicar as alterações como eram antes, sem tentar adicionar todas elas para confirmação.

git stash apply --index

aqui está a explicação completa:

http://git-scm.com/book/en/Git-Tools-Stashing

Marco Ponti
fonte
Obrigado por essa dica, mas isso não vai ajudar quando eu já fiz git stash pop- ou existe uma maneira de reverter isso e fazer git stash apply --indexquando eu descobrir que isso git stash popvai entrar em conflito?
Sven
Adicionei um exemplo de como produzir isso - imagine que você esteja editando mais de 10 arquivos, para não saber qual deles modificou fora do esconderijo.
Sven
3
Se você olhar no final deste post AQUI, ele diz que, se você executar git stash pope acabar com conflitos, o stash não será removido ... para que você possa executar git reset --hardpara desfazer o pop e tentar a solução que eu sugeri.
Marco Ponti
Apenas tentei isso e não funciona depois que você tem um arquivo em estado de conflito. Mesmo se você corrigir o conflito manualmente.
Jul3
2

git stash branchO will works, que cria uma nova ramificação para você, verifica o commit em que estava quando você armazenou seu trabalho, reaplica seu trabalho lá e, em seguida, elimina o armazenamento se for aplicado com êxito. verifique isso

acalentar
fonte
2

A maneira mais rápida que encontrei é resolver o conflito e git add -u, em seguida git reset HEAD, o que nem envolve um commit.

Jammer
fonte
1

De acordo com as perguntas do git stash , após corrigir o conflito, git add <file>é o curso de ação certo.

Foi depois de ler este comentário que entendi que as alterações são automaticamente adicionadas ao índice (por design). É por isso que git add <file>conclui o processo de resolução de conflitos.

samgrigg
fonte
-1

Não é a melhor maneira de fazê-lo, mas funciona:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file
Bishwas Mishra
fonte
esta resposta parece errado claro para mim, como seria descartar todas as alterações file/path/to/your/file, o que não é o que pediu o OP, AFAIU
oromoiluig