Cela faisait longtemps que je n’avais pas alimenté la section Git – le b.a.-ba.

Imaginons que pour réaliser un développement bien particulier, vous avez été amené à le faire en plusieurs commits. Imaginons que maintenant, il vous est demandé de reporter ce travail dans une autre branche. Bien entendu, il y a des commits sur la branche actuelle que vous ne souhaitez pas reporter.

Alors comment faire pour reporter ce travail proprement ?

Tout d’abord, il faut lister tous les commits à récupérer et demander à git de les appliquer dans votre nouvelle branche :

$ git cherry-pick fbbf6d2f b080a2c9 585186b5 2e77b0c7

Une fois les commits appliqués, nous allons les regrouper en un seul pour obtenir un historique plus lisible :

$ git rebase -i HEAD~4
pick fbbf6d2f feat: awesome feature
pick b080a2c9 fix: awesome feature
pick 585186b5 fix: awesome feature
pick 2e77b0c7 fix: awesome feature

# Rebase 25581cd..fbbf6d2f onto 25581cd
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Ici le chiffre 4 correspond au nombre de commits à regrouper. Cette opération est plus connue sous le terme de git squash1. A savoir que vous auriez très bien pu également passer en mode rebase interactif à partir du commit précédent le premier appliqué de cette façon :

$ git rebase -i $(git rev-list --parents -n 1 fbbf6d2f)

Maintenant, vous devez indiquer à git quels sont les commits à regrouper. Pour cela, il faut laisser le premier en pick et passer tous les autres en squash :

$ git rebase -i HEAD~4
pick fbbf6d2f feat: awesome feature
squash b080a2c9 fix: awesome feature
squash 585186b5 fix: awesome feature
squash 2e77b0c7 fix: awesome feature

# Rebase 25581cd..fbbf6d2f onto 25581cd
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Vous enregistrez et quittez. Puis git vous demande de confirmer le message de commit en vous rappelant tous les messages de commit à regrouper :

# This is a combination of 4 commits.
# The first commit's message is:
feat: awesome feature

# This is the 2nd commit message:

fix: awesome feature

# This is the 3rd commit message:

fix: awesome feature

# This is the 4th commit message:

fix: awesome feature

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    new file:   Dockerfile
#    new file:   bin/docker-entrypoint
#    modified:   bin/startup.sh
#    modified:   config/log4j2.properties
#

Modifiez le message de commit, enregistrez, quittez et laissez git réappliquer ce nouvel et unique commit à la place des 4 précédents.

Cette situation ne devrait pas survenir souvent car en général nous travaillons dans une branche spécifique2. Néanmoins, il se peut que parfois nous ayons besoin de pousser du code sur une branche et se rendre compte après coup qu’il faille le modifier. Un report ultérieur est l’occasion de nettoyer l’historique git. Et comme la situation ne se produit pas souvent, je pense qu’il peut être pratique de savoir que c’est possible et d’avoir un petit rappel sur la façon se procéder. 😉

C’est maintenant à vous de jouer avec l’historique de vos sources !

  1. Je vous invite à créer un alias git pour.
  2. Pour une PR ou MR.