Como refazer uma mesclagem revertida no Git

231

Eu encontrei um problema aqui: eu tinha uma ramificação específica do problema 28sno Git, que eu mesclava na developramificação geral . Acontece que eu tinha feito isso muito rápido, então usei o git-revert para desfazer a mesclagem. Agora, porém, chegou a hora de fundir 28sem develop, mas o comando git-merge vê a fusão original, e felizmente anuncia que tudo está bem e galhos já foram mescladas. O que eu faço agora? Criar um 'Revert "Revert" 28s -> develop ""' commit? Não parece ser uma boa maneira de fazer isso, mas não consigo imaginar outra no momento.

Como é a estrutura da árvore:

Saída de log do Git

Toms Mikoss
fonte
4
É o GitX ( gitx.frim.nl ).
Toms Mikoss

Respostas:

169

Você precisa "reverter a reversão". Dependendo de como o original foi revertido, pode não ser tão fácil quanto parece. Veja o documento oficial sobre este tópico .

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

permitir:

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

Mas tudo isso funciona? Claro que sim. Você pode reverter uma mesclagem e, de um ângulo puramente técnico, o git fez isso muito naturalmente e não teve problemas reais.
Apenas considerou uma mudança de "estado antes da mesclagem" para "estado após mesclagem", e foi isso.
Nada complicado, nada estranho, nada realmente perigoso. O Git fará isso sem nem pensar.

Portanto, do ponto de vista técnico, não há nada errado em reverter uma mesclagem, mas do ponto de vista do fluxo de trabalho é algo que você geralmente deve evitar .

Se for possível, por exemplo, se você encontrar um problema que foi incorporada pela árvore principal, em vez de reverter a fusão, tente realmente difícil :

  • divida o problema no ramo que você mesclou e corrija-o,
  • ou tente reverter a confirmação individual que a causou.

Sim, é mais complexo e não, nem sempre vai funcionar (às vezes a resposta é: "opa, eu realmente não deveria ter mesclado, porque ainda não estava pronto e preciso desfazer todos os mesclar "). Portanto, você realmente deve reverter a mesclagem, mas quando deseja refazer a mesclagem, agora precisa fazer isso revertendo a reversão.

J-16 SDiZ
fonte
10
Bom link (+1). Tomei a liberdade de copiar parte do documento em sua resposta para permitir que os leitores vejam imediatamente as opções relevantes nesse caso. Se você não concordar, sinta-se à vontade para reverter.
VonC 03/07/2009
5
Acabamos de encontrar um caso em que precisávamos fazer isso e descobrimos que a diversão não para por aqui. Como uma ramificação de longa duração foi incorporada, precisamos continuar atualizando. Minha abordagem aqui: tech.patientslikeme.com/2010/09/29/…
jdwyah
Eu segui a postagem do blog de @ jdwyah e foi gloriosa (sério, foi incrível que funcionasse).
hellatan
2
@jdwyah que parece ser um link quebrado, mas parece uma leitura interessante. Aqui está um espelho archive.org mas está faltando as imagens: web.archive.org/web/20111229193713/http://...
Alex KeySmith
15
Post foi ressuscitado, graças: blog.jdwyah.com/2015/07/dealing-with-git-merge-revisions.html
jdwyah
53

Vamos supor que você tenha essa história

---o---o---o---M---W---x-------x-------*
              /                      
      ---A---B

Onde A, B falhou, confirma e W - reverte M

Portanto, antes de começar a corrigir os problemas encontrados, faço uma escolha cereja do W com o meu ramo

git cherry-pick -x W

Então eu reverto W commit no meu branch

git revert W 

Depois eu posso continuar consertando.

A história final pode parecer com:

---o---o---o---M---W---x-------x-------*
              /                       /     
      ---A---B---W---W`----------C---D

Quando eu envio um PR, ele mostra claramente que o PR está desfazendo a reversão e adiciona alguns novos commit.

Maksim Kotlyar
fonte
3
Isto olha como ele poderia ser útil, mas é tão escassa nos detalhes (quais são C, D no último diagrama) que é mais frustrante do que útil
Isochronous
4
@Isochronous C e D parecem ser commits que corrigem os problemas introduzidos por A e B.
Thomas
@Thomas exatamente
Maksim Kotlyar
É bom que você tenha destacado o uso de um PR nesta instância, pois ele pode fornecer uma 'verificação de sanidade' final antes de voltar ao master.
Willem van Ketwich 5/09/19
use por que você reinicia sua ramificação a partir do W original? Ou seja, deixe seu tópico continuar de W, com W` seguido de C e D? Isso elimina algumas duplicações
Erik Carstensen
12

Para reverter a reversão sem estragar demais o fluxo de trabalho:

  • Crie uma cópia de lixo local do develop
  • Reverta o commit de reversão na cópia local do develop
  • Mesclar essa cópia no seu ramo de recursos e enviar por push seu ramo de recursos para o servidor git.

Agora, sua ramificação de recursos poderá ser mesclada normalmente quando você estiver pronto para isso. A única desvantagem aqui é que você terá alguns compromissos adicionais de mesclagem / reversão em seu histórico.

Sam Dufel
fonte
Apenas para evitar mais confusões, também criei uma cópia 'lixo' do meu ramo de recursos e mesclou o desenvolvimento revertido.
Jhhwilliams
Obrigado! Esta é a única resposta que realmente explica como fazê-lo, em vez de dizer que você não deve fazer isso. Realmente útil.
Emmy
Obrigado, isso realmente me ajudou. :)
Daniel Stracaboško
11

Para reverter uma reversão no GIT:

git revert <commit-hash-of-previous-revert>
Richard
fonte
1
Usando isso no meu ramo de trabalho para reverter a reversão, desenvolva um novo PR. Agora, o git vê todas as alterações que estavam no PR anterior que foram revertidas. Obrigado.
Danstan 03/03
3

Em vez de usar, git-revertvocê poderia ter usado este comando no develramo para jogar fora (desfazer) a confirmação de mesclagem incorreta (em vez de apenas revertê-la).

git checkout devel
git reset --hard COMMIT_BEFORE_WRONG_MERGE

Isso também ajustará o conteúdo do diretório de trabalho de acordo. Cuidado :

  • Salve suas alterações no ramo de desenvolvimento (desde a mesclagem incorreta) porque elas também serão apagadas pelo git-reset. Todas as confirmações após a que você especificar como git resetargumento desaparecerão!
  • Além disso, não faça isso se suas alterações já tiverem sido extraídas de outros repositórios, pois a redefinição reescreverá o histórico.

Eu recomendo estudar a git-resetpágina de manual cuidadosamente antes de tentar isso.

Agora, após a redefinição, você poderá aplicar novamente as alterações devele, em seguida,

git checkout devel
git merge 28s

Esta será uma verdadeira fusão de 28sem develcomo o inicial (que agora é apagado da história do git).

Knweiss
fonte
8
Para quem não está familiarizado com o git e pode querer seguir estas instruções: cuidado com a combinação de reset --harde push origin. Lembre-se também de que um empurrão forçado na origem pode realmente prejudicar PRs abertos no GitHub.
Funroll 7/07
Muito útil para corrigir alguns problemas de mesclagem em um servidor git privado. Obrigado!
mix3d
1
+1 para esta técnica. Potencialmente destrutivo, mas pode poupar muita dor de cabeça (e um histórico mutilado) quando aplicado criteriosamente.
Siliconrockstar 25/05
1

Acabei de encontrar este post ao enfrentar o mesmo problema. Acho muito assustador fazer redefinições difíceis, etc. Acabarei excluindo algo que não quero e não conseguirá recuperá-lo.

Em vez disso, verifiquei o commit para o qual o ramo retornaria, por exemplo git checkout 123466t7632723. Em seguida, convertido em um ramo git checkout my-new-branch. Eu apaguei o ramo que não queria mais. Claro que isso só funcionará se você conseguir jogar fora o galho que você errou.

Claire
fonte
1
O git reflogprotegerá em uma reinicialização definitiva por alguns meses, caso você descubra mais tarde que precisa dos commits perdidos. O reflog é limitado ao seu repositório local.
Todd
1

Eu sugiro que você siga as etapas abaixo para reverter uma reversão, digamos SHA1.

git checkout develop #go to develop branch
git pull             #get the latest from remote/develop branch
git branch users/yourname/revertOfSHA1 #having HEAD referring to develop
git checkout users/yourname/revertOfSHA1 #checkout the newly created branch
git log --oneline --graph --decorate #find the SHA of the revert in the history, say SHA1
git revert SHA1
git push --set-upstream origin users/yourname/revertOfSHA1 #push the changes to remote

Agora crie PR para a filial users/yourname/revertOfSHA1

Venkataraman R
fonte
1
  1. crie uma nova ramificação no commit antes da mesclagem original - chame de 'base de desenvolvimento'
  2. execute uma rebase interativa de 'develop' em cima de 'develop-base' (mesmo que já esteja no topo). Durante o rebase interativo, você terá a oportunidade de remover a confirmação de mesclagem e a confirmação que reverteu a mesclagem, ou seja, remover os dois eventos do histórico do git

Nesse ponto, você terá uma ramificação limpa de 'desenvolvimento' na qual poderá mesclar seu recurso de braach como faz regularmente.

Misha Mostov
fonte
Essa abordagem criará problemas se o ramo de desenvolvimento for compartilhado com outras pessoas.
PSR