Comment puis-je écraser deux commits non consécutifs?

Je suis un peu nouveau à toute la fonctionnalité de rebasage de git. Disons que j’ai fait les commits suivants:

A -> B -> C -> D 

Par la suite, je me rends compte que D contient un correctif qui dépend de certains nouveaux codes ajoutés dans A , et que ces validations sont identiques. Comment puis-je écraser A & D et laisser B & C seul?

Vous pouvez lancer git rebase --interactive et réorganiser D avant B et squash D dans A.

Git ouvrira un éditeur et vous verrez un fichier comme celui-ci:

 pick aaaaaaa Commit A pick bbbbbbb Commit B pick ccccccc Commit C pick ddddddd Commit D # Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s)) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out 

Maintenant, vous changez le fichier qu’il ressemble à ceci:

 pick aaaaaaa Commit A squash ddddddd Commit D pick bbbbbbb Commit B pick ccccccc Commit C 

Et git va maintenant fusionner les changements de A et D en un seul commit et mettre B et C ensuite. Lorsque vous ne souhaitez pas conserver le message de validation de D, vous pouvez également utiliser le mot clé “fix”.

Note: Vous ne devez pas modifier les commits qui ont été poussés vers un autre repository à moins d’en connaître les conséquences .

git log --oneline -4

 D commit_message_for_D C commit_message_for_C B commit_message_for_B A commit_message_for_A 

git rebase --interactive

 pick D commit_message_for_D pick C commit_message_for_C pick B commit_message_for_B pick A commit_message_for_A 

Tapez i (Mettez VIM en mode insertion)

Modifiez la liste pour qu’elle ressemble à ceci (vous n’avez pas besoin de supprimer ou d’inclure le message de validation). Ne pas mal orthographier le squash ! :

 pick C commit_message_for_C pick B commit_message_for_B pick A commit_message_for_A squash D 

Tapez Esc puis ZZ (Enregistrer et quitter VIM)

 # This is a combination of 2 commits. # The first commit's message is: commit_message_for_D # This is the 2nd commit message: commit_message_for_A 

Type i

Changez le texte en ce que vous voulez que le nouveau message de validation ressemble. Je recommande que ceci soit une description des changements dans les commits A et D :

 new_commit_message_for_A_and_D 

Tapez Esc puis ZZ

git log --oneline -4

 E new_commit_message_for_A_and_D C commit_message_for_C B commit_message_for_B 

git show E

 (You should see a diff showing a combination of changes from A and D) 

Vous avez maintenant créé un nouvel commit E Les commits A et D ne sont plus dans votre histoire mais ne sont plus partis. Vous pouvez toujours les récupérer à ce stade et pendant un certain temps par git rebase --hard D ( git rebase --hard détruira tous les changements locaux! ).

Pour ceux qui utilisent SourceTree :

Assurez-vous de ne pas avoir déjà poussé les commits.

  1. Repository> Interactive Rebase …
  2. Faites glisser D (le plus récent commit) pour qu’il soit directement au-dessus de A (l’ancien commit)
  3. Assurez-vous que commit D est en surbrillance
  4. Cliquez sur Squash with previous

$ git checkout master

$ git log –oneline

 D C B A 

$ git rebase –onto HEAD ^^^ HEAD ^

$ git log –oneline

 D A