Git - Trouver le commit introduisant une régression

dim. 08 juil. 2018 by Marmotte

Git est un système de gestion de versions décentralisé. Le côté décentralisé implique que chaque client télécharge une copie complète du dépôt, la plupart des opérations étant donc réalisées directement sur la machine de l'utilisateur.

Cet article fait partie d'une série expliquant quelques fonctionnalités avancées que j'utilise régulièrement.

  1. Généralités et notations
  2. Quelques configurations
  3. Notes diverses
  4. Dépôts et répertoires de travail
  5. L'historique local
  6. Retravailler l'historique des commits
  7. Trouver le commit introduisant une régression

Lorsqu'on rencontre un bug, il est courant de retourner à un point précédent dans l'historique des commits, pour vérifier s'il était déjà présent ou pas. Dans le cas d'une régression, il est possible d'automatiser partiellement ou totalement la recherche du commit l'ayant introduite avec la commande git bisect.

Initialisation

Après avoir trouvé un commit auquel le bug est présent (souvent le dernier commit de la branche), et un autre auquel le bug est absent, on peut lancer le processus de bisection :

$ git bisect start
$ git bisect good <good-commit>
$ git bisect bad <bad-commit>

Si un ou plusieurs répertoires ou fichiers sont soupçonnés de contenir le bug, il est possible de préciser leurs chemins lors du lancement du processus. Cela permettra de réduire le nombre de commits testés, puisque git ne passera alors que sur les commits modifiant ces éléments.

$ git bisect start -- <some-file> <some-directory>

Git change ensuite automatiquement de commit courant entre les deux.

Exécution manuelle

Après avoir testé manuellement la validité du commit courant (en exécutant des tests unitaires, en vérifiant le contenu d'un fichier, ou d'une autre manière), il faut indiquer à git si le commit courant est valide ou non. Cela se fait simplement avec les commandes git bisect good (bug absent) ou git bisect bad (bug présent). Il est aussi possible d'utiliser la commande git bisect skip pour indiquer qu'il est impossible de vérifier la validité de ce commit (par exemple, si un autre bug empêche de vérifier la présence de celui que l'on recherche).

Le commit courant est modifié automatiquement, pour se déplacer sur le prochain à tester. On recommence alors la vérification de validité du commit courant en boucle, jusqu'à la fin du processus.

Suivre l'avancement

Il est possible de suivre l'avancement du processus au moyen de la commande git bisect log. La liste des commits testés, ainsi que sa description et le résultat donné pour chacun est alors affiché. Cela peut permettre de vérifier ce qui a été fait en cas de soupçon d'une fausse manipulation.

Exécution automatique

Lorsque c'est possible, il est intéressant d'écrire un script qui vérifie la validité du commit de manière automatique. Ce script devra renvoyer le code de retour 0 (bug absent), 1 (bug présent) ou 125 (vérification impossible). On lance enfin le processus automatique avec la commande git bisect run </path/script>.

Résultat final

Une fois la recherche terminée, git peut afficher différents résultats.

La recherche a réussi

Le hash du commit fautif est annoncé :

<commit-hash> is the first bad commit

Les résultats retournés sont incohérents

Un même commit a été annoncé comme valide et invalide.

Ce résultat provient souvent d'une erreur de manipulation, ou d'un bug dans le script de test automatique :

<commit-hash> was both good and bad

Il existe des commits valides plus récents que des commits invalides.

Ce résultat peut provenir d'une erreur dans la validation effectuée, ou d'une précédente correction du même bug. Dans ce second cas, relancer le processus de bisection en partant d'un commit valide plus récent peut permettre de résoudre le problème :

Some good revs are not ancestor of the bad rev.
git bisect cannot work properly in this case.
Maybe you mistook good and bad revs?