¿Cómo uso git bisect?

Resuelto IAdapter asked hace 13 años • 7 respuestas

He leído algunos artículos que dicen que eso git bisectes increíble. Sin embargo, no puedo entender por qué es increíble.

  1. ¿Como lo uso?
  2. ¿Es igual svn blame?
IAdapter avatar Jan 17 '11 19:01 IAdapter
Aceptado

La idea detrás git bisectes realizar una búsqueda binaria en el historial para encontrar una regresión particular. Imagine que tiene el siguiente historial de desarrollo:

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

Usted sabe que su programa no funciona correctamente en la currentrevisión y que estaba funcionando en la revisión 0. Entonces , la regresión probablemente se introdujo en una de las confirmaciones 1, 2, 3, 4, .5current

Podría intentar verificar cada confirmación, compilarla y verificar si la regresión está presente o no. Si hay una gran cantidad de confirmaciones, esto puede llevar mucho tiempo. Esta es una búsqueda lineal. Podemos hacerlo mejor haciendo una búsqueda binaria. Esto es lo que git bisecthace el comando. En cada paso, intenta reducir a la mitad el número de revisiones potencialmente malas.

Utilizarás el comando de esta manera:

$ 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

Después de este comando, gitse realizará una confirmación. En nuestro caso, será commit 3. Debe crear su programa y verificar si la regresión está presente o no. También deberá indicar gitel estado de esta revisión git bisect badsi la regresión está presente o git bisect goodno.

Supongamos que la regresión se introdujo en el compromiso 4. Entonces la regresión no está presente en esta revisión y le decimos que lo haga git.

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

Luego verificará otra confirmación. O 4o 5(ya que solo hay dos confirmaciones). Supongamos que eligió 5. Después de una compilación, probamos el programa y vemos que la regresión está presente. Luego le decimos git:

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

Probamos la última revisión, 4. Y como es el que introdujo la regresión le decimos git:

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

En esta sencilla situación, solo tuvimos que probar 3 versiones ( 3, 4, 5) en lugar de 4 ( 1, 2, 3, 4). Esta es una pequeña victoria, pero se debe a que nuestra historia es muy pequeña. Si el rango de búsqueda es de N confirmaciones, deberíamos esperar probar 1 + log2 N confirmaciones en git bisectlugar de aproximadamente N/2 confirmaciones con una búsqueda lineal.

Una vez que haya encontrado la confirmación que introdujo la regresión, puede estudiarla para encontrar el problema. Una vez hecho esto, puedes git bisect resetvolver a poner todo en el estado original antes de usar git bisectel comando.

Sylvain Defresne avatar Jan 17 '2011 14:01 Sylvain Defresne

git bisect runbisección automática

Si tiene un ./testscript automatizado que tiene estado de salida 0 y si la prueba es correcta, puede encontrar el error automáticamente con 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

Esto supone, por supuesto, que si se ./testrealiza un seguimiento del script de prueba, no desaparece en alguna confirmación anterior durante la bisección.

He descubierto que muy a menudo puedes salirte con la tuya simplemente copiando el script del árbol y posiblemente jugando con PATHvariables tipo - y ejecutándolo desde allí.

Por supuesto, si la infraestructura de prueba de la que testdepende se rompe en confirmaciones más antiguas, entonces no hay solución y tendrá que hacer las cosas manualmente, decidiendo cómo probar las confirmaciones una por una.

Sin embargo, he descubierto que el uso de esta automatización a menudo funciona y puede suponer un gran ahorro de tiempo para las pruebas más lentas que se encuentran en su acumulación de tareas, donde puede dejar que se ejecute durante la noche y posiblemente identificar el error a la mañana siguiente. Vale la pena. el intento.

Mas consejos

Permanezca en la primera confirmación fallida después de la bisección en lugar de volver a master:

git bisect reset HEAD

start+ inicial bady goodde una vez:

git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~

es lo mismo que:

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

Vea lo que se ha probado hasta ahora (mediante manual goody bado run):

git bisect log

Salida de muestra:

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

Muestre referencias buenas y malas en git log para tener una mejor noción del tiempo:

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

Esto solo muestra confirmaciones con una referencia correspondiente, lo que reduce en gran medida el ruido, pero incluye referencias de tipo generadas automáticamente:

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

que nos dicen qué confirmaciones marcamos como buenas o malas.

Considere este repositorio de prueba si quiere jugar con el comando.

El fracaso es rápido, el éxito es lento.

A veces:

  • El fallo ocurre rápidamente, por ejemplo, una de las primeras pruebas se rompe.
  • el éxito lleva un tiempo, por ejemplo, los pases de prueba rotos y todas las demás pruebas que no nos importan siguen

Para esos casos, por ejemplo, suponiendo que la falla siempre ocurre dentro de los 5 segundos, y si nos da pereza hacer la prueba más específica como realmente deberíamos, podemos usar timeoutcomo en:

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

Esto funciona desde timeoutlas salidas 124mientras fallan las test-commandsalidas 1.

Estados de salida mágica

git bisect runes un poco exigente con los estados de salida:

  • cualquier valor superior a 127 hace que la bisección falle con algo como:

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

    In particular, a C assert(0) leads to a SIGABRT and exits with status 134, very annoying.

  • 125 is magic and makes the run be skipped with git bisect skip.

    The intention of this is to help skip broken builds due to unrelated reasons.

See man git-bisect for the details.

So you might want to use something like:

#!/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"

Tested on git 2.16.1.