Chapitre 3 : Les notions avancées
Concepts abordés
- Reflog
- Références relatives (~ et ^)
- Bisect
Reflog
Le reflog est un journal de toutes les modifications des références (HEAD, branches, etc.) dans votre dépôt local. Il enregistre chaque déplacement de HEAD, chaque commit, chaque reset, etc.
La commande git reflog affiche l'historique des références. Chaque entrée montre l'ancien hash, le nouveau hash, l'action effectuée et un message descriptif.
La lecture du reflog permet de retrouver des commits "perdus" après un reset ou une suppression de branche. Les entrées sont référencées par leur position (ex: HEAD@{1} pour l'état précédent) ou par un hash partiel.
Le reflog est local uniquement et expire après 90 jours par défaut. Il est essentiel pour récupérer des commits supprimés accidentellement : git checkout <hash-du-reflog> puis création d'une nouvelle branche pour sauvegarder le commit.
Références relatives
Git permet de référencer des commits de manière relative à partir d'un commit donné, sans connaître son hash exact. Deux opérateurs principaux sont disponibles : ~ (tilde) et ^ (caret).
L'opérateur ~ remonte dans l'historique linéaire : HEAD~1 est le parent de HEAD, HEAD~2 est le grand-parent, HEAD~n est le n-ième ancêtre. Par défaut, ~ équivaut à ~1.
L'opérateur ^ permet de naviguer parmi les parents d'un commit de merge. Un commit de merge a plusieurs parents : HEAD^1 est le premier parent (la branche sur laquelle le merge a été fait), HEAD^2 est le second parent (la branche fusionnée). Pour un commit normal (un seul parent), ^ équivaut à ^1.
Ces opérateurs peuvent être combinés : HEAD~3^2 signifie "le second parent de l'arrière grand-parent de HEAD", utile pour naviguer dans un historique avec des merges. HEAD^^ est équivalent à HEAD~2 pour un historique linéaire, mais HEAD^2 sélectionne le second parent d'un merge.
Ces références sont pratiques pour des commandes comme git log, git diff, git show, git rebase ou git reset sans avoir à chercher le hash exact d'un commit.
Bisect
git bisect est un outil de recherche binaire pour identifier le commit qui a introduit un bug. Le processus consiste à marquer un commit "bon" (sans le bug) et un commit "mauvais" (avec le bug), puis Git teste automatiquement les commits intermédiaires pour isoler le commit problématique.
L'utilisation typique : git bisect start pour démarrer, git bisect bad sur le commit actuel, git bisect good <hash> sur un commit ancien connu comme fonctionnel. Git vous place ensuite sur un commit intermédiaire, vous testez, et vous indiquez git bisect good ou git bisect bad. Le processus se répète jusqu'à identifier le commit exact.
Pour automatiser le processus, utilisez git bisect run <script> qui exécute un script de test à chaque étape, rendant la recherche entièrement automatique.
Questions clés (validation des acquis du chapitre)
- Reflog : dans quels cas le reflog "sauve" un travail perdu ? Pourquoi ne remplace-t-il pas un backup/remote ?
- Récupération : après un
reset --hard, comment retrouver le commit perdu et le "sauvegarder" durablement ? - Références relatives : quelle différence entre
HEAD~3etHEAD^^^? Donnez un cas où^2a du sens. - Parents d'un merge : à quoi correspondent
HEAD^1etHEAD^2sur un commit de merge ? - Analyse : comment utiliser
git diffavec^/~pour comparer l'état avant/après un merge ? - Bisect : pourquoi
git bisectest-il efficace (principe) ? Quel prérequis rend son usage fiable ? - Bisect : quelle différence entre bisect manuel (good/bad) et
git bisect run?
Exercices :
Exercice 8 — Reflog : récupérer un commit "perdu"
Objectif : restaurer un état après une manipulation destructive.
Étapes :
- Sur une branche créer 2 commits, puis faire un
git reset --hard HEAD~1(vous venez de "perdre" le dernier commit). - Retrouver le hash via
git reflog. - Revenir sur le commit perdu (checkout) puis le sécuriser en créant une branche (ex :
recover/<date>).
Exercice 9 — Références relatives ~ et ^ sur un merge
Objectif : utiliser ~ pour remonter et ^n pour naviguer dans les parents d'un merge.
Étapes :
- Forcer la création d'un commit de merge (ex : merge
feature/...dansmainavec--no-ff). - Afficher les 2 parents :
git show HEAD^1etgit show HEAD^2(depuis le commit de merge). - Comparer les contenus avec
git diff HEAD^1..HEADpuisgit diff HEAD^2..HEAD. - Utiliser
HEAD~npour retrouver un ancêtre et expliquer ce que vous pointez.
Exercice 10 — Bisect : isoler le commit qui introduit un bug
Objectif : identifier rapidement une régression dans une série de commits.
Étapes :
- Créer une petite suite de commits où un comportement change (ex : un script/fonction qui doit retourner une valeur attendue).
- Marquer un commit "good" et un commit "bad", lancer
git bisect. - À chaque étape, tester et marquer
good/badjusqu'à identification du commit fautif. - Récupérer le hash du commit identifié + message expliquant la cause de la régression.