Reflog : par où suis-je passé ?

Par Maxime Bréhin • Publié le 25 février 2025 • 4 min

Le reflog, c’est la fonctionnalité de Git assez méconnue qui pourtant nous aide à annuler, défaire et plus largement à utiliser des commandes comme reset sans avoir peur de perdre nos commits.

Techniquement, le reflog enregistre les positions successives de HEAD et des étiquettes de branches.

stateDiagram
  direction LR
  [*] --> A

  A --> B
  B --> C
  C --> A

  A --> D
  D --> [*]

On peut voir ça comme le tracé GPS qu’on vient de suivre et qui trace également nos erreurs de parcours. Le reflog ne réalise donc pas de modification dans Git, mais fournit le support permettant le suivi de nos actions.

Affichage

Le reflog affiche une ligne par action réalisée ayant abouti à un déplacement de HEAD ou une étiquette de branche. L’ordre est chronologique inversé. La dernière action est affichée en haut. On observe ensuite une structure en 3 colonnes :

  1. L’identifiant du commit par lequel nous sommes “passé” ;
  2. Une syntaxe de révision propre au reflog permettant parfois certaines facilités d’écriture ;
  3. Un résumé succint de l’action menée au moment du “passage” préfixé par le type de l’action.

Moyennement un peu d’entraînement, on peut donc déterminer le parcours réalisé dans le projet et ainsi déterminer éventuellement un point/commit sur lequel nous souhaitons retourner. Ça peut s’avérer pratique lorsqu’on doit aider un·e collègue qui s’est perdu dans ses commandes.

Exerçons-nous à sa lecture

Voici un exemple ɗ’affichage des 10 dernières entrées du reflog, donc des 10 derniers déplacements de HEAD :

> git reflog -9

1101a95 HEAD@{0}: rebase (finish): returning to refs/heads/main
1101a95 HEAD@{1}: rebase (reset): 'onto': Merge branch 'article/restore'
3357906 HEAD@{2}: rebase (reset): 'onto'
4b1c57b HEAD@{3}: rebase (fixup): feat(article): add "restore"
05ef60c HEAD@{4}: rebase: fast-forward
3357906 HEAD@{5}: rebase (start): checkout 05ef60c~1
884936a HEAD@{6}: commit: fixup! feat(article): add "restore"
3822c66 HEAD@{7}: merge @{-1}: Merge made by the 'ort' strategy.
3357906 HEAD@{8}: checkout: moving from article/restore to main

Si on part du bas (HEAD@{8}), voici l’interprétation des actions que nous pouvons faire :

  • on a changé de branche pour passer de la branche article/restore à main ;
  • la dernière branche active (notée ici @{-1}) est fusionnée dans la branche courante (donc article/restore dans main) ;
  • un commit de correction a été réalisé, corrigeant un commit intitulé feat(article): add "restore" ;
  • un rebase a été lancé et sa première opération fait un checkout du commit précédant 05ef60c ;
  • la première action du rebase fait une avance rapide (aucune action à mener a priori) ;
  • le commit (fixup): feat(article): add "restore" est rejoué ;
  • les deux actions suivantes indiquent qu’une fusion a été reproduite/retranscrite dans l’historique (celle de article/restore dans main) ;
  • le rebase s’est terminé, l’étiquette main est repositionnée sur le nouveau commit de fusion 1101a95.

Evidemment, ça demande du temps, de la pratique et un certain socle de connaissances pour avoir une lecture fine du reflog.

Options d’affichage

Le reflog est en quelque sorte un cousin du log, c’est-à-dire qu’on retrouve de nombreuses options similaires, à commencer par limiter le nombre d’éléments affichés (vu précédemment avec l’option -9). Malgré ce potentiel d’options intéressant, on limitera généralement notre usage à deux choses :

  1. limiter le nombre d’éléments affichés ;
  2. restreindre l’affichage à une branche donnée.

J’encourage la seconde car je juge généralement plus pertinent d’afficher les déplacements qui concernent la branche courante quand le reflog “classique” affichera l’ensemble des déplacement de HEAD, toutes branches confondues, changement de branches inclus (exemple au-dessus avec la dernière ligne checkout…). Tout dépend évidemment de l’objectif et de l’analyse recherchés.

Pour utiliser la combinaison des deux, on précisera le nom de la branche ciblée, par exemple :

git reflog -10 article/reflog

L’affichage change alors pour nous montrer en seconde colonne une syntaxe de révision propre à la branche désignée.

> git reflog -4 article/reflog

884936a article/reflog@{0}: rebase (finish): refs/heads/article/reflog onto 566c5f4aa7bc67525a47bb490a17f5b1b34e32dd
ddb24bc article/reflog@{1}: commit: feat(article): setup "reflog" metadata
aa68d54 article/reflog@{2}: commit: feat(article): add "reflog"
f497ecc article/reflog@{3}: branch: Created from main

Procédons à un petit exercice d’analyse des actions menées sur cette branche en partant de la dernière ligne, tout en bas :

  1. La branche a été créée à partir de la branche main ;
  2. Elle a reçu un nouveau commit dont la première ligne était intitulée feat(article): add "reflog" ;
  3. Elle a reçu un second commit dont la première ligne était intitulée feat(article): setup "reflog" metadata ;
  4. Elle a été mise à jour par dessus le commit 566c5f4aa7bc67525a47bb490a17f5b1b34e32dd à l’aide d’un rebase.

On pourrait par exemple annuler la dernière opération à l’aide de la commande git reset --keep article/reflog@{1}. Si on fait cela, alors le reflog sera actualisé avec notre déplacement de HEAD et de la branche :

> git reflog -5 article/reflog

ddb24bc article/reflog@{0}: reset: moving to article/reflog@{1}
884936a article/reflog@{1}: rebase (finish): refs/heads/article/reflog onto 566c5f4aa7bc67525a47bb490a17f5b1b34e32dd
ddb24bc article/reflog@{2}: commit: feat(article): setup "reflog" metadata
aa68d54 article/reflog@{3}: commit: feat(article): add "reflog"
f497ecc article/reflog@{4}: branch: Created from main

Le article/reflog@{0} est devenu article/reflog@{1}, le article/reflog@{1} est devenu article/reflog@{2} et ainsi de suite…

On observe aussi en première colonne que l’identifiant du commit désigné par article/reflog@{0} est le même que article/reflog@{2}. C’est logique, puisque c’est à cet emplacement que nous avons demandé à Git de nous repositionner. Évidemment, on ne vérifie pas la bonne application du reset avec le reflog, mais plutôt avec le log (l’historique) du projet.

Note au passage l’avantage de l’affichage du reflog de la branche par rapport au reflog de HEAD lorsqu’il s’agit de retrouver le commit d’avant rebase. Je te remets le reflog de HEAD pour que tu puisses comparer. Je triche un peu et te place en commentaire une information pour l’identifier.

> git reflog -9

1101a95 HEAD@{0}: rebase (finish): returning to refs/heads/main
1101a95 HEAD@{1}: rebase (reset): 'onto': Merge branch 'article/restore'
3357906 HEAD@{2}: rebase (reset): 'onto'
4b1c57b HEAD@{3}: rebase (fixup): feat(article): add "restore"
05ef60c HEAD@{4}: rebase: fast-forward
3357906 HEAD@{5}: rebase (start): checkout 05ef60c~1
884936a HEAD@{6}: commit: fixup! feat(article): add "restore" # <-- C’est celui-là !
3822c66 HEAD@{7}: merge @{-1}: Merge made by the 'ort' strategy.
3357906 HEAD@{8}: checkout: moving from article/restore to main

Moins évident, non ?

Nettoyage du reflog

Git bénéficie d’un système de ramasse miette, autrement appelé en anglais garbage collector. Celui-ci gère différentes tâches dont celle de purger les références qui ne sont plus rattachées à des historiques “nommés” (essentiellement des étiquettes de branches et HEAD).

De ce fait, les commits “perdus” qu’on espère trouver dans le reflog risquent de ne plus y être. Heureusement, le délais initial de purge est configuré à 30 jours (et peut être changé), ce qui nous laisse très largement le temps de retrouver nos références.

À cela s’ajoute que les opérations de nettoyage ne sont déclenchées que lorsque nous effectuons des opérations sur le projet qui aboutissent à des changements d’historique (commit, fusion, rebase, reset…). Nous voilà donc doublement rassurés !

Vous voulez aller plus loin et maîtriser pleinement les fondamentaux de Git ou être accompagné pour garantir la qualité de vos projets grâce à une bonne mise en place de Git ? On peut vous aider ou vous former, il suffit de nous décrire votre besoin !
Vous pouvez aussi regarder le programme de notre formation "Comprendre Git" ou nous poser vos questions sur notre forum discord.