Pour ceux qui ne le sauraient pas, je suis fan de ''Monotone'', un beau logiciel de gestion des versions qui fut, d'après la légende, une source d'inspiration pour un certain Linus T. au moment de créer un autre logiciel dont j'ai parlé ici.

Mais là, ce n'est pas pour casser du sucre sur le dos des autres VCS que j'écris mais pour présenter une fonctionnalité intéressante de Monotone, j'ai nommé le ''bisecting''.
But de l'opération ? Retrouver LA version qui a introduit une ou plusieurs régressions dans un logiciel.
Allons-y gaiement pour la démo !
Toutes les étapes seront détaillées mais il est possible d'utiliser la base de données attachée à ce billet.

Tout d'abord, on initialise une base de données Monotone.

fred@dagobah:~/Dev$ mtn --db=bisect_test.mtn db init

Rien de monstrueux alors on continue en créant notre projet

fred@dagobah:~/Dev$ mtn --db=bisect_test.mtn --branch=bisect_test setup bisect_test

Là encore, si vous suivez le tutorial de Monotone, toujours rien d'extraordinaire. Ajoutons un peu de code pour notre première version dans le répertoire bisect_test :

with Ada.Text_Io; use Ada.Text_Io;
 
procedure Bisect is
begin
   Put_Line("Hello world");
end Bisect;

Ok, c'est nul :)
On ajoute et on committe

fred@dagobah:~/Dev$ mtn add bisect.adb
fred@dagobah:~/Dev$ mtn ci

Après avoir saisi notre message et notre mot de passe, on a notre version. On continue :

with Ada.Text_Io; use Ada.Text_Io;
 
procedure Bisect is
 
   type My_Type is range 12..21;
 
   My_Var : My_Type := 12;
 
begin
   Put_Line("Hello world");
   Put_Line("My_Var=" & My_Type'Image(My_Var));
end Bisect;

Rebelote, on committe et on refait une modif... Bon, je vais pas tout mettre là mais ce qui est intéressant, c'est d'introduire une erreur et de refaire une version après. Voilà la version finale qui finalement compile mais comme le dit le compilateur, ça va foirer :)
Merci Ada !

with Ada.Text_Io; use Ada.Text_Io;
 
procedure Bisect is
 
   type My_Type is range 12..21;
 
   My_Var : My_Type := 11;
 
begin
   Put_Line("Hello world");
   -- Put_Line("My_Var=" & My_Type'Image(My_Var));
end Bisect;

Le problème, c'est que cela n'a pas été fait dans cette révision mais une ou plusieurs révisions avant.
Vite, retrouvons le coupable sans faire de recherche par lecture du code mais par le test.
On commence par marquer la révision courante comme foireuse :

fred@dagobah:~/Dev$ mtn bisect bad
mtn: bissection débutée à la révision « 99c46344761c157cabd4e8e41e9fb6d3a0442a92 frederic.praca@free.fr 20/12/2012 21:51:39 »
mtn: révisions en cours de bissection ; 0 bonnes, 1 mauvaises, 0 sautées. Veuillez spécifier les bonnes révisions pour débuter la recherche.

Bien sûr, vos révisions n'auront pas forcément les mêmes identifiants.
Maintenant, on retourne à la version que l'on sait fonctionner pour la marquer comme correcte :

fred@dagobah:~/Dev/bisect_test$ mtn update -r 5e78416bc66278692a30f1a807aa00b25f31ca56
mtn: sélection de la cible 5e78416bc66278692a30f1a807aa00b25f31ca56 pour la mise à jour
mtn: [gauche]  75b7d43d6a0d02baa366d48984c259a8f6df755e
mtn: [droite]  5e78416bc66278692a30f1a807aa00b25f31ca56
mtn: mise à jour de « bisect.adb »
mtn: mise à jour vers la révision de base 5e78416bc66278692a30f1a807aa00b25f31ca56
fred@dagobah:~/Dev/bisect_test$ mtn bisect good
mtn: 4 révisions en cours de bissection ; 1 bonnes, 1 mauvaises, 0 sautées, 2 restantes
mtn: mise à jour vers 2aaa51f8afa82b23d85c95843ff4f75efcd3a2b4 frederic.praca@free.fr 20/12/2012 21:51:19
mtn: mise à jour de « bisect.adb »

Et voilà, on vient de préparer la dichotomie. Une petite vérification

fred@dagobah:~/Dev/bisect_test$ mtn bisect status
mtn: 4 révisions en cours de bissection ; 1 bonnes, 1 mauvaises, 0 sautées, 2 restantes
mtn: avertissement : prochaine révision pour le test de bissection est e941bd9f9386dd74860eba21a43b35c064c41425
mtn: avertissement : toutefois, cet espace de travail est actuellement à 2aaa51f8afa82b23d85c95843ff4f75efcd3a2b4
mtn: avertissement : exécutez « bisect update » pour mettre à jour vers cette révision avant de tester

L'outil nous dit même comment faire, si c'est pas du luxe !! :)
Alors, on y va

fred@dagobah:~/Dev/bisect_test$ mtn bisect update
mtn: 4 révisions en cours de bissection ; 1 bonnes, 1 mauvaises, 0 sautées, 2 restantes
mtn: mise à jour vers e941bd9f9386dd74860eba21a43b35c064c41425 frederic.praca@free.fr 20/12/2012 21:50:33
mtn: mise à jour de « bisect.adb »

Si vous avez bien regardé la base de données fournie ou votre propre base, vous vous rendrez compte que la version vers laquelle on a mis à jour n'est pas juste la suivante mais celle qui se trouve au milieu des révisions, de la dichotomie quoi !
On teste et comme ça marche, on le dit à l'outil.

fred@dagobah:~/Dev/bisect_test$ mtn bisect good
mtn: 4 révisions en cours de bissection ; 2 bonnes, 1 mauvaises, 0 sautées, 1 restantes
mtn: mise à jour vers 2aaa51f8afa82b23d85c95843ff4f75efcd3a2b4 frederic.praca@free.fr 20/12/2012 21:51:19
mtn: mise à jour de « bisect.adb »

Et là encore, on se retrouve à mi-chemin entre la dernière bonne et la mauvaise.
Cette fois-ci, on la teste et... Bang !!! Ça part au tapis !!
Encore une fois, on le dit à l'outil

fred@dagobah:~/Dev/bisect_test$ mtn bisect bad
mtn: 4 révisions en cours de bissection ; 2 bonnes, 2 mauvaises, 0 sautées, 0 restantes
mtn: bissection terminée à la révision « 2aaa51f8afa82b23d85c95843ff4f75efcd3a2b4 frederic.praca@free.fr 20/12/2012 21:51:19 »

Et là... Youpi !!! La bissection est terminée, la première version qui a introduit l'erreur est trouvée quand la dernière révision restante est marquée comme mauvaise.
Maintenant, il y a plusieurs options :

  • Corriger et committer en créant une divergence
  • Désapprouver avec disapprove la version foireuse

Enfin, il ne faut pas oublier de faire un mtn bisect reset pour retirer les informations de bissection.
Voili, voilou, une bonne façon de retrouver des régressions :D
Amusez-vous bien !