Question

J'ai lu quelques articles disant que git bisect est impressionnant. Cependant, je ne suis pas un locuteur natif et je ne comprends pas pourquoi il est impressionnant.

Quelqu'un pourrait-il s'il vous plaît démontrer avec un certain exemple de code:

  1. Comment l'utiliser?
  2. Est-il comme svn blame?
Était-ce utile?

La solution

L'idée derrière git bisect est d'effectuer une recherche binaire dans l'histoire pour trouver une régression particulière. Imaginez que vous avez l'histoire du développement suivant:

... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current

Vous savez que votre programme ne fonctionne pas correctement à la révision de current, et qu'il travaillait à la 0 de révision. Ainsi, la régression a probablement été introduite dans l'un des commits 1, 2, 3, 4, 5, current.

Vous pouvez essayer de vérifier chaque validation, construire, vérifier si la régression est présente ou non. S'il y a un grand nombre de commits, cela peut prendre beaucoup de temps. Ceci est une recherche linéaire. Nous pouvons faire mieux en faisant une recherche binaire. C'est ce que la commande git bisect fait. A chaque étape, il tente de réduire le nombre de révisions qui sont potentiellement mauvais de moitié.

Vous allez utiliser la commande suivante:

$ git stash save
$ git bisect start
$ git bisect bad
$ git bisect good 0
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[< ... sha ... >] 3

Après cette commande, vous git la caisse une validation. Dans notre cas, ce sera commettre 3. Vous devez construire votre programme, et vérifier si la régression est présente ou non. Vous aurez également besoin de dire git le statut de cette révision soit git bisect bad si la régression est présente ou git bisect good si elle est pas.

Supposons que la régression a été introduite en commettre 4. Ensuite, la régression est pas présent dans cette révision, et nous dire à git.

$ make
$ make test
... ... ...
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[< ... sha ... >] 5

Il sera alors une autre caisse commettras. Soit 4 ou 5 (car il n'y a que deux commits). Admettons qu'il a pris 5. Après une construction, nous testons le programme et voir que la régression est présente. Nous disons alors à git:

$ make
$ make test
... ... ...
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[< ... sha ... >] 4

Nous testons la dernière révision, 4. Et comme il est celui qui a introduit la régression, nous disons à git:

$ make
$ make test
... ... ...
$ git bisect bad
< ... sha ... > is the first bad commit
< ... commit message ... >

Dans cette situation simple, nous ne devions tester 3 versions (3, 4, 5) au lieu de 4 (1, 2, 3, 4). Ceci est une petite victoire, mais cela est parce que notre histoire est si petit. Si la plage de recherche est de N commits, nous devrions nous attendre à tester 1 + log2 N commits avec git bisect au lieu d'environ N / 2 commits avec une recherche linéaire.

Une fois que vous avez trouvé la commettras qui a introduit la régression, vous pouvez l'étudier pour trouver le problème. Une fois cela fait, vous utilisez git bisect reset pour tout remettre à l'état d'origine avant d'utiliser la commande git bisect.

Autres conseils

git bisect run automatique bisect

Si vous avez un script automatisé ./test qui a le statut de sortie 0 ssi le test est OK, vous pouvez trouver automatiquement le bogue avec bisect run:

git checkout KNOWN_BAD_COMMIT
git bisect start

# Confirm that our test script is correct, and fails on the bad commit.
./test
# Should output != 0.
echo $?
# Tell Git that the current commit is bad.
git bisect bad

# Same for a known good commit in the past.
git checkout KNOWN_GOOD_COMMIT
./test
# Should output 0.
echo $?
# After this, git automatically checks out to the commit
# in the middle of KNOWN_BAD_COMMIT and KNOWN_GOOD_COMMIT.
git bisect good

# Bisect automatically all the way to the first bad or last good rev.
git bisect run ./test

# End the bisect operation and checkout to master again.
git bisect reset

Ceci suppose bien sûr que si le script de test est ./test git sur chenilles, qu'il ne disparaît pas sur certains commettras plus tôt au cours bissectrice.

J'ai trouvé que vous pouvez souvent sortir simplement en copiant le dans l'arbre de script sur l'arbre, et peut-être jouer avec PATH comme des variables, et l'exécuter à partir de là à la place.

Bien sûr, si l'infrastructure de test sur lequel test dépend des pauses sur les anciens commits, alors il n'y a pas de solution, et vous devrez faire des choses manuellement, de décider comment tester engage un par un.

Plus d'astuces

Rester sur le premier défaut de commettre après sécable au lieu de retourner à master:

git bisect reset HEAD

start + bad initiale et good en une seule fois:

git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~

est le même que:

git checkout KNOWN_BAD_COMMIT
git bisect start
git bisect bad
git bisect good KNOWN_GOOD_COMMIT

Voir ce qui a été testé jusqu'à présent (par le manuel good et bad ou run):

git bisect log

Exemple de sortie:

git bisect log
git bisect start
# bad: [00b9fcdbe7e7d2579f212b51342f4d605e53253d] 9
git bisect bad 00b9fcdbe7e7d2579f212b51342f4d605e53253d
# good: [db7ec3d602db2d994fe981c0da55b7b85ca62566] 0
git bisect good db7ec3d602db2d994fe981c0da55b7b85ca62566
# good: [2461cd8ce8d3d1367ddb036c8f715c7b896397a5] 4
git bisect good 2461cd8ce8d3d1367ddb036c8f715c7b896397a5
# good: [8fbab5a3b44fd469a2da3830dac5c4c1358a87a0] 6
git bisect good 8fbab5a3b44fd469a2da3830dac5c4c1358a87a0
# bad: [dd2c05e71c246f9bcbd2fbe81deabf826c54be23] 8
git bisect bad dd2c05e71c246f9bcbd2fbe81deabf826c54be23
# bad: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05] 7
git bisect bad c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05
# first bad commit: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c0

Afficher bon et mauvais refs sur git log pour obtenir une meilleure notion de temps:

git log --decorate --pretty=fuller --simplify-by-decoration master

Cela montre seulement commits avec un ref correspondant, ce qui réduit le bruit Grealy, mais ne comprend refs de type générées automatiquement:

refs/bisect/good*
refs/bisect/bad*

qui nous dit que nous avons marqué commits comme bon ou mauvais.

cette prise en pension de test si vous voulez jouer avec la commande.

L'échec est rapide, le succès est lent

Parfois:

  • échec se produit rapidement, par exemple l'un des premiers tests pauses
  • succès prend un certain temps, par exemple le test cassé passe, et tous les autres tests que nous ne se soucient pas de suivre

Pour ces cas, par exemple en supposant que l'échec se produit toujours withing 5 secondes, et si nous sommes paresseux pour rendre le test plus précis que nous devrions vraiment, nous pouvons utiliser timeout comme dans:

#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
  exit 1
fi

Cela fonctionne depuis les sorties de timeout 124 alors que l'échec des sorties de test-command 1.

états sortie magique

git bisect run est un peu pointilleux sur les statuts de la sortie:

  • quoi que ce soit au-dessus de 127 fait la bissectrice échouer avec quelque chose comme:

    git bisect run failed:
    exit code 134 from '../test -aa' is < 0 or >= 128
    

    En particulier, un conduit C de assert(0) à un SIGABRT et les sorties avec le statut 134, très ennuyeux.

  • 125 est magique et rend le be run sauté avec git bisect skip.

    L'intention est de Skip brisé builds pour des raisons non liées.

Voir man git-bisect pour les détails.

Vous pouvez utiliser quelque chose comme:

#!/usr/bin/env bash
set -eu
./build
status=0
./actual-test-command || status=$?
if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
  status=1
fi
exit "$status"

Testé sur git 2.16.1.

TL; DR

Début:

$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>

Bisecting: X revisions left to test after this (roughly Y steps)

Répétition:

L'enjeu existe encore?

  • Oui: $ git bisect bad
  • Non: $ git bisect good

Résultat:

<abcdef> is the first bad commit

Lorsque Fait:

git bisect reset

Il suffit d'ajouter un autre point:

Nous pouvons spécifier un nom de fichier ou le chemin de git bisect start au cas où nous savons que le virus est venu de fichiers particuliers. Par exemple, Supposons que nous savions que les changements qui ont causé la régression étaient dans la com / WorkingDir répertoire alors nous pouvons exécuter git bisect start com/workingDir Cela signifie que seuls les commits qui ont changé le contenu de ce répertoire seront vérifiés et cela rend les choses encore plus vite.

Aussi, s'il est difficile de dire si une livraison particulière est bon ou mauvais, vous peut fonctionner git bisect skip, qui l'ignorer. Étant donné qu'il ya suffisamment d'autres commits, git bisect utilisera une autre pour limiter la recherche à la place.

$ git bisect .. bascically outil Git pour le débogage . debugs 'Git BiSect' en passant par le précédent commits depuis votre dernière (connue) de commit. Il utilise la recherche binaire pour passer par tous les commits, pour arriver à celui qui a introduit la régression / bug.

# $ git bisect start A partir bisect

# $ git bisect bad indiquant que le courant commit (v1.5) a la régression / mise en point 'mauvais'

# $ git bisect good v1.0 mentionner le dernier bon fonctionnement commit (sans régression)

Cette mention de 'mauvais' et 'bon' des points vous aideront git bisect (recherche binaire) Choisissez l'élément central (commit v1.3). Si la régression est là à commettre v1.3, vous allez définir comme nouveau 'mauvais' point de savoir ( Bon -> v1.0 et Bad -> v1.3 )

$ git bisect bad

ou même, si l'commettras v1.3 est sans bug vous définissez comme le nouveau 'Bon point' à savoir (* Bon -> v1.3 et Bad -> v1.6).

$ git bisect good

Note:. Les termes good et bad ne sont pas les seuls que vous pouvez utiliser pour marquer un commettras avec ou sans une certaine propriété

Git 2.7 (Q4 2015) introduit de nouvelles options de git bisect.

 git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
                  [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]

Avec la documentation en ajoutant:

  

Parfois, vous ne cherchez pas la validation qui a introduit une rupture, mais plutôt pour une livraison qui a provoqué un changement entre un autre état « ancien » Etat et « nouveau » .

     

Par exemple, vous cherchez peut-être la validation qui a introduit une solution particulière.
  Ou vous cherchez peut-être le premier commit dans lequel les noms de code source ont finalement été tous convertis à la norme de dénomination de votre entreprise. Ou autre.

     

Dans ce cas, il peut être très déroutant d'utiliser les termes « bons » et « mauvais » pour désigner « l'état avant le changement » et « l'état après le changement ».

     

Ainsi, au lieu, vous pouvez utiliser les termes "old" et "new", respectivement, à la place de "good" et "bad".
  (Mais notez que vous ne pouvez pas mélanger « good » et « bad » avec « old » et « new » en une seule séance.)

     

Dans cet usage plus général, vous fournir git bisect avec un « new » commit a une propriété et un « old » commit qui n'a pas cette propriété.

     

Chaque fois que vérifie git bisect un commit, vous tester si ce commit a la propriété:
  Dans le cas contraire, marquer le commettras comme « new »; autrement, le marquer comme "old".

     

Lorsque la bissectrice est fait, git bisect fera rapport qui allouent introduit la propriété.


Voir commettre 06e6a74 , commit 21b55e3 , Matthieu Moy (moy) .
Voir engager 21e5cfd (29 juin 2015) par Antoine Delaite (CanardChouChinois) .
(Fusionné par Junio ??Hamano C - gitster - commit 22dd6eb , 5 octobre 2015)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top