KeiruaProd

I help my clients acquire new users and make more money with their web businesses. I have ten years of experience with SaaS projects. If that’s something you need help with, we should get in touch!
< Back to article list

Identifier l'origine d'une régression avec git bisect

Quand on travaille sur un gros projet, on doit parfois identifier l’origine d’une régression. C’est ce qui arrive par exemple lorsque l’on modifie une fonctionnalité pour l’enrichir : quelque chose a été cassé à un autre endroit qui utilisait la même fonctionnalité, en général sans que l’on s’en rende compte lors de la modification.

Une des difficultés, c’est d’identifier l’origine de l’erreur. Car lorsque l’on est plusieurs à travailler sur le projet et qu’il s’est passé plusieurs dizaines (voire centaines, ou plus) de commit entre le moment où la fonctionnalité marchait et celle où elle a été identifié, retrouver le commit à l’origine de l’erreur peut s’avérer être une tâche titanesque.

Sauf que !

Parmi ses nombreuses fonctionnalités sympa, git propose une solution pour ce genre de situations : la recherche dichotomique. Pour ceux qui n’écoutaient pas pendant les cours d’algo, on va partir de l’ensemble des commit, et regarder celui qui se trouve au milieu. On teste le programme, et si la régression est présente, on sait qu’il faut chercher dans les commit qui se trouve avant, sinon dans ceux qui se trouvent après. Et on recommence, jusqu’à ce qu’on ait trouvé l’origine de l’erreur. Bien sûr, git propose un moyen pratique de faire ça, il s’agit de git bisect.

L’avantage ?

La vitesse, et la rigueur ! Quand comme moi on a 85 commits à revoir, au lieu de tester un peu au hasard et n’être pas sûr de trouver après de nombreux essais, avec cette méthode on est certain de trouver l’origine de l’erreur en environ 6 étapes. Et avec cette méthode, le nombre d’étapes augmente lentement : pour 1000 commits, il y aurait seulement une dizaine de commits à revoir !

On fait comment ? Il faut tout d’abord identifier un commit où la fonctionnalité marchait. Ça peut être une ancienne version taggée, un commit… bref, il faut avoir un point de départ. Dans cet exemple, on va dire qu’il n’y avait pas régression lors du commit bacd25e, et qu’on s’en est rendu compte dans la dernière version (sur le HEAD courant).

On démarre le mode de recherche :
<br /> git bisect start<br />
On indique que le HEAD est une version où la fonctionnalité considérée ne fonctionne pas :
<br /> git bisect bad<br />
On indique ensuite un commit où ça marche avec git bisect bad [hash du commit]

git bisect good bacd25e

Et c’est parti !

Git nous positionne sur un commit intermédiaire, il faut maintenant tester l’application dans ses différents états.

Après avoir testé, on indique à git si notre fonctionnalité marchait (avec git bisect good) ou ne marchait pas (avec git bisect bad). On obtient alors un nouveau commit à essayer, et ainsi de suite.

gitbisect_goodbad

On continue à tester les différentes versions jusqu’à ce que git nous dise qu’on a fini de chercher.
Git nous présente alors le coupable :

gitbisect_summary

Il ne reste plus qu’à regarder dans les modifications faites lors de ce commit (avec un outil tel que gitk par exemple, pour ne pas galérer dans la console s’il y a eu de grosses modifications), et trouver l’origine de l’erreur. Avant de se mettre au boulot, revenez au bon endroit sur votre branche de travail en quittant le mode de recherche avec :

git bisect reset

Bonus !

La commande log de git est par défaut assez peu pratique. Voici une commande que je trouve assez utile pour gagner de la place, voir les branches et mettre de la couleur :

git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

screen_better_log

 

Bon OK, c’est très flou, mais vous voyez l’idée.

Comme il n’est pas très pratique de taper régulièrement cette commande, le plus simple est d’en faire un alias :

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"<br />

Désormais, lorsque l’on tape git lg dans la console on a accès à ces logs plus sympa. Merci à Filipe Kiss pour l’astuce !