Français ▾ Topics ▾ Latest version ▾ git-bisect-lk2009 last updated in 2.40.0

Résumé

"git bisect" permet aux utilisateurs de logiciels et aux développeurs de trouver facilement le commit qui a introduit une régression. Nous montrons pourquoi il est important d’avoir de bons outils pour lutter contre les régressions. Nous décrivons comment "git bisect" fonctionne de l’extérieur et les algorithmes qu’il utilise à l’intérieur. Ensuite, nous expliquons comment tirer parti de "git bisect" pour améliorer les pratiques actuelles. Et nous discutons de la façon dont "git bisect" pourrait s’améliorer à l’avenir.

Introduction à "git bisect"

Git est un système de contrôle de version distribué (DVCS) créé par Linus Torvalds et entretenu par Junio Hamano.

Dans Git comme dans de nombreux autres systèmes de contrôle de version (VCS), les différents états des données gérées par le système sont appelés commits. Et, comme les VCS sont principalement utilisés pour gérer le code source logiciel, parfois des changements de comportement « intéressants » dans le logiciel sont introduits dans certains commits.

En fait, les gens sont particulièrement intéressés par des commits qui présentent un comportement « mauvais », appelé un bug ou une régression. Ils s’intéressent à ces commits parce qu’un commit (seulement) contient un très petit ensemble de changements de code source. Et il est beaucoup plus facile de comprendre et de corriger correctement un problème quand vous n’avez qu’à vérifier un très petit ensemble de changements, que quand vous ne savez pas où regarder en premier lieu.

Pour aider les gens à trouver des commits qui introduisent un comportement « mauvais », l’ensemble de commandes "git bisect" a été inventé. Et il s’ensuit bien sûr que dans "git bisect", les commits où le « comportement intéressant » est présent sont appelés « mauvais » commits, tandis que d’autres commits sont appelés « bons » commits. Et un commit qui introduit le comportement que nous sommes intéressés est appelé un « premier mauvais commit ». Notez qu’il pourrait y avoir plus d’un « premier mauvais commit » dans l’espace de commits que nous explorons.

Donc "git bisect" est conçu pour aider à trouver un « premier mauvais commit ». Et pour être aussi efficace que possible, il essaie d’effectuer une recherche binaire.

Aperçu de la lutte contre les régressions

Les régressions : un problème important

Les régressions sont un gros problème dans l’industrie logicielle. Mais il est difficile de mettre des chiffres réels derrière cette affirmation.

Il y a quelques chiffres sur les bugs en général, comme une étude NIST en 2002 [1] qui indique :

Les bugs logiciels, ou les erreurs, sont si répandus et si préjudiciables qu’ils coûtent à l’économie américaine un montant estimé à 59,5 milliards de dollars par an, soit environ 0,6% du produit intérieur brut, selon une étude nouvellement publiée commandée par l’Institut national des normes et de la technologie du ministère du Commerce (NIST). Au niveau national, plus de la moitié des coûts sont supportés par les utilisateurs de logiciels et le reste par les développeurs/vendors de logiciels. L’étude a également constaté que, bien que toutes les erreurs ne puissent pas être supprimées, plus d’un tiers de ces coûts, ou un montant estimé à 22,2 milliards de dollars, pourraient être éliminés par une infrastructure d’essai améliorée qui permet d’identifier et de supprimer plus efficacement les défauts logiciels. Ce sont les économies associées à l’augmentation du pourcentage (mais pas 100 pour cent) d’erreurs plus proches des stades de développement dans lesquels elles sont introduites. À l’heure actuelle, plus de la moitié de toutes les erreurs ne sont trouvées qu’en « aval » dans le processus de développement ou pendant l’utilisation de logiciels après vente.

Et puis :

Les développeurs de logiciels dépensent déjà environ 80 pour cent des coûts de développement sur l’identification et la correction des défauts, et pourtant peu de produits de tout type autre que le logiciel sont expédiés avec ces niveaux élevés d’erreurs.

Finalement, la conclusion a commencé avec :

Le chemin vers une qualité logicielle supérieure est considérablement amélioré les tests logiciels.

D’autres estimations indiquent que 80 % des coûts liés aux logiciels concernent l’entretien [2].

Bien que, selon Wikipedia [3] :

Une perception commune de l’entretien est qu’il est simplement de corriger les bogues. Cependant, des études et des enquêtes au cours des années ont indiqué que la majorité, plus de 80%, de l’effort d’entretien est utilisée pour des actions non correctrices (Pigosky, 1997). Cette perception est perpétuée par les utilisateurs qui soumettent des rapports de problèmes qui en réalité sont des améliorations de fonctionnalité au système.

Mais nous pouvons deviner que l’amélioration des logiciels existants est très coûteuse parce que vous devez surveiller les régressions. Au moins, cela rendrait les études ci-dessus cohérentes entre elles.

Bien sûr, une sorte de logiciel est développé, puis utilisé pendant un certain temps sans être amélioré souvent, puis finalement abandonné. Dans ce cas, bien sûr, les régressions peuvent ne pas être un gros problème. Mais d’autre part, il y a beaucoup de gros logiciels qui sont continuellement développés et entretenus pendant des années ou même des dizaines d’années par beaucoup de gens. Et comme il y a souvent beaucoup de gens qui dépendent (parfois de manière critique) de tels logiciels, les régressions sont un très grand problème.

Un tel logiciel est le noyau Linux. Et si nous regardons le noyau Linux, nous pouvons voir que beaucoup de temps et d’effort est dépensé pour lutter contre les régressions. Le cycle de sortie commence par une fenêtre de fusion de 2 semaines. Puis la première version candidate (rc) est marquée. Et après cela, environ 7 ou 8 versions supplémentaires de rc apparaîtront avec environ une semaine entre chacune d’elles, avant la version finale.

Le temps entre la première version rc et la version finale est supposé être utilisé pour tester les versions rc et combattre les bugs et surtout les régressions. Et cette fois-ci, c’est plus de 80% du temps de stabilisation. Mais ce n’est pas encore la fin du combat, car bien sûr il continue après la publication.

Et puis c’est ce qu’Ingo Molnar (un développeur Linux bien connu) dit sur son utilisation de git bisect :

Je l’utilise le plus activement pendant la fenêtre de fusion (quand beaucoup d’arbres se fusionnent en amont et quand l’afflux de bugs est le plus élevé) - et oui, il y a eu des cas que je l’ai utilisé plusieurs fois par jour. Ma moyenne est environ une fois par jour.

Ainsi les régressions sont combattues tout le temps par les développeurs, et en effet il est bien connu que les bugs devraient être corrigés le plus tôt possible, dès qu’ils sont trouvés. C’est pourquoi il est intéressant d’avoir de bons outils à cette fin.

Autres outils pour lutter contre les régressions

Quels sont les outils utilisés pour combattre les régressions ? Ils sont presque les mêmes que ceux utilisés pour combattre les bugs réguliers. Les seuls outils spécifiques sont des suites de test et des outils similaires à "git bisect".

Les suites d’essai sont très agréables. Mais quand elles sont utilisés seules, elles sont supposées être utilisées pour que tous les tests soient vérifiés après chaque commit. Cela signifie qu’elles ne sont pas très efficaces, parce que de nombreux tests sont exécutés pour aucun résultat intéressant, et elles souffrent d’explosion combinatoire.

En fait, le problème est que le gros logiciel a souvent plusieurs options de configuration différentes et que chaque cas de test devrait passer pour chaque configuration après chaque commit. Donc si vous avez pour chaque sortie : N configurations, M commits et T test cases, vous devez effectuer :

N * M * T tests

où N, M et T grandissent avec la taille de votre logiciel.

Très vite, il ne sera pas possible de tout tester.

Et si certains bugs échappent à votre suite de test, vous pouvez ajouter un test à votre suite de test. Mais si vous voulez utiliser votre nouvelle suite de test améliorée pour trouver où le bug a glissé, alors vous devrez soit émuler un processus de bisection ou vous allez peut-être tester bêtement chaque commit en arrière à partir du "mauvais" commit que vous avez, ce qui peut gaspiller beaucoup de ressources.

Survol "git bisect"

Commencer une bisection

La première sous-commande "git bisect" à utiliser est "git bisect start" pour commencer la recherche. Ensuite, les limites doivent être fixées pour limiter l’espace des commits. Cela se fait généralement en donnant un "mauvais" commit et au moins un "bon" commit. Ils peuvent être passés dans l’appel initial à "git bisect start" comme ceci :

$ git bisect start [MAUVAIS [BON...]]

ou ils peuvent être réglés en utilisant :

$ git bisect bad [COMMIT]

et :

$ git bisect good [COMMIT...]

où MAUVAIS, BON et COMMIT sont tous les noms qui peuvent être résolus à un commit.

Puis "git bisect" va extraire un commit de son choix et demander à l’utilisateur de le tester, comme ceci :

$ git bisect start v2.6.27 v2.6.25
Bisecting: 10928 revisions left to test after this (roughly 14 steps)
[2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86 : clean up using max_low_pfn on 32-bit

Notez que l’exemple que nous allons utiliser est vraiment un exemple simplifié, nous allons chercher le premier commit qui a une version comme "2.6.26-quelquechose", c’est le commit qui a une ligne "SUBLEVEL = 26" dans le Makefile de niveau supérieur. Il s’agit d’un exemple simplifié parce qu’il y a de meilleures façons de trouver ce commit avec Git que d’utiliser "git bisect" (par exemple "git blame" ou "git log -S<chaîne>").

Piloter manuellement une bisection

À ce stade, il y a essentiellement 2 façons de piloter la recherche. Elle peut être pilotée manuellement par l’utilisateur ou elle peut être conduite automatiquement par un script ou une commande.

Si l’utilisateur la pilote, alors à chaque étape de la recherche, l’utilisateur devra tester le commit actuel et dire si c’est "bon" ou "mauvais" en utilisant les commandes "git bisect good" ou "git bisect bad" respectivement qui ont été décrites ci-dessus. Par exemple :

$ git bisect bad
Bisecting: 5480 revisions left to test after this (roughly 13 steps)
[66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file->f_count abuse in kvm

Et après quelques étapes comme ça, "git bisect" va finalement trouver un premier mauvais commit :

$ git bisect bad
2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
commit 2ddcca36c8bcfa251724fe342c8327451988be0d
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Sat May 3 11:59:44 2008 -0700

    Linux 2.6.26-rc1

:100644 100644 5cf82581... 4492984e... M      Makefile

À ce moment, nous pouvons voir ce que le commit fait, l’extraire (s’il n’est pas déjà extrait) ou bricoler avec lui, par exemple :

$ git show HEAD
commit 2ddcca36c8bcfa251724fe342c8327451988be0d
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Sat May 3 11:59:44 2008 -0700

    Linux 2.6.26-rc1

diff --git a/Makefile b/Makefile
index 5cf8258..4492984 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 25
-EXTRAVERSION =
+SUBLEVEL = 26
+EXTRAVERSION = -rc1
 NAME = Funky Weasel is Jiggy wit it

 # *DOCUMENTATION*

Et quand nous en avons fini, nous pouvons utiliser "git bisect reset" pour retourner à la branche où nous étions avant de commencer à bissecter :

$ git bisect reset
Checking out files: 100% (21549/21549), done.
La position précédente de HEAD était sur 2ddcca3... Linux 2.6.26-rc1
Basculement sur la branche 'master'

Conduire une bissection automatiquement

L’autre façon de piloter le processus de bissection est de dire à « git bisect » de lancer un script ou une commande à chaque étape de bissection pour savoir si le commit courant est « bon » ou « mauvais ». Pour ce faire, on utilise la commande « git bisect run ». Par exemple :

$ git bisect start v2.6.27 v2.6.25
Bisecting: 10928 revisions left to test after this (roughly 14 steps)
[2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit
$
$ git bisect run grep '^SUBLEVEL = 25' Makefile
running grep ^SUBLEVEL = 25 Makefile
Bisecting: 5480 revisions left to test after this (roughly 13 steps)
[66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file->f_count abuse in kvm
running grep ^SUBLEVEL = 25 Makefile
SUBLEVEL = 25
Bisecting: 2740 revisions left to test after this (roughly 12 steps)
[671294719628f1671faefd4882764886f8ad08cb] V4L/DVB(7879): Adding cx18 Support for mxl5005s
...
...
running grep ^SUBLEVEL = 25 Makefile
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[2ddcca36c8bcfa251724fe342c8327451988be0d] Linux 2.6.26-rc1
running grep ^SUBLEVEL = 25 Makefile
2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
commit 2ddcca36c8bcfa251724fe342c8327451988be0d
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Sat May 3 11:59:44 2008 -0700

    Linux 2.6.26-rc1

:100644 100644 5cf82581... 4492984e... M      Makefile
bisect run success

Dans cet exemple, on a passé « grep ^SUBLEVEL = 25 Makefile » comme paramètre à « git bisect run ». Cela signifie qu’à chaque étape, la commande grep qu’on a passée sera lancée. Et si elle se termine avec le code 0 (cela signifie succès), git bisect marquera l’état courant comme « bon ». Si elle se termine avec le code 1 (ou n’importe quel code entre 1 et 127 inclus, sauf le code spécial 125), l’état courant sera marqué comme « mauvais ».

Les codes de sortie entre 128 et 255 sont spéciaux pour « git bisect run ». Ils lui font arrêter immédiatement le processus de bissection. C’est utile par exemple si la commande passée prend trop de temps à se terminer, car on peut la tuer avec un signal et cela arrêtera le processus de bissection.

Il peut aussi être utile dans les scripts passés à « git bisect run » de faire « exit 255 » si une situation très anormale est détectée.

Éviter les commits intestables

Il arrive parfois que l’état courant ne puisse pas être testé, par exemple s’il ne compile pas parce qu’il y avait un bogue qui l’en empêchait à ce moment-là. C’est à cela que sert le code de sortie spécial 125. Il dit à « git bisect run » que le commit courant doit être marquée comme non testable et qu’une autre doit être choisie et extraite.

Si le processus de bissection est piloté manuellement, on peut utiliser « git bisect skip » pour faire la même chose. (En fait, le code de sortie spécial 125 fait que « git bisect run » utilise « git bisect skip » en arrière-plan.)

Ou si vous voulez plus de contrôle, vous pouvez inspecter l’état courant en utilisant par exemple « git bisect visualize ». Cela lancera gitk (ou « git log » si la variable d’environnement DISPLAY n’est pas définie) pour vous aider à trouver un meilleur point de bissection.

Dans tous les cas, si vous avez une série de commits non testables, il peut arriver que la régression que vous cherchez ait été introduite par l’une de ces commits non testables. Dans ce cas, il n’est pas possible de dire avec certitude quel commit a introduit la régression.

Donc si vous avez utilisé « git bisect skip » (ou si le script run s’est terminé avec le code spécial 125), vous pourriez obtenir un résultat comme celui-ci :

Il ne reste que des commits 'skip'pées à tester.
Le premier mauvais commit pourrait être l'un de :
15722f2fa328eaba97022898a305ffc8172db6b1
78e86cf3e850bd755bb71831f42e200626fbd1e0
e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace
070eab2303024706f2924822bfec8b9847e4ac1b
On ne peut plus bissecter !

Sauvegarder un journal et le rejouer

Si vous voulez montrer à d’autres personnes votre processus de bissection, vous pouvez obtenir un journal en utilisant par exemple :

$ git bisect log > bisect_log.txt

Et il est possible de le rejouer en utilisant :

$ git bisect replay bisect_log.txt

Détails de "git bisect"

Algorithme de bisection

Comme les commits Git forment un graphe acyclique orienté (DAG), trouver la meilleur commit de bissection à tester à chaque étape n’est pas si simple. Quoi qu’il en soit, Linus a trouvé et implémenté un algorithme « vraiment stupide », amélioré plus tard par Junio Hamano, qui fonctionne assez bien.

L’algorithme utilisé par « git bisect » pour trouver la meilleur commit de bissection quand il n’y a pas de commits ignorées est le suivant :

1) ne garder que les commits qui :

a) sont ancêtres du commit « mauvais » (y compris le commit « mauvais » elle-même), b) ne sont pas ancêtres d’un commit « bon » (en excluant les commits « bons »).

Cela signifie qu’on se débarrasse des commits sans intérêt dans le DAG.

Par exemple, nous démarrons avec un graphe comme celui-ci :

G-Y-G-W-W-W-X-X-X-X
	   \ /
	    W-W-B
	   /
Y---G-W---W
 \ /   \
Y-Y     X-X-X-X

-> le temps s'écoule dans ce sens ->

où B est le commit « mauvais », « G » sont les commits « bons » et W, X, et Y sont d’autres commits, on obtiendra le graphe suivant après cette première étape :

W-W-W
     \
      W-W-B
     /
W---W

Donc seules les commits W et B seront conservées. Parce que les commits X et Y auront été supprimées par les règles a) et b) respectivement, et parce que les commits G sont supprimées par la règle b) aussi.

Note pour les utilisateurs de Git : c’est équivalent à ne garder que le commit donné par :

git rev-list BAD --not GOOD1 GOOD2...

Notez également qu’on n’exige pas que les commits conservées soient des descendants d’un commit « bon ». Donc dans l’exemple suivant, les commits W et Z seront conservées :

G-W-W-W-B
   /
Z-Z

2) en partant des extrémités « bonnes » du graphe, associer à chaque commit le nombre de ses ancêtres plus un

Par exemple avec le graphe suivant où H est le commit « mauvais » et A et D sont des parents de certains commits « bons » :

A-B-C
     \
      F-G-H
     /
D---E

cela donnera :

1 2 3
A-B-C
     \6 7 8
      F-G-H
1   2/
D---E

3) associer à chaque commit : min(X, N - X)

où X est la valeur associée au commit à l’étape 2) et N est le nombre total de commits dans le graphe.

Dans l’exemple ci-dessus on a N = 8, donc cela donnera :

1 2 3
A-B-C
     \2 1 0
      F-G-H
1   2/
D---E

4) le meilleur point de bissection est le commit avec le nombre associé le plus élevé

Donc dans l’exemple ci-dessus, le meilleur point de bissection est le commit C.

5) noter que des raccourcis sont implémentés pour accélérer l’algorithme

Comme on connaît N dès le début, on sait que min(X, N - X) ne peut pas être supérieur à N/2. Donc pendant les étapes 2) et 3), si on devait associer N/2 à un commit, alors on sait que c’est le meilleur point de bissection. Dans ce cas, on peut simplement arrêter de traiter toute autre commit et retourner le commit courant.

Débogage de l’algorithme de bissection

Pour n’importe quel graphe de commits, on peut voir le nombre associé à chaque commit en utilisant « git rev-list --bisect-all ».

Par exemple, pour le graphe ci-dessus, une commande telle que :

$ git rev-list --bisect-all MAUVAIS --not BON1 BON2

produirait quelque chose comme :

e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace (dist=3)
15722f2fa328eaba97022898a305ffc8172db6b1 (dist=2)
78e86cf3e850bd755bb71831f42e200626fbd1e0 (dist=2)
a1939d9a142de972094af4dde9a544e577ddef0e (dist=2)
070eab2303024706f2924822bfec8b9847e4ac1b (dist=1)
a3864d4f32a3bf5ed177ddef598490a08760b70d (dist=1)
a41baa717dd74f1180abf55e9341bc7a0bb9d556 (dist=1)
9e622a6dad403b71c40979743bb9d5be17b16bd6 (dist=0)

Discussion de l’algorithme de bissection

Définissons d’abord le « meilleur point de bissection ». On dira qu’un commit X est un meilleur point de bissection ou une meilleur commit de bissection si connaître son état (« bon » ou « mauvais ») donne autant d’informations que possible sur le fait que l’état du commit soit « bon » ou « mauvais ».

Cela signifie que les meilleurs commits de bissection sont les commits où la fonction suivante est maximale :

f(X) = min(information_if_good(X), information_if_bad(X))

où information_if_good(X) est l’information qu’on obtient si X est bon et information_if_bad(X) est l’information qu’on obtient si X est mauvais.

Maintenant on va supposer qu’il n’y a qu’une seule « premier mauvais commit ». Cela signifie que tous ses descendants sont « mauvais » et tous les autres commits sont « bons ». Et on va supposer que tous les commits ont une probabilité égale d’être bons ou mauvais, ou d’être le premier mauvais commit, donc connaître l’état de c commits donne toujours la même quantité d’information où que soient ces c commits sur le graphe et quelle que soit c. (On suppose donc que le fait que ces commits soient par exemple sur une branche ou près d’un bon ou mauvais commit ne donne pas plus ou moins d’information).

Supposons également qu’on ait un graphe nettoyé comme celui obtenu après l’étape 1) de l’algorithme de bissection ci-dessus. Cela signifie qu’on peut mesurer l’information qu’on obtient en termes de nombre de commits qu’on peut supprimer du graphe..

Prenons également un commit X dans le graphe.

Si X s’avère « bon », alors on sait que tous ses ancêtres sont « bons », donc on veut dire que :

information_if_good(X) = number_of_ancestors(X)  (VRAI)

Et c’est vrai car à l’étape 1) b) on supprime les ancêtres des commits « bons ».

Si X s’avère « mauvais », alors on sait que tous ses descendants sont « mauvais », donc on veut dire que :

information_if_bad(X) = number_of_descendants(X)  (FAUX)

Mais c’est faux car à l’étape 1) a) on ne garde que les ancêtres du mauvais commit. Donc on obtient plus d’information quand un commit est marqué comme « mauvais », car on sait aussi que les ancêtres du précédent commit « mauvais » qui ne sont pas des ancêtres du nouveau commit « mauvais » ne sont pas le premier mauvais commit. On ne sait pas si elles sont bonnes ou mauvaises, mais on sait qu’elles ne sont pas le premier mauvais commit car elles ne sont pas ancêtres du nouveau commit « mauvais ».

Donc quand un commit est marqué comme « mauvais », on sait qu’on peut supprimer tous les commits du graphe sauf ceux qui sont des ancêtres du nouveau commit « mauvais ». Cela signifie que :

information_if_bad(X) = N - number_of_ancestors(X)  (VRAI)

où N est le nombre de commits dans le graphe (nettoyé).

Donc en fin de compte, cela signifie que pour trouver les meilleurs commits de bissection, on devrait maximiser la fonction :

f(X) = min(number_of_ancestors(X), N - number_of_ancestors(X))

Et c’est bien car à l’étape 2) on calcule number_of_ancestors(X) et donc à l’étape 3) on calcule f(X).

Prenons le graphe suivant comme exemple :

            G-H-I-J
           /       \
A-B-C-D-E-F         O
           \       /
            K-L-M-N

Si nous calculons la fonction non optimale suivante dessus :

g(X) = min(number_of_ancestors(X), number_of_descendants(X))

on obtient :

            4 3 2 1
            G-H-I-J
1 2 3 4 5 6/       \0
A-B-C-D-E-F         O
           \       /
            K-L-M-N
            4 3 2 1

mais avec l’algorithme utilisé par git bisect on obtient :

            7 7 6 5
            G-H-I-J
1 2 3 4 5 6/       \0
A-B-C-D-E-F         O
           \       /
            K-L-M-N
            7 7 6 5

On choisit donc G, H, K ou L comme meilleur point de bissection, ce qui est mieux que F. Car si par exemple L est mauvais, alors on saura non seulement que L, M et N sont mauvais mais aussi que G, H, I et J ne sont pas le premier mauvais commit (puisqu’on suppose qu’il n’y a qu’une seule premier mauvais commit et qu’elle doit être un ancêtre de L).

L’algorithme actuel semble donc être le meilleur possible étant donné ce qu’on a initialement supposé.

Algorithme de saut

Quand certains commits ont été sautées (avec « git bisect skip »), l’algorithme de bissection est le même pour les étapes 1) à 3). Mais ensuite on utilise grosso modo les étapes suivantes :

6) trier les commits par valeur associée décroissante

7) si le premier commit n’a pas été sautée, on peut la retourner et s’arrêter ici

8) sinon filtrer tous les commits sautés dans la liste triée

9) utiliser un générateur de nombres pseudo-aléatoires (PRNG) pour générer un nombre aléatoire entre 0 et 1

10) multiplier ce nombre aléatoire par sa racine carrée pour le biaiser vers 0

11) multiplier le résultat par le nombre de commits dans la liste filtrée pour obtenir un indice dans cette liste

12) retourner le commit à l’indice calculé

Discussion sur l’algorithme de saut

Après l’étape 7) (dans l’algorithme de saut), on pourrait vérifier si le deuxième commit a été sauté et la retourner si ce n’est pas le cas. Et en fait c’était l’algorithme utilisé depuis le développement de « git bisect skip » dans Git version 1.5.4 (sorti le 1er février 2008) jusqu’à Git version 1.6.4 (sorti le 29 juillet 2009).

Mais Ingo Molnar et H. Peter Anvin (un autre développeur bien connu du noyau linux) se sont tous deux plaints que parfois les meilleurs points de bissection se trouvaient tous dans une zone où tous les commits sont non testables. Et dans ce cas, l’utilisateur était invité à tester de nombreuses commits non testables, ce qui pouvait être très inefficace.

En effet, les commits non testables sont souvent non testables parce qu’une régression a été introduite à un moment donné, et cette régression n’a été corrigée qu’après l’introduction de nombreuses autres commits.

Cette régression est bien sûr la plupart du temps sans rapport avec la régression qu’on essaie de localiser dans le graphe de commits. Mais elle nous empêche de savoir si le « mauvais comportement » intéressant est présent ou non.

Il est donc avéré que les commits proches d’un commit non testable ont une forte probabilité d’être elles-mêmes non testables. Et les meilleurs commits de bissection se trouvent souvent ensemble aussi (à cause de l’algorithme de bissection).

C’est pourquoi c’est une mauvaise idée de simplement choisir la prochaine meilleur commit de bissection non sautée quand la première a été sautée.

On a constaté que la plupart des commits sur le graphe peuvent donner beaucoup d’information quand ils sont testés. Et les commits qui ne donneront pas beaucoup d’information en moyenne sont ceux proches des bons et mauvais commits.

Utiliser un PRNG avec un biais favorisant les commits éloignées des bons et mauvais commits semblait donc un bon choix.

Une amélioration évidente de cet algorithme serait de chercher un commit dont la valeur associée est proche de celle de la meilleur commit de bissection, et qui se trouve sur une autre branche, avant d’utiliser le PRNG. Car si une tel commit existe, elle n’a pas de fortes chances d’être elle aussi non testable, donc elle donnera probablement plus d’information qu’un commit choisi presque au hasard.

Vérification des bases de fusion

Il y a un autre ajustement dans l’algorithme de bissection qui n’a pas été décrit dans l'« algorithme de bissection » ci-dessus.

Dans les exemples précédents, on a supposé que les commits « bons » étaient des ancêtres du commit « mauvais ». Mais ce n’est pas une exigence de « git bisect ».

Bien sûr, le commit « mauvais » ne peut pas être un ancêtre d’un commit « bon », car les ancêtres des bons commits sont supposés être « bons ». Et tous les commits « bons » doivent être liées à le mauvais commit. Elles ne peuvent pas être sur une branche qui n’a aucun lien avec la branche du commit « mauvais ». Mais il est possible qu’une bon commit soit liée à une mauvais commit sans être ni l’un de ses ancêtres ni l’un de ses descendants.

Par exemple, il peut y avoir une branche « main », et une branche « dev » qui a été bifurquée de la branche principale à un commit nommé « D » comme ceci :

A-B-C-D-E-F-G  <--main
       \
        H-I-J  <--dev

Le commit « D » est appelée « base de fusion » pour les branches « main » et « dev » car c’est le meilleur ancêtre commun pour ces branches pour une fusion.

Supposons maintenant que le commit J est mauvais et le commit G est bon et qu’on applique l’algorithme de bissection comme décrit précédemment.

Comme décrit à l’étape 1) b) de l’algorithme de bissection, on supprime tous les ancêtres des bons commits car ils sont supposés être bons aussi.

Il ne nous resterait donc que :

H-I-J

Mais que se passe-t-il si le premier mauvais commit est « B » et si elle a été corrigée dans la branche « main » par le commit « F » ?

Le résultat d’une telle bissection serait qu’on trouverait que H est le premier mauvais commit, alors qu’en fait c’est B. Ce serait donc faux !

Et oui, il peut arriver en pratique que les personnes travaillant sur une branche ne soient pas au courant que les personnes travaillant sur une autre branche ont corrigé un bogue ! Il pourrait aussi arriver que F ait corrigé plus d’un bogue ou que ce soit une annulation de gros travaux de développement qui n’étaient pas prêts à être publiés.

En fait, les équipes de développement maintiennent souvent à la fois une branche de développement et une branche de maintenance, et ce serait assez facile pour elles si « git bisect » fonctionnait simplement quand elles veulent bissecter une régression sur la branche de développement qui n’est pas sur la branche de maintenance. Elles devraient pouvoir commencer à bissecter en utilisant :

$ git bisect start dev main

Pour activer cette fonctionnalité supplémentaire intéressante, quand une bissection est démarrée et que certains bons commits ne sont pas des ancêtres du mauvais commit, on calcule d’abord les bases de fusion entre les mauvais et les bons commits et on choisit ces bases de fusion comme premiers commits qui seront extraits et testés.

S’il arrive qu’une base de fusion soit mauvaise, alors le processus de bissection est arrêté avec un message tel que :

La base de fusion BBBBBB est mauvaise.
Cela signifie que le bogue été corrigé entre BBBBBB et [GGGGGG,...].

où BBBBBB est le hachage sha1 de la mauvaise base de fusion et [GGGGGG,…​] est une liste séparée par des virgules des sha1 des bons commits.

Si certaines des bases de fusion sont sautées, le processus de bissection continue, mais le message suivant est affiché pour chaque base de fusion sautée :

Avertissement : la base de fusion entre BBBBBB et [GGGGGG, ...] doit être évitée.
On ne peut donc pas être certain que le premier commit mauvais se trouve entre MMMMMM et BBBBBB.
On continue tout de même.

où BBBBBB est le hachage sha1 du mauvais commit, MMMMMM est le hachage sha1 de la base de fusion qui est sautée et [GGGGGG,…​] est une liste séparée par des virgules des sha1 des bons commits.

Donc s’il n’y a pas de mauvaise base de fusion, le processus de bissection continue comme d’habitude après cette étape.

Meilleures pratiques de bissection

Utiliser les suites de tests et git bisect ensemble

Si vous avez à la fois une suite de tests et utilisez git bisect, il devient moins important de vérifier que tous les tests passent après chaque commit. Bien sûr, c’est probablement une bonne idée d’avoir des vérifications pour éviter de casser trop de choses car cela pourrait rendre la bissection d’autres bogues plus difficile.

Vous pouvez concentrer vos efforts pour vérifier en quelques points (par exemple les versions rc et bêta) que tous les T cas de test passent pour toutes les N configurations. Et quand certains tests ne passent pas, vous pouvez utiliser « git bisect » (ou mieux « git bisect run »). Vous devriez donc effectuer approximativement :

c * N * T + b * M * log2(M) tests

où c est le nombre de tours de test (donc une petite constante) et b est le ratio de bogues par commit (espérons aussi une petite constante).

C’est donc bien sûr beaucoup mieux car c’est O(N * T) contre O(N * T * M) si on testait tout après chaque commit.

Cela signifie que les suites de tests sont bonnes pour empêcher certains bogues d’être validés et elles sont aussi assez bonnes pour vous dire que vous avez des bogues. Mais elles ne sont pas si bonnes pour vous dire où des bogues ont été introduits. Pour vous le dire efficacement, git bisect est nécessaire.

L’autre avantage des suites de tests, c’est que quand vous en avez une, vous savez déjà comment tester les mauvais comportements. Vous pouvez donc utiliser cette connaissance pour créer un nouveau cas de test pour « git bisect » quand il apparaît qu’il y a une régression. Il sera ainsi plus facile de bissecter le bogue et de le corriger. Vous pouvez ensuite ajouter le cas de test que vous venez de créer à votre suite de tests.

Donc si vous savez comment créer des cas de test et comment bissecter, vous serez soumis à un cercle vertueux :

plus de tests ⇒ plus facile de créer des tests ⇒ plus facile de bissecter ⇒ plus de tests

Les suites de tests et « git bisect » sont donc des outils complémentaires très puissants et efficaces quand ils sont utilisés ensemble.

Bissecter les échecs de compilation

Vous pouvez très facilement bissecter automatiquement les compilations cassées en utilisant quelque chose comme :

$ git bisect start BAD GOOD
$ git bisect run make

Passer sh -c "des commandes" à "git bisect run"

Par exemple :

$ git bisect run sh -c "make || exit 125; ./my_app | grep 'good output'"

D’un autre côté, si vous faites cela souvent, il peut valoir la peine d’avoir des scripts pour éviter de trop taper.

Trouver les régressions de performance

Voici un exemple de script légèrement modifié par rapport à un script réel utilisé par Junio Hamano [4].

Ce script peut être passé à « git bisect run » pour trouver le commit qui a introduit une régression de performance :

#!/bin/sh

# Les erreurs de compilation ne m'intéressent pas.
make my_app || exit 255

# On vérifie si ça s'arrête dans un délai raisonnable, donc
# on le laisse tourner en arrière-plan...

./my_app >log 2>&1 &

# ... et on récupère son identifiant de processus.
pid=$!

# ... puis on attend suffisamment longtemps.
sleep $NORMAL_TIME

# ... puis on vérifie si le processus est toujours là.
if kill -0 $pid
then
	# Il tourne encore -- c'est mauvais signe.
	kill $pid; sleep 1; kill $pid;
	exit 1
else
	# Il a déjà fini (le processus $pid n'existe plus),
	# et on est satisfait.
	exit 0
fi

Suivre les meilleures pratiques générales

Il est évidemment judicieux de ne pas avoir de commits avec des changements qui cassent volontairement des choses, même si d’autres commits ultérieures corrigent la casse.

C’est aussi une bonne idée quand on utilise un SCM quelconque de n’avoir qu’un seul petit changement logique dans chaque commit.

Plus les changements dans votre commit sont petits, plus « git bisect » sera efficace. Et vous aurez probablement moins besoin de « git bisect » au départ, car les petits changements sont plus faciles à relire même s’ils ne sont relus que par l’auteur du commit.

Une autre bonne idée est d’avoir de bons messages de validation. Ils peuvent être très utiles pour comprendre pourquoi certains changements ont été effectués.

Ces meilleures pratiques générales sont très utiles si vous bissectez souvent.

Éviter les fusions sujettes aux bogues

Les fusions elles-mêmes peuvent introduire des régressions même quand la fusion ne nécessite aucune résolution de conflit dans le code source. C’est parce qu’un changement sémantique peut se produire dans une branche tandis que l’autre branche n’en est pas consciente.

Par exemple, une branche peut modifier la sémantique d’une fonction tandis que l’autre branche ajoute des appels supplémentaires à la même fonction.

La situation est bien pire si de nombreux fichiers doivent être corrigés pour résoudre les conflits. C’est pourquoi ces fusions sont appelées « fusions maléfiques ». Elles peuvent rendre les régressions très difficiles à localiser. Il peut même être trompeur de connaître le premier mauvais commit si elle se trouve être une telle fusion, car les gens pourraient penser que le bogue provient d’une mauvaise résolution de conflit alors qu’il provient d’un changement sémantique dans une branche.

En tout cas, « git rebase » peut être utilisé pour linéariser l’historique. Cela peut être utilisé soit pour éviter les fusions en premier lieu, soit pour bissecter sur un historique linéaire au lieu d’un historique non linéaire, car cela devrait donner plus d’informations en cas de changement sémantique dans une branche.

Les fusions peuvent aussi être simplifiées en utilisant des branches plus petites ou en utilisant de nombreuses branches thématiques au lieu de seulement de longues branches liées aux versions.

Et les tests peuvent être effectués plus souvent dans des branches d’intégration spéciales comme linux-next pour le noyau linux.

Adapter votre flux de travail

Un flux de travail spécial pour traiter les régressions peut donner d’excellents résultats.

Voici un exemple de flux de travail utilisé par Andreas Ericsson :

  • écrire, dans la suite de tests, un script de test qui expose la régression

  • utiliser"git bisect run" pour rechercher la modification qui l’a introduite

  • corriger le bogue qui est souvent mis en évidence par l’étape précédente

  • valider à la fois la correction et le script de test (et si nécessaire plus de tests)

Et voici ce qu’Andreas a dit sur ce flux de travail [5] :

Pour donner des chiffres concrets, notre cycle moyen rapport-correction était de 142,6 heures (selon notre traqueur de bogues un peu bizarre qui mesure simplement le temps réel). Depuis notre passage à Git, nous l’avons réduit à 16,2 heures. Principalement parce que nous pouvons maintenant rester au top de la correction des bogues, et parce que tout le monde se bouscule pour corriger les bogues (nous sommes très fiers de notre paresse à laisser Git trouver les bogues pour nous). Chaque nouvelle version donne ~40% de bogues en moins (presque certainement dû à notre nouvelle façon d’envisager l’écriture de tests).

Ce flux de travail utilise clairement le cercle vertueux entre les suites de tests et « git bisect ». En fait, il en fait la procédure standard pour traiter les régressions.

Dans d’autres messages, Andreas dit qu’ils utilisent aussi les « meilleures pratiques » décrites ci-dessus : petits commits logiques, branches thématiques, pas de fusion maléfique,…​ Ces pratiques améliorent toutes la bissectabilité du graphe de commits, en rendant la bissection plus facile et plus utile.

Un bon flux de travail devrait donc être conçu autour des points ci-dessus. C’est-à-dire rendre la bissection plus facile, plus utile et standard.

Impliquer les équipes QA et si possible les utilisateurs finaux

Ce qui est bien avec « git bisect », c’est que ce n’est pas seulement un outil pour développeurs. Il peut être utilisé efficacement par les équipes QA ou même les utilisateurs finaux (s’ils ont accès au code source ou s’ils peuvent avoir accès à toutes les compilations).

Il y a eu une discussion à un moment sur la liste de diffusion du noyau linux pour savoir s’il était acceptable de toujours demander aux utilisateurs finaux de bissecter, et de très bons arguments ont été avancés pour soutenir le point de vue que c’est acceptable.

Par exemple, David Miller a écrit [6] :

Ce que les gens ne comprennent pas, c’est que c’est une situation où le « principe du nœud terminal » s’applique. Quand vous avez des ressources limitées (ici : les développeurs), vous ne leur imposez pas la majeure partie du fardeau. Au lieu de cela, vous transmettez les choses à la ressource dont vous disposez en abondance, les nœuds terminaux (ici : les utilisateurs), pour que la situation passe effectivement à l’échelle.

Cela signifie qu’il est souvent « moins coûteux » que ce soient les équipes QA ou les utilisateurs finaux qui le fassent.

Ce qui est intéressant aussi, c’est que les utilisateurs finaux qui signalent des bogues (ou les équipes QA qui ont reproduit un bogue) ont accès à l’environnement où le bogue se produit. Ils peuvent donc souvent reproduire plus facilement une régression. Et s’ils peuvent bissecter, alors plus d’informations seront extraites de l’environnement où le bogue se produit, ce qui signifie qu’il sera plus facile de comprendre puis de corriger le bogue.

Pour les projets open source, cela peut être un bon moyen d’obtenir des contributions plus utiles des utilisateurs finaux, et de les initier aux activités de QA et de développement.

Utiliser des scripts complexes

Dans certains cas, comme pour le développement du noyau, il peut valoir la peine de développer des scripts complexes pour pouvoir automatiser entièrement la bissection.

Voici ce qu’Ingo Molnar dit à ce sujet [7] :

j’ai un script de bissection de blocage au démarrage entièrement automatisé. Il est basé sur « git-bisect run ». Je lance le script, il compile et démarre les noyaux de façon entièrement automatique, et quand le démarrage échoue (le script le remarque via le journal série, qu’il surveille en continu - ou via un délai d’expiration, si le système ne démarre pas dans les 10 minutes c’est un « mauvais » noyau), le script attire mon attention via un bip et je coupe l’alimentation de la machine de test. (oui, je devrais utiliser une prise de courant gérée pour l’automatiser à 100%)

Combiner les suites de tests, git bisect et d’autres systèmes ensemble

On a vu que les suites de tests et git bisect sont très puissants quand ils sont utilisés ensemble. Cela peut être encore plus puissant si on peut les combiner avec d’autres systèmes.

Par exemple, certaines suites de tests pourraient être exécutées automatiquement la nuit avec des configurations inhabituelles (ou même aléatoires). Et si une régression est trouvée par une suite de tests, alors « git bisect » peut être lancé automatiquement, et son résultat peut être envoyé par courriel à l’auteur de le premier mauvais commit trouvé par « git bisect », et peut-être à d’autres personnes aussi. Et une nouvelle entrée dans le système de suivi des bogues pourrait être créée automatiquement aussi.

L’avenir de la bissection

"git replace"

On a vu plus tôt que « git bisect skip » utilise maintenant un PRNG pour essayer d’éviter les zones du graphe de commits où les commits sont non testables. Le problème est que parfois le premier mauvais commit se trouvera dans une zone non testable.

Pour simplifier la discussion, on va supposer que la zone non testable est une simple suite de commits et qu’elle a été créée par une régression introduite par un commit (appelons-la BBC pour bisect breaking commit) et corrigée plus tard par une autre (appelons-la BFC pour bisect fixing commit).

Par exemple :

...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...

où on sait que Y est bon et BFC est mauvais, et où BBC et X1 à X6 sont non testables.

Dans ce cas, si vous bissectez manuellement, ce que vous pouvez faire est de créer une branche spéciale qui commence juste avant le BBC. le premier commit de cette branche devrait être le BBC avec le BFC écrasé dedans. Et les autres commits de la branche devraient être les commits entre BBC et BFC rebasées sur le premier commit de la branche, puis le commit après BFC également rebasée.

Par exemple :

      (BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'
     /
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...

où les commits marqués d’une apostrophe ont été rebasées.

Vous pouvez facilement créer une telle branche avec Git en utilisant le rebasage interactif.

Par exemple en utilisant :

$ git rebase -i Y Z

puis en déplaçant BFC après BBC et en l’écrasant.

Après cela, vous pouvez commencer à bissecter comme d’habitude dans la nouvelle branche et vous devriez finalement trouver le premier mauvais commit.

Par exemple :

$ git bisect start Z' Y

Si vous utilisez « git bisect run », vous pouvez utiliser la même correction manuelle que ci-dessus, puis démarrer un autre « git bisect run » dans la branche spéciale. Ou comme le dit la page de manuel de « git bisect », le script passé à « git bisect run » peut appliquer un patch avant de compiler et tester le logiciel [8]. Le patch devrait transformer un commit actuellement non testable en un commit testable. Ainsi, le test donnera « bon » ou « mauvais » et « git bisect » pourra trouver le premier mauvais commit. Et le script ne devrait pas oublier de supprimer le patch une fois les tests terminés avant de quitter le script.

(Notez qu’au lieu d’un patch vous pouvez utiliser « git cherry-pick BFC » pour appliquer la correction, et dans ce cas vous devriez utiliser « git reset --hard HEAD^ » pour annuler le cherry-pick après les tests et avant de retourner du script.)

Mais les façons ci-dessus de contourner les zones non testables sont un peu maladroites. Utiliser des branches spéciales est bien car ces branches peuvent être partagées par les développeurs comme des branches habituelles, mais le risque est que les gens se retrouvent avec de nombreuses branches de ce type. Et cela perturbe le flux de travail normal de « git bisect ». Donc, si vous voulez utiliser « git bisect run » de façon complètement automatique, vous devez ajouter du code spécial dans votre script pour redémarrer la bissection dans les branches spéciales.

En tout cas, on peut remarquer dans l’exemple de branche spéciale ci-dessus que les commits Z' et Z devraient pointer vers le même état du code source (le même « arbre » dans le jargon git). C’est parce que Z' résulte de l’application des mêmes changements que Z juste dans un ordre légèrement différent.

Donc si on pouvait simplement « remplacer » Z par Z' lors de la bissection, on n’aurait pas besoin d’ajouter quoi que ce soit à un script. Cela fonctionnerait simplement pour n’importe qui dans le projet partageant les branches spéciales et les remplacements.

Avec l’exemple ci-dessus, cela donnerait :

      (BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'-...
     /
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z

C’est pourquoi la commande « git replace » a été créée. Techniquement, elle stocke les « refs » de remplacement dans la hiérarchie « refs/replace/ ». Ces « refs » sont comme des branches (stockées dans « refs/heads/ ») ou des étiquettes (stockées dans « refs/tags »), ce qui signifie qu’elles peuvent automatiquement être partagées comme des branches ou des étiquettes entre développeurs.

« git replace » est un mécanisme très puissant. Il peut être utilisé pour corriger des commits dans un historique déjà publié, par exemple pour changer le message de validation ou l’auteur. Et il peut aussi être utilisé à la place des « greffes » git pour relier un dépôt à un autre ancien dépôt.

En fait, c’est cette dernière fonctionnalité qui l’a « vendu » à la communauté Git, donc il est maintenant dans la branche « master » du dépôt Git de Git et devrait être publié dans Git 1.6.5 en octobre ou novembre 2009.

Un problème avec « git replace » est qu’actuellement il stocke toutes les refs de remplacement dans « refs/replace/ », mais il serait peut-être mieux si les refs de remplacement utiles uniquement pour la bissection étaient dans « refs/replace/bisect/ ». De cette façon, les refs de remplacement pourraient être utilisées uniquement pour la bissection, tandis que les autres refs directement dans « refs/replace/ » seraient utilisées presque tout le temps.

Bisection de bugs sporatiques

Une autre amélioration possible à « git bisect » serait d’ajouter optionnellement de la redondance aux tests effectués afin qu’il soit plus fiable lors du suivi de bogues sporadiques.

Cela a été demandé par certains développeurs du noyau car certains bogues appelés bogues sporadiques n’apparaissent pas dans toutes les compilations du noyau car ils dépendent beaucoup de la sortie du compilateur.

L’idée est que tous les 3 tests par exemple, « git bisect » pourrait demander à l’utilisateur de tester un commit qui a déjà été trouvé comme étant « bon » ou « mauvais » (parce qu’un de ses descendants ou un de ses ancêtres a été trouvé comme étant « bon » ou « mauvais » respectivement). S’il arrive qu’un commit ait été précédemment classé incorrectement, la bissection peut être abandonnée tôt, espérons-le avant que trop d’erreurs aient été commises. L’utilisateur devra alors examiner ce qui s’est passé et redémarrer la bissection en utilisant un journal de bissection corrigé.

Il existe déjà un projet appelé BBChop créé par Ealdwulf Wuffinga sur Github qui fait quelque chose de similaire en utilisant la théorie de recherche bayésienne [9] :

BBChop est comme git bisect (ou équivalent), mais fonctionne quand votre bogue est intermittent. C’est-à-dire qu’il fonctionne en présence de faux négatifs (quand une version se trouve fonctionner cette fois-ci même si elle contient le bogue). Il suppose qu’il n’y a pas de faux positifs (en principe, la même approche fonctionnerait, mais l’ajouter peut ne pas être trivial).

Mais BBChop est indépendant de tout SCM et il serait plus pratique pour les utilisateurs de Git d’avoir quelque chose d’intégré dans Git.

Conclusion

On a vu que les régressions sont un problème important, et que « git bisect » a de belles fonctionnalités qui complètent très bien les pratiques et autres outils, en particulier les suites de tests, généralement utilisés pour lutter contre les régressions. Mais il pourrait être nécessaire de changer certains flux de travail et (mauvaises) habitudes pour en tirer le meilleur parti.

Des améliorations aux algorithmes de « git bisect » sont possibles et certaines nouvelles fonctionnalités pourraient aider dans certains cas, mais dans l’ensemble « git bisect » fonctionne déjà très bien, est beaucoup utilisé, et est déjà très utile. Pour étayer cette dernière affirmation, laissons le dernier mot à Ingo Molnar quand l’auteur lui a demandé combien de temps il pense que « git bisect » lui fait gagner quand il l’utilise :

beaucoup.

Il y a environ dix ans, j’ai fait ma première « bissection » d’une file de patches Linux. C’était avant Git (et même avant BitKeeper). J’ai littéralement passé des jours à trier des patches, créant ce qui était essentiellement des commits autonomes que je supposais être liées à ce bogue.

C’était un outil de dernier recours absolu. Je préférais passer des jours à regarder la sortie de printk plutôt que de faire une bissection de patch manuelle.

Avec Git bisect c’est un jeu d’enfant : dans le meilleur des cas je peux faire une bissection de noyau en ~15 étapes en 20-30 minutes, de façon automatisée. Même avec une aide manuelle ou lors de la bissection de plusieurs bogues qui se chevauchent, c’est rarement plus d’une heure.

En fait c’est inestimable car il y a des bogues que je n’essaierais même jamais de déboguer sans git bisect. Dans le passé, il y avait des motifs de bogues qu’il m’était immédiatement impossible de déboguer - au mieux je pouvais envoyer la signature du plantage/bogue à lkml et espérer que quelqu’un d’autre puisse trouver quelque chose.

Et même si une bissection échoue aujourd’hui, elle nous dit quelque chose de précieux sur le bogue : qu’il est non déterministe - dépendant du timing ou de la disposition de l’image noyau.

Donc git bisect est un bien inconditionnel - et n’hésitez pas à le citer ;-)

Remerciements

Mes sincères remerciements à Junio Hamano pour son aide dans la relecture de cet article, pour la relecture des patches que j’ai envoyés à la liste de diffusion Git, pour avoir discuté de certaines idées et m’avoir aidé à les améliorer, pour avoir beaucoup amélioré « git bisect » et pour son formidable travail dans la maintenance et le développement de Git.

Mes sincères remerciements à Ingo Molnar pour m’avoir donné des informations très utiles qui apparaissent dans cet article, pour ses commentaires sur cet article, pour ses suggestions pour améliorer « git bisect » et pour l’évangélisation de « git bisect » sur les listes de diffusion du noyau linux.

Mes sincères remerciements à Linus Torvalds pour avoir inventé, développé et évangélisé « git bisect », Git et Linux.

Mes sincères remerciements aux nombreuses autres grandes personnes qui ont aidé d’une façon ou d’une autre quand je travaillais sur Git, en particulier Andreas Ericsson, Johannes Schindelin, H. Peter Anvin, Daniel Barkalow, Bill Lear, John Hawley, Shawn O. Pierce, Jeff King, Sam Vilain, Jon Seymour.

Mes sincères remerciements au comité de programme du Linux-Kongress pour avoir choisi l’auteur pour donner une conférence et pour avoir publié cet article.