Regrouper plusieurs commits en un
N’as-tu jamais oublié d’ajouter des modifications ou fichiers dans un commit pour, plus tard, les ajouter à un autre commit dont l’intitulé ressemble à « Oops, j’avais oublié des choses » ? Ne t’inquiète pas, tu n’es pas seul·e à faire ça. Par contre, ça serait mieux de faire en sorte que ça ne vienne pas polluer ton historique. Je te propose dans cet article de découvrir comment regrouper plusieurs commits en un seul.
Cet article fait partie de notre série pour savoir annuler, défaire et corriger.
Je n’ai pas encore créé le commit traitant l’oubli
Si tu viens de t’apercevoir de l’oubli, la procédure sera encore plus aisée. Je te renvoie à notre autre article « Ajouter des modifications à un commit ».
Contexte
Prenons l’exemple de l’historique suivant.
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { 'commitLabelFontSize': '16px' }, 'gitGraph': {'showBranches': false} } }%% gitGraph commit id: "id1" commit id: "id2" commit id: "id3" type: HIGHLIGHT commit id: "id4" commit id: "id5" type: HIGHLIGHT commit id: "(HEAD) id6"
Nous avions fait un commit id3
pour traiter une tâche. Malheureusement, nous avons oublié d’ajouter certains fichiers au commit. On s’en est aperçu plus tard, après avoir créé le commit intermédiaire id4
. Pour que notre oubli soit intégré à l’historique et partagé, nous avons créé un commit id5
. Pour corser un peu la situation, on va considérer qu’un commit id6
a ensuite été réalisé.
Pour rendre l’historique plus clair on veut remplacer le commit id3
par un commit id3’
qui soit la somme des commits id3
et id5
.
Rebase à la rescousse
Pour régler cette situation, on va utiliser la commande rebase
et son mode interactif. Ce mode va nous permettre de regrouper et fusionner les commits (opération de squash ou fixup).
On lance donc la commande en lui demandant de partir du commit précédent id3
.
git rebase -i id2
Git ouvre notre éditeur avec la liste des actions et référence de commits, par ordre chronologique :
pick id3 Première ligne du message de commit 3
pick id4 Première ligne du message de commit 4
pick id5 Première ligne du message de commit 5
pick id6 Première ligne du message de commit 6
Cette liste est suivie d’un long commentaire listant, entre autres, les actions possibles à renseigner dans la première colonne, avant l’identifiant de chaque commit (par défaut renseigné à pick
). On y trouve notamment les lignes suivantes :
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
Chacune de ces actions peut faire l’affaire pour régler notre situation. Mais l’essentiel du temps, le message du commit initial (id3
dans notre cas) est déjà correct. On utilisera alors action fixup
.
Avant de renseigner l’action, on doit regrouper les lignes qui traitent id3
et id5
. Le plus souvent, on déplacera le dernier pour l’approcher du premier :
pick id3 Première ligne du message de commit 3
pick id5 Première ligne du message de commit 5 # On remonte la ligne id5 sous la ligne id3
pick id4 Première ligne du message de commit 4
pick id6 Première ligne du message de commit 6
Reste alors à marquer l’action fixup
qui indique de fusionner avec l’action précédente (celle au-dessus) :
pick id3 Première ligne du message de commit 3
fixup id5 Première ligne du message de commit 5 # On a remplacé "pick" par "fixup"
pick id4 Première ligne du message de commit 4
pick id6 Première ligne du message de commit 6
On finit par enregistrer le fichier et le fermer. Git reprend la main et finalise le rebase. On vérifie l’historique :
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { 'commitLabelFontSize': '16px' }, 'gitGraph': {'showBranches': false} } }%% gitGraph commit id: "id1" commit id: "id2" commit id: "id3’" commit id: "id4" commit id: "(HEAD) id6"
C’est parfait ! Notre commit id3’
est bien présent et id5
n’est plus là.
Et si j’ai déjà partagé mon travail (via un push) ?
Git est très permissif. En gros, il nous permet de tout faire ! Il nous incombe de définir un workflow adapté. Généralement, on s’autorise à changer un historique partagé sur des branches non sensibles. Et pour ce qui est de pousser “correctement”, je t’invite à lire notre article « Comprendre les risques de --force
et l’alternative --force-with-lease
».
Te voilà désormais équipé·e pour assurer la qualité et l’atomicité de tes commits.
Tu peux aussi regarder le programme de notre formation "Comprendre Git" ou nous poser tes questions sur notre forum discord.