Je suis un peu nouveau pour toute la fonctionnalité de rebasage dans git. Disons que j'ai fait les commits suivants:
A -> B -> C -> D
Ensuite, je me rends compte que D
contient un correctif qui dépend du nouveau code ajouté dans A
, et que ces commits appartiennent ensemble. Comment puis-je écraser A
& D
ensemble et laisser B
& C
tranquille?
Tu peux courir git rebase --interactive
et réorganiser D avant B et écraser D en 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 qui 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 après. Lorsque vous ne souhaitez pas conserver le message de validation de D, vous pouvez également utiliser le mot clé "fix".
Remarque: vous ne devez pas modifier les commits qui ont été poussés vers un autre référentiel de quelque manière que ce soit sauf si vous connaissez 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 ressembler à ceci (vous n'avez pas besoin de supprimer ou d'inclure le message de validation). Ne pas mal orthographier squash
!:
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D
Type 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
Tapez i
Remplacez le texte par ce à quoi vous voulez que le nouveau message de validation ressemble. Je recommande que ce soit une description des changements dans commit A
et D
:
new_commit_message_for_A_and_D
Type Esc alors 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 nouveau commit E
. Les validations A
et D
ne sont plus dans votre historique mais n'ont pas disparu. 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 que vous n'avez pas déjà poussé les commits.
Squash with previous
Le rebase interactif fonctionne bien jusqu'à ce que vous ayez une grosse branche de fonctionnalités avec 20-30 commits et/ou quelques fusions de master ou/et de résolution des conflits pendant que vous vous engagiez dans votre branche. Même avec la recherche de mes validations dans l'historique et le remplacement de pick
par squash
ne fonctionne pas ici. Je cherchais donc un autre moyen et j'ai trouvé cela article . J'ai fait mes changements pour travailler cela sur une branche distincte:
git checkout master
git fetch
git pull
git merge branch-name
git reset Origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git Push -f --set-upstream Origin branch-name
Avant cela, j'ai reçu ma demande de tirage avec environ 30 commits avec 2-3 fusions de conflits maître + correction. Et après cela, j'ai obtenu un PR clair avec un seul commit.
P.S. voici bash script pour faire ces étapes en mode automatique.