web-dev-qa-db-fra.com

git rebase interactive: la fusion de squash s'engage ensemble

Je voulais avoir une solution simple pour écraser deux commits de fusion ensemble lors d'un rebase interactif.

Mon référentiel ressemble à:

   X --- Y --------- M1 -------- M2 (my-feature)
  /                 /           /
 /                 /           /
a --- b --- c --- d --- e --- f (stable)

Autrement dit, j'ai un my-feature branche qui a été fusionnée deux fois récemment, sans réel commit entre les deux. Je ne veux pas simplement rebaser le my-feature branche puisqu'il s'agit de sa propre branche publiée, je veux juste regrouper les deux dernières validations de fusion en une seule (je n'ai pas encore publié ces validations)

   X --- Y ---- M (my-feature)
  /            /
 /            /
a --- ... -- f (stable)

J'ai essayé:

git rebase -p -i M1^

Mais j'ai:

Refusing to squash a merge: M2

Ce que j'ai finalement fait, c'est:

git checkout my-feature
git reset --soft HEAD^  # remove the last commit (M2) but keep the changes in the index
git commit -m toto      # redo the commit M2, this time it is not a merge commit
git rebase -p -i M1^    # do the rebase and squash the last commit
git diff M2 HEAD        # test the commits are the same

Maintenant, le nouveau commit de fusion n'est plus considéré comme un commit de fusion (il ne gardait que le premier parent). Alors:

git reset --soft HEAD^               # get ready to modify the commit
git stash                            # put away the index
git merge -s ours --no-commit stable # regenerate merge information (the second parent)
git stash apply                      # get the index back with the real merge in it
git commit -a                        # commit your merge
git diff M2 HEAD                     # test that you have the same commit again

Mais cela peut se compliquer si j'ai plusieurs commits, avez-vous une meilleure solution? Merci.

Mildred

52
Mildred

C'est un vieux sujet, mais je l'ai simplement parcouru en cherchant des informations similaires.

Une astuce similaire à celle décrite dans Subtree octopus merge est une très bonne solution à ce type de problème:

git checkout my-feature
git reset --soft Y
git rev-parse f > .git/MERGE_HEAD
git commit

Cela prendra l'index tel qu'il existe à la pointe de my-feature et l'utilisera pour créer un nouveau commit hors de Y, avec 'f' comme second parent. Le résultat est le même que si vous n'aviez jamais exécuté M1, mais passé directement à M2.

48
Matt

si vous n'avez pas publié les deux derniers validations de fusion, vous pouvez effectuer une réinitialisation et une fusion simple.

git reset --hard Y
git merge stable
8
bobDevil

Je suis venu sur ce sujet en voulant écraser un seul commit de fusion; donc ma réponse n'est pas très utile à la question d'origine.

               X
                \   
                 \  
a --- b --- c --- M1 (subtree merge)

Ce que je voulais, c'était rebaser la fusion M1 et tout écraser en un seul commit au-dessus de b.

a --- b --- S (include the changes from c, X and M1)

J'ai essayé toutes sortes de combinaisons différentes mais c'est ce qui a fonctionné:

git checkout -b rebase b (checkout a working branch at point b)
git merge --squash M1

Cela appliquera les modifications dans l'index où elles peuvent être validées git commit

5
Michael O'Cleirigh

Aucune des méthodes mentionnées ne fonctionne pour moi avec une version récente de git. Dans mon cas, ce qui suit a fait l'affaire:

git reset --soft Y
git reset --hard $(git commit-tree $(git write-tree) -p HEAD -p stable < commit_msg)

Cependant, vous devrez d'abord écrire le message de validation dans le fichier commit_msg.

0
Michael Wild