Rebase : réécrire l’histoire

La commande git rebase permet de réécrire l’histoire des commits, par exemple pour la rendre plus lisible.

Pour éviter les soucis de compatibilité on évite de réécrire une histoire publique. On ne fait des rebase que sur des branches qui ne sont pas liées aux autres.

Un exemple d’utilisation de rebase : le merge

Classiquement quand on merge une branche test dans master on a un historique de commit comme dans la figure suivante

simple branche

Si cette situation se reproduit de nombreuses fois sur de nombreuses branches le graphe des commits devient vite illisible. Pour faciliter la vision de l’historique du projet on peut modifier cet arbre.

simple branche

En pratique

Pour réussir facilement cette tâche, il suffit se positionner sur la branche test et on va faire comme si on avait commencé à développer test à partir de la dernière version de master

git switch test
git rebase master

A l’issue de cette opération, test est une succession de changements initiés depuis la dernière version de master. En fussionnant master et test, on va juste faire avancer master de quelques commits on n’aura as de commit de merge.

git switch master
git merge test

simple branche

Pour aller plus loin

Le rebase permet de réécrire toute l’histoire des commits. Si l’on souhaite modifier les 5 derniers commits. Par exemple dans la branche rebase voici l’historique des 5 derniers commits.

metienne@RMATHMPE20:~/git/finistR2022$ git log -n 5 --oneline
423f7a1 (HEAD -> rebase) Add git8 rebase merge illustration
3ebd174 Add git8 rebase  illustration
a535bf1 Add git8 merge bifucation illustration
d3ae968 git rebase fast forward
2a0b55e (origin/master, master) Add build directory to .gitignore

Il m’a fallu 3 commits pour ajouter les images, je n’ai pas envie de garder cet historique inutile, je voudrais un seul commit qui inclut toutes les images. je peux utiliser rebase pour faire ceci. La commande suivante, demande rentrer dans un mode de rebase automatique à partir pour les 5 derniers commits.

git rebase --interactive HEAD~5

On a alors accès aux derniers commits ouvert dans un éditeur de texte (attention ils sont dans l’ordre inverse, le plus récent en bas). Pour réécrire l’histoire il suffit de modifier le mot clé pick par une des propositions ci dessous.

pick 2a0b55e Add build directory to .gitignore
pick d3ae968 git rebase fast forward
pick a535bf1 Add git8 merge bifucation illustration
pick 3ebd174 Add git8 rebase  illustration
pick 423f7a1 Add git8 rebase merge illustration

# Rebase cefde40..423f7a1 onto 3ebd174 (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
                               [ Read 31 lines ]
^G Get Help  ^O Write Out ^W Where Is  ^K Cut Text  ^J Justify   ^C Cur Pos
^X Exit      ^R Read File ^\ Replace   ^U Paste Text^T To Spell  ^_ Go To Line

Pour ne faire qu’un seul commit de mes 3 ajouts de fichier, je vais utiliser squash

pick 2a0b55e Add build directory to .gitignore
pick d3ae968 git rebase fast forward
pick a535bf1 Add git8 merge bifucation illustration
s 3ebd174 Add git8 rebase  illustration
f 423f7a1 Add git8 rebase merge illustration

# Rebase cefde40..423f7a1 onto 3ebd174 (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
                               [ Read 31 lines ]
^G Get Help  ^O Write Out ^W Where Is  ^K Cut Text  ^J Justify   ^C Cur Pos
^X Exit      ^R Read File ^\ Replace   ^U Paste Text^T To Spell  ^_ Go To Line

Ensuite, on peut modifier les messages de commit

# This is a combination of 3 commits.
# This is the 1st commit message:

Add git8 merge bifucation illustration

# This is the commit message #2:

Add git8 rebase  illustration

# The commit message #3 will be skipped:

# Add git8 rebase merge illustration
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Tue Aug 23 11:32:14 2022 +0200
#
# interactive rebase in progress; onto cefde40

Si on sauve ce fichier et qu’on quitte, on a réécrit l’histoire

commit 5d107f70b48a6344e8bd8c07eb0e4683b572b924 (HEAD -> rebase)
Author: Marie-Pierre Etienne <marie-pierre.etienne@agrocampus-ouest.fr>
Date:   Tue Aug 23 11:54:53 2022 +0200

    Git rebase interactive mode redaction

commit 339f67470bbc5aee4fe737eb049a61c4212a405b
Author: Marie-Pierre Etienne <marie-pierre.etienne@agrocampus-ouest.fr>
Date:   Tue Aug 23 11:32:14 2022 +0200

    Add git8 merge bifucation illustration
    
    Add git8 rebase  illustration

commit d3ae968e4961f636c55a67e4d630574798154f3c
Author: Marie-Pierre Etienne <marie-pierre.etienne@agrocampus-ouest.fr>
Date:   Tue Aug 23 11:27:54 2022 +0200

    git rebase fast forward

commit 2a0b55e1ebba204c94126d51b72bacd1f8f0e0d0 (origin/master, master)
Author: Marie-Pierre Etienne <marie-pierre.etienne@agrocampus-ouest.fr>
Date:   Tue Aug 23 09:34:53 2022 +0200

    Add build directory to .gitignore

commit cefde40f7516ff8877bca4a6cebc910a14dd7d15
Author: Marie-Pierre Etienne <marie-pierre.etienne@agrocampus-ouest.fr>
Date:   Tue Aug 23 09:34:12 2022 +0200

    Remove build directory automatically created on the gh-pages branch

Important

Bien sur en réécrivant l’histoire on modifie le passé. Comme dans retour vers le futur, modifier le passé va affecter toutes les personnes concernées par ce passé. On doit donc etre très prudent avec cette approche. On ne rebase jamais master !!!! On ne peut réécrire l’histoire que pour des branches simples qui n’ont pas d’enfant.

pour visualiser ce qui se passe

Un outil pratique (merci Cédric pour comprendre, visualiser tester les différentes commandes git )

https://learngitbranching.js.org/?locale=fr_FR&NODEMO=