6 votes

Comment refusionner une branche déjà fusionnée ?

J'ai un graphique de livraison qui ressemble à celui ci-dessous. Les commits marqués avec * représentent beaucoup de commits.

   A*
   |
   B---------
   |        |
   C*       D*    <- old feature branch
   |        |
   E---------
   |
   F*
   |
   G      <- master

Le commit de fusion E a été fait de manière incorrecte et certains changements (pas tous) dans C* ont été perdus. Comment puis-je refaire cette fusion pour réintroduire les changements dans le master actuel ?

Tout a déjà été poussé (projet open source), donc changer l'histoire n'est pas une option.

J'ai essayé de créer un patch à partir des commits C* et de l'appliquer au master, mais parce que un peu de des changements de C* ont été fusionnés correctement et parce que le projet a évolué depuis ce commit, environ 80% du patch échoue.

Idéalement, nous devrions prendre toutes les modifications dans C*, les appliquer à master et résoudre tous les conflits. Mais comme les branches ont déjà été fusionnées, git ne détecte aucun changement et ne permet pas de fusionner à nouveau.

$ git checkout 5bc5295   # C
HEAD is now at 5bc5295... cleanup

$ git checkout -b "missing-commits"
Switched to a new branch 'missing-commits'

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

$ git merge missing-commits
Already up-to-date.

2voto

AnoE Points 5134

Idéalement, nous devrions prendre toutes les modifications dans C*, les appliquer à master et résoudre tous les conflits.

Non, l'idéal serait de rembobiner le temps, de faire la fusion comme à l'époque (mais correctement, cette fois), puis de réappliquer la méthode de la F* les changements et aboutir à une master .

Vous pouvez le faire comme ça :

git checkout missing-commits
git checkout -b correct-merge
git merge D    # do it right, this time around!
git checkout master
git checkout -b correct-master
git rebase --onto correct-merge wrong-merge correct-master # have fun with the mother of all rebases!

Si vous parvenez à gérer tous les conflits au cours du rebasement, vous obtiendrez exactement ce que vous vouliez, à l'origine, dans la branche correct-master .

Puisque vous ne voulez pas changer l'histoire, vous pourriez alors créer un gros correctif et l'appliquer à votre actuelle master mais je préfère cette approche (en supposant que vous avez effectué tout votre travail dans votre répertoire de travail). yourrepos ) :

cd yourrepos ; git checkout correct-master ; cd ..
cp -a yourrepos newrepos
rm -rf newrepos/.git
cd yourrepos ; git checkout master ; cd ..
cp -a yourrepos/.git newrepos/

Maintenant, quand vous entrez newrepos et faire un git status vous serez dans la branche master et verra précisément tous les changements entre master y correct-master comme si vous aviez appliqué un patch. Il détectera les fichiers supprimés, les nouveaux fichiers, les fichiers modifiés, les permissions modifiées, les liens symboliques modifiés, etc.

Idéalement, si tout s'est bien passé, cela montrera exactement les commits manquants de C . Utilisez votre variante préférée de git add et enfin une belle git commit (ou plusieurs, si vous préférez), et vous avez terminé. Aucune histoire n'a été réécrite.

1voto

jthill Points 10384

Git stocke des instantanés et détecte les changements à la volée, donc la façon de travailler avec la différence entre un mauvais commit et un bon est d'enregistrer le bon comme un descendant du mauvais - à peu près la même chose que n'importe quoi, maintenant que j'y pense. Utilisez git reset --soft pour indiquer à git la bonne ascendance :

git checkout badmerge^1    # generate the right result 
git merge badmerge^2

git reset --soft badmerge  # as an improvement on the wrong result
git commit

git checkout master        # merge the difference now that git sees it
git merge @{1} -m "applying corrections to a bad merge"

0voto

Vampire Points 515

Essayez, au lieu de créer des correctifs simples et de les appliquer à l'utilisation git format-patch y git am . Cela devrait vous permettre d'obtenir une situation normale de conflit et d'utiliser un outil de fusion pour résoudre les conflits, contrairement à ce qui se passe avec l'option git apply où l'application échoue tout simplement.

0voto

Frodon Points 2311

Vous pouvez essayer par une cueillette de cerises :

git checkout master
git cherry-pick B..[last_commit_of_C*]

Git peut vous demander de confirmer le cherry-pick puisque les commits sont dans les ancêtres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X