Votre code régresse et vous ne savez pas quel commit en est la
cause ? git bisect trouve le commit fautif par recherche
dichotomique (O(log n)), sur 1000 commits, ~10 tests suffisent, et
git blame identifie qui a écrit chaque ligne. Ce guide vous apprend
à utiliser les deux outils, y compris bisect en mode automatisé et
blame avec .git-blame-ignore-revs pour masquer les reformatages.
Prérequis : Consulter l'historique et Sélection de révisions.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Utiliser
git bisectmanuellement pour isoler le commit d'une régression - Automatiser bisect avec un script de test pour des audits rapides
- Lire
git blamepour identifier l'auteur et le contexte d'une ligne - Combiner bisect et blame dans un workflow de débogage complet
git bisect : trouver une régression
Section intitulée « git bisect : trouver une régression »Le principe
Section intitulée « Le principe »bisect ne cherche pas le bug, il cherche la frontière entre deux états de
l'historique. Vous lui donnez ces deux états, il vous place au milieu, et
chaque réponse divise l'intervalle par deux. Sur 1000 commits, dix réponses
suffisent à isoler le coupable, contre 1000 vérifications dans le pire des cas
en parcourant l'historique linéairement.
La contrainte tient en une phrase : votre test doit être déterministe. Un
bug qui ne se manifeste qu'une fois sur trois donnera un résultat faux, car une
seule mauvaise réponse envoie bisect explorer la moitié d'historique qui ne
contient pas la régression.
bisect fonctionne comme une recherche dichotomique :
- Vous indiquez un commit bon (sans le bug) et un commit mauvais (avec le bug)
- Git sélectionne le commit au milieu
- Vous testez et dites si c'est bon ou mauvais
- Git réduit de moitié à chaque étape
Bisect manuel pas à pas
Section intitulée « Bisect manuel pas à pas »Pendant toute la session, Git place votre copie de travail en HEAD détaché
sur le commit à tester : vous n'êtes plus sur votre branche. C'est normal, et
c'est la raison pour laquelle l'étape 7 n'est pas optionnelle, git bisect reset étant le seul moyen propre de revenir sur la branche de départ. Pensez
aussi à committer ou remiser vos modifications en cours avant de démarrer, Git
refusera de changer de commit sinon.
-
Démarrez la session bisect :
Fenêtre de terminal git bisect start -
Marquez le commit actuel comme mauvais :
Fenêtre de terminal git bisect bad -
Marquez un commit connu comme bon (par exemple un tag ou un SHA ancien) :
Fenêtre de terminal git bisect good v1.0.0# Ou avec un SHA :git bisect good a1b2c3d -
Git checkout automatiquement le commit du milieu :
Bisecting: 15 revisions left to test after this (roughly 4 steps)[e4f5a6b...] Refactor module pricing -
Testez (lancez vos tests, vérifiez manuellement...) puis marquez :
Fenêtre de terminal git bisect good # Ce commit est OK# ougit bisect bad # Ce commit a le bug -
Répétez l'étape 5 jusqu'à ce que Git identifie le commit fautif :
d7c8b9a is the first bad commitAuthor: Bob <bob@example.com>Date: Thu Mar 20 10:00:00 2026feat: modifier le calcul de remise -
Terminez la session :
Fenêtre de terminal git bisect reset# Retour à la branche d'origine
Sauter un commit non testable
Section intitulée « Sauter un commit non testable »Tous les commits d'un historique ne sont pas testables : certains ne compilent pas, d'autres sont des états intermédiaires d'un rebase. Les déclarer « bons » ou « mauvais » au hasard fausserait toute la recherche.
git bisect skipGit écarte alors ce commit et propose un voisin. Si la zone entière est
intestable, bisect finit par annoncer une plage de commits suspects au
lieu d'un commit unique : c'est un résultat valide, à affiner à la main.
Visualiser la progression
Section intitulée « Visualiser la progression »Ces deux commandes répondent à des besoins différents. git bisect log produit
la trace de vos réponses, rejouable avec git bisect replay : c'est votre
filet de sécurité si vous vous trompez de verdict en cours de route. git bisect visualize affiche les commits encore suspects, dans gitk si un
environnement graphique est détecté, sinon dans git log.
git bisect log # Historique de la session, rejouable avec bisect replaygit bisect visualize # Commits restants (gitk, ou git log sans affichage graphique)Bisect automatisé avec un script
Section intitulée « Bisect automatisé avec un script »Le vrai pouvoir de bisect : un script teste automatiquement chaque
commit.
git bisect start HEAD v1.0.0git bisect run ./test-regression.shLe script doit retourner :
- 0 → le commit est bon
- 1 à 124, 126 à 127 → le commit est mauvais
- 125 → le commit est non testable (skip)
Exemple de script de test
Section intitulée « Exemple de script de test »Ce script montre les deux réflexes qui rendent un bisect run fiable. D'abord
la sortie 125 sur un échec de compilation : sans elle, un commit qui ne
construit pas serait déclaré mauvais et enverrait la recherche dans la mauvaise
direction. Ensuite le fait de ne lancer qu'un seul test, celui qui
reproduit la régression : lancer la suite complète multiplie le temps par le
nombre d'étapes et fait échouer le script pour des raisons sans rapport avec le
bug recherché.
Attention à une subtilité rarement documentée : un code de sortie supérieur à
127 interrompt la session au lieu de marquer le commit. Un script tué par un
signal, ou un exit -1 qui devient 255, arrête donc bisect en cours de route.
#!/bin/bash# Compiler le projetmake build 2>/dev/null || exit 125 # 125 = skip si ça ne compile pas
# Lancer le test spécifiquepython -m pytest tests/test_pricing.py::test_remise# pytest retourne 0 si OK, 1 si échec → parfait pour bisectchmod +x test-regression.shgit bisect start HEAD v1.0.0git bisect run ./test-regression.shGit exécute le script sur chaque commit testé et trouve le fautif sans intervention manuelle.
Bisect avec make ou npm
Section intitulée « Bisect avec make ou npm »Quand la commande de test tient sur une ligne, sh -c évite de créer un
fichier. Le point à ne pas manquer est la reconstruction des dépendances à
chaque étape : make clean et npm ci garantissent que vous testez bien le
code du commit courant, et non des artefacts laissés par l'étape précédente.
C'est la cause la plus fréquente d'un bisect qui désigne un commit
manifestement innocent.
# Projet C/C++git bisect run sh -c 'make clean && make && ./run_tests'
# Projet Node.jsgit bisect run sh -c 'npm ci && npm test'git blame : identifier l'auteur
Section intitulée « git blame : identifier l'auteur »git blame annote chaque ligne d'un fichier avec le commit, l'auteur
et la date :
git blame src/pricing.pya1b2c3d4 (Alice 2026-03-15 14:30:00 +0100 1) def calculate_price(qty, price):a1b2c3d4 (Alice 2026-03-15 14:30:00 +0100 2) total = qty * priced7c8b9a0 (Bob 2026-03-20 10:00:00 +0100 3) if qty > 100:d7c8b9a0 (Bob 2026-03-20 10:00:00 +0100 4) total *= 0.9a1b2c3d4 (Alice 2026-03-15 14:30:00 +0100 5) return totalLes lignes 3-4 ont été ajoutées par Bob le 20 mars.
Un détail de lecture qui déroute au premier abord : Git préfixe d'un accent
circonflexe (^) les empreintes des commits dits limites, c'est-à-dire les
plus anciens de la plage examinée. Ce marqueur signifie « la ligne existait déjà
avant le début de l'intervalle observé », pas « ce commit est spécial ».
Options utiles de blame
Section intitulée « Options utiles de blame »Trois de ces options changent radicalement le résultat et méritent d'être
utilisées par défaut. -w neutralise les réindentations, -M suit les lignes
déplacées à l'intérieur du fichier, -C les lignes reprises d'un autre fichier
modifié dans le même commit. Sans elles, blame attribue un déplacement de
code à celui qui l'a déplacé, et non à celui qui l'a écrit. Les répéter
(-C -C, -C -C -C) élargit progressivement la recherche, au prix d'un temps
d'exécution nettement plus long sur un gros fichier.
| Option | Effet | Exemple |
|---|---|---|
-L 10,25 | Limiter aux lignes 10-25 | git blame -L 10,25 file.py |
-L :func | Limiter à une fonction | git blame -L :calculate_price file.py |
-C | Détecter les lignes copiées depuis un autre fichier | git blame -C file.py |
-C -C | Détecter aussi dans les commits de création | git blame -C -C file.py |
-w | Ignorer les changements de whitespace | git blame -w file.py |
-M | Détecter les lignes déplacées dans le même fichier | git blame -M file.py |
--since | Depuis une date | git blame --since=2.weeks file.py |
Ignorer les commits de reformatage
Section intitulée « Ignorer les commits de reformatage »Les reformatages massifs (prettier, black) polluent le blame. Créez
un fichier d'exclusion :
# Reformatage avec blacka1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0# Migration vers prettiere4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3# Configurer Git pour ignorer ces commitsgit config blame.ignoreRevsFile .git-blame-ignore-revsAjoutez .git-blame-ignore-revs au repo pour que toute l'équipe en
bénéficie. GitHub reconnaît aussi ce fichier automatiquement.
git annotate
Section intitulée « git annotate »git annotate est un alias de blame avec un format de sortie
légèrement différent. En pratique, utilisez blame, c'est le
standard.
Workflow de débogage
Section intitulée « Workflow de débogage »Cet enchaînement répond à quatre questions successives : quel commit, quoi
dedans, quelles lignes, et pourquoi. Chacune se pose seulement quand la
précédente a une réponse, ce qui évite l'erreur classique consistant à lire un
blame avant de savoir quel commit chercher. La dernière étape mérite une
nuance : git revert crée un nouveau commit qui annule le fautif, sans
réécrire l'historique. C'est l'option à privilégier sur une branche partagée,
où un reset obligerait toute l'équipe à réaligner sa copie locale.
# 1. Un bug est signalé. Trouver le commit fautif :git bisect start HEAD v1.0.0git bisect run npm test
# 2. bisect trouve le commit d7c8b9a. Voir les détails :git show d7c8b9a
# 3. Identifier les lignes modifiées :git blame -L 3,4 src/pricing.py
# 4. Comprendre le contexte avec le log de la fonction :git log -L :calculate_price:src/pricing.py
# 5. Corriger et committer :git revert d7c8b9a # ou fix manuelDépannage
Section intitulée « Dépannage »Les deux premières lignes de ce tableau désignent la même cause profonde : un
script de test qui ne dit pas la vérité. Avant de lancer une session complète,
prenez trente secondes pour exécuter votre script sur un commit que vous savez
bon puis sur un commit que vous savez mauvais, et vérifiez le code de retour
avec echo $?. Un bisect lancé sur un test non fiable produit un résultat
faux avec la même assurance qu'un résultat juste.
| Symptôme | Cause probable | Solution |
|---|---|---|
| bisect retourne un mauvais commit | Script de test non fiable | Testez le script sur un commit bon et un mauvais manuellement |
| bisect tourne en boucle | Commits non testables (ne compilent pas) | Retournez 125 dans le script pour skipper |
| blame montre un commit de reformatage | Reformatage massif | Créez .git-blame-ignore-revs |
-L :func ne fonctionne pas | Langage non reconnu | Configurez *.ext diff=lang dans .gitattributes |
| bisect corrompu | Session interrompue | git bisect reset pour tout nettoyer |
À retenir
Section intitulée « À retenir »git bisect: recherche dichotomique, O(log n) commits à testergit bisect run script: automatisation complète, le script retourne 0 (bon) ou 1 (mauvais)git blame: identifie l'auteur et le commit de chaque ligne-Cdétecte les copier-coller,-wignore le whitespace.git-blame-ignore-revspour exclure les reformatages du blame- Workflow :
bisect→show→blame→log -L→ fix