Introduction
Apprenez comment Git réécrit l'historique avec git commit --amend, git reflog et git rebase — ce que fait chaque commande et quand l'utiliser.
Dans Git, l'historique est la séquence de commits qui retrace l'évolution de votre projet au fil du temps. Chaque commit est identifié par un hash unique et pointe vers le ou les commits qui le précèdent. La plupart du temps, vous ne faites qu'ajouter à cette chaîne. Mais parfois, vous devez modifier ce qui s'y trouve déjà — corriger une faute de frappe dans un message de commit, regrouper plusieurs commits désordonnés en un seul commit propre, ou récupérer un travail que vous pensiez avoir perdu.
C'est à cela que servent les outils de réécriture de l'historique de Git. Les trois que vous utiliserez le plus souvent sont :
git commit --amend— remplacer le commit le plus récent.git reflog— voir chaque position à laquelleHEADa pointé, afin de récupérer des commits « perdus ».git rebase— rejouer une série de commits sur une nouvelle base, en les modifiant éventuellement au passage.
Cette page vous donne un aperçu fonctionnel de chacun d'eux. Les chapitres plus détaillés liés ci-dessus parcourent l'ensemble des options disponibles.
La règle d'or de la réécriture de l'historique : ne réécrivez jamais des commits que vous avez déjà poussés vers une branche partagée. La réécriture modifie les hashes des commits, de sorte que toute personne ayant récupéré les anciens commits se retrouvera avec des conflits. Réécrivez librement sur vos propres branches locales ; laissez l'historique partagé intact.
Modifier le dernier commit avec git commit --amend
Il est facile d'oublier de préparer un fichier, de laisser une faute de frappe dans un message de commit, ou de committer trop tôt. Au lieu d'ajouter un commit « correctif » séparé, git commit --amend vous permet de remplacer le dernier commit par un commit corrigé.
Pour corriger uniquement le message du commit le plus récent :
git commit --amend -m "Add login validation"Pour ajouter un fichier oublié au dernier commit, indexez-le d'abord, puis faites un amend sans modifier le message :
git add forgotten-file.js
git commit --amend --no-editL'option --no-edit conserve le message existant et le réutilise. En coulisses, amend ne modifie pas l'ancien commit en place — il crée un tout nouveau commit (avec un nouveau hash) et déplace la branche pour qu'elle pointe vers lui. Le commit original est laissé derrière, sans référence.
Comme un amend produit un nouveau hash, la même règle d'or s'applique : ne faites un amend que sur un commit que vous n'avez pas poussé vers une branche partagée par d'autres personnes.
Pour une présentation complète, voir git commit --amend.
Récupérer des commits perdus avec git reflog
Le reflog (journal de référence) enregistre chaque modification apportée au sommet de vos branches et à HEAD — chaque commit, checkout, reset, merge et rebase. C'est votre filet de sécurité : même après une réécriture ou un hard reset, les anciens commits se trouvent toujours dans le dépôt et le reflog se souvient de leur emplacement.
Affichez le journal avec :
git reflogUne sortie typique ressemble à ceci :
a1b2c3d HEAD@{0}: commit: Add login validation
9f8e7d6 HEAD@{1}: reset: moving to HEAD~1
4c3b2a1 HEAD@{2}: commit: Work in progressChaque entrée affiche un hash de commit, une référence HEAD@{n} (combien de déplacements auparavant) et ce qui s'est passé. Si vous avez accidentellement supprimé un commit avec un reset, retrouvez-le dans le reflog et récupérez-le :
git reset --hard HEAD@{2}La commande git reflog dispose également de sous-commandes telles que git reflog show, git reflog expire et git reflog delete. Notez que les entrées du reflog sont locales à votre dépôt et expirent au fil du temps (90 jours par défaut pour les entrées accessibles), elles constituent donc un outil de récupération, pas une sauvegarde permanente. Voir git reflog et le chapitre associé git reset pour plus de détails.
Rebaser sur une nouvelle base avec git rebase
git rebase prend une série de commits et les rejoue au-dessus d'un commit de base différent. Son principal avantage est un historique linéaire et lisible : au lieu d'un commit de merge reliant deux branches, votre travail apparaît comme une ligne propre de commits.
Il existe deux modes :
- Le mode standard applique les commits de votre branche actuelle au-dessus du sommet d'une autre branche. C'est l'alternative au merge lors de l'intégration des mises à jour depuis
main:
git rebase main- Le mode interactif vous permet de réordonner, modifier, combiner ou supprimer des commits au fur et à mesure qu'ils sont rejoués. Ajoutez l'option
-iet passez le commit sur lequel vous souhaitez rebaser :
git rebase -i <base-branch>Une cible interactive courante est « les N derniers commits », par exemple les trois derniers :
git rebase -i HEAD~3Pour un traitement plus complet, voir git rebase et git rebase interactive.
Modifier des commits lors d'un rebase interactif
Lorsque vous démarrez un rebase interactif, Git ouvre un éditeur listant les commits sélectionnés, chacun préfixé par une action. Vous changez le mot-clé d'action pour contrôler ce qui se passe :
pick— conserver le commit tel quel (par défaut).reword(r) — faire une pause pour réécrire le message de ce commit.squash(s) — fusionner ce commit avec le précédent et combiner leurs messages dans un éditeur.fixup(f) — commesquash, mais ignore le message de ce commit et ne conserve que celui du précédent (pas d'invite éditeur).edit(e) — faire une pause pour pouvoir modifier le contenu du commit.drop(d) — supprimer entièrement le commit.
Une liste de tâches de rebase typique ressemble à ceci :
pick a1b2c3d Add login form
squash 9f8e7d6 Fix typo in label
fixup 4c3b2a1 Adjust spacingIci, le deuxième et le troisième commits sont fusionnés dans le premier, laissant un seul commit bien rangé.
Pourquoi les commits réécrits obtiennent de nouveaux identifiants
Le rebase ne déplace pas les commits originaux — il crée de nouveaux commits avec les mêmes modifications mais des parents différents, et donc des hashes différents. Les anciens commits deviennent sans référence (toujours récupérables via le reflog pendant un certain temps). Même les commits que vous avez marqués pick obtiennent de nouveaux identifiants si un commit avant eux dans la séquence a été modifié, car leur parent a changé.

C'est précisément pour cela que la règle d'or est importante : de nouveaux hashes signifient un historique divergent pour quiconque possédait les anciens.