99 votes

Modifier un commit de fusion avec git rebase

En Git lorsque j'ai des commits par exemple A - B - C et que je veux éditer le commit B, je

  • utilise git rebase -i ,
  • dans la liste j'écris la commande edit devant le commit B,
  • git rebase s'arrête juste après le commit B donc je peux corriger ce que je veux en utilisant git commit --amend,
  • et ensuite je continue en utilisant git rebase --continue.

D'après ce que je sais, c'est la meilleure pratique pour le faire. Avec cette méthode je peux éditer n'importe quel commit dans le passé (tant qu'il n'a pas encore été poussé sur la branche distante), et de plus avec le drapeau -p je peux même préserver les fusions. C'est vraiment super.

Mon problème actuel est le suivant : j'ai fait une erreur (une faute de frappe) sur une ligne dans un commit de fusion (lors de la résolution d'un conflit lors de la fusion de deux branches).

Je voudrais le corriger mais je ne sais pas comment faire en sorte que git rebase s'arrête à un commit de fusion. La liste git rebase -p -i ignore les commits de fusion, donc je ne peux pas écrire la commande edit devant eux pour faire en sorte que git rebase s'arrête là pour me laisser le modifier.

Est-ce que quelqu'un peut m'aider s'il vous plaît ? Je veux juste corriger cette ligne dans le commit de fusion tout en préservant tous les commits (et fusions) qui viennent après.

Merci.

158voto

Richard Hansen Points 13044

Réponse mise à jour pour 2020 :

Vous pouvez forcer git rebase -i à s'arrêter au commit de fusion via la commande break (ajoutée dans Git 2.20). Vous pouvez ensuite modifier le commit de fusion comme vous le souhaitez via git commit --amend.

Étapes détaillées :

  1. Exécutez git rebase -i --rebase-merges $ancetre_du_commit_de_fusion

  2. Recherchez le commit de fusion que vous souhaitez modifier dans la liste de tâches à effectuer.

  3. Insérez une nouvelle ligne après le commit de fusion qui contient uniquement break (ou b).

  4. Enregistrez vos modifications et quittez votre éditeur. Git rebase vérifiera le commit de fusion, affichera quelque chose comme ce qui suit, puis vous renverra à votre invite :

    Stopped at fb91fab (Merge branch 'foo' into bar)
  5. Utilisez git commit --amend pour modifier le commit de fusion comme vous le souhaitez.

  6. Exécutez git rebase --continue lorsque vous avez fini de modifier le commit de fusion.

Approche alternative si vous n'avez aucun commit de fusion après le commit que vous souhaitez modifier :

  1. Exécutez git rebase -i $id_du_commit_de_fusion

  2. Insérez une nouvelle ligne en haut de la liste de choses à faire qui contient uniquement break (ou b).

  3. Enregistrez vos modifications et quittez votre éditeur. Git rebase vérifiera le commit de fusion, affichera quelque chose comme ce qui suit, puis vous renverra à votre invite :

    Stopped at fb91fab (Merge branch 'foo' into bar)
  4. Utilisez git commit --amend pour modifier le commit de fusion comme vous le souhaitez.

  5. Exécutez git rebase --continue lorsque vous avez fini de modifier le commit de fusion.

Réponse initiale de 2012 (avant break) :

Git ne facilite pas les rebases interactifs lorsque des fusions sont impliquées. L'option -p utilise le mécanisme -i en interne, donc mélanger les deux ne fonctionne pas vraiment.

Cependant, git rebase est simplement un moyen automatisé de faire de nombreux cherry-picks. Vous pouvez reproduire son comportement en faisant manuellement des cherry-picks pour obtenir un peu plus de contrôle sur le processus. C'est moins pratique et plus sujet aux erreurs humaines, mais c'est possible.

Voici l'approche que je suggère :

  1. utilisez git rebase pour arriver au commit après la fusion (l'enfant de la fusion)
  2. utilisez git reset --hard HEAD^ pour arriver manuellement à la fusion
  3. utilisez git commit --amend pour réparer la fusion
  4. utilisez git cherry-pick pour revenir au commit après la fusion
  5. utilisez git rebase --continue pour terminer

Voici les étapes spécifiques :

  1. Notez l'identifiant SHA1 du commit de fusion que vous souhaitez modifier. Pour l'exemple, supposons que ce soit deadbeef.
  2. Notez l'identifiant SHA1 du commit juste après le commit de fusion que vous souhaitez modifier (l'enfant du commit de fusion). Supposons que ce soit facef00d.
  3. Exécutez git rebase -i deadbeef.
  4. Sélectionnez facef00d pour l'édition.
  5. Lorsque le rebase vous ramène à une invite pour éditer facef00d, exécutez git reset --hard HEAD^. Vous devriez maintenant être à deadbeef (git rev-parse HEAD devrait afficher deadbeef).
  6. Effectuez vos modifications pour corriger le conflit de fusion incorrect et utilisez git add pour les mettre en stage.
  7. Exécutez git commit --amend pour fusionner la correction mise en scène avec le mauvais commit de fusion. Le résultat aura alors un SHA1 différent (pas deadbeef).
  8. Exécutez git cherry-pick facef00d pour appliquer les modifications faites par facef00d au commit de fusion corrigé.
  9. Exécutez git rebase --continue pour terminer.

14voto

Raman Points 1250

C'est beaucoup plus facile maintenant avec l'option --rebase-merges disponible dans Git 2.22 et supérieur. Cette option préserve la topologie des fusions et fonctionne avec les rebases interactifs.

Cela ressemblera à quelque chose comme ceci, en supposant que B est le commit de fusion à modifier :

label onto

... certaines définitions de branches ...

reset onto
merge -C B nom-de-la-branche # Fusionner la branche 'B' dans tout
pick C

Vous pouvez maintenant insérer un b (ou break) entre la fusion et le pick:

merge -C B nom-de-la-branche # Fusionner la branche 'xyz' dans tout
break
pick C

À la pause commit --amend la fusion, puis continuer le rebase.

Cela fonctionne également avec un commit de fixup. Par exemple, supposons que le commit avec la correction de la fusion est D. Vous pouvez déplacer votre commit fixup D immédiatement après le commit de fusion :

merge -C B nom-de-la-branche # Fusionner la branche 'xyz' dans tout
fixup D
pick C

Consultez la section Rebasing Merges de la page man git-merge.

1voto

i3ensays Points 747

Il est peut-être plus facile de créer un commit de réparation 'D' puis d'utiliser 'git rebase -p -i ' pour réordonner 'D' juste après 'B' et le fusionner avec 'B'.

pick A
pick B  <- commit de fusion à amender
fixup D
pick C

0voto

TTT Points 529

tl;dr: Parfois, vous ne devriez simplement pas utiliser git rebase pour modifier un commit de fusion. Une autre méthode peut être plus efficace.

Je viens de vivre un tel scénario : j'avais un commit de fusion qui fusionnait une branche très ancienne, et il y avait de nombreux conflits qui ont été résolus dans le commit de fusion. Il y avait quelques commits supplémentaires après la fusion, et ensuite il a été découvert qu'une erreur avait été commise dans le grand commit de fusion lors de la résolution d'un conflit de fichiers. J'ai configuré le rebase interactif comme décrit dans la réponse acceptée, mais quand ma machine s'est bloquée à 2/59 j'ai réalisé qu'elle écrivait beaucoup de fichiers en réorganisant mon système de fichiers pour correspondre à l'ancienne branche. Après quelques minutes, je l'ai arrêté, j'ai annulé le rebase, puis j'ai dû supprimer 100 000 fichiers pour revenir à la situation initiale. Au lieu du rebase, j'ai fait ceci à la place :

  1. Prendre note des ID de commit que je veux rejouer après avoir corrigé le commit de fusion.
  2. git reset --hard [id-du-commit-de-fusion]
  3. Faire le changement et simplement modifier le commit HEAD (qui est le commit de fusion).
  4. Sélectionner chacun des ID de commit dans l'ordre après le commit de fusion, ou utiliser git rebase --onto avec 3 arguments pour sélectionner tout le range s'il y en a plus que quelques-uns.)

C'était beaucoup plus rapide.

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