your you track the helps example git git-bisect

you - git-blame



¿Cómo usar git bisect? (6)

TL; DR

Comienzo:

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

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

Repetir:

¿Todavía existe el problema?

  • Sí: $ git bisect bad
  • No: $ git bisect good

Resultado:

<abcdef> is the first bad commit

Cuando termine:

git bisect reset

He leído algunos artículos que dicen que git bisect es increíble, sin embargo no soy un hablante nativo y no puedo entender por qué es increíble.

¿Podría por favor demostrar en algún ejemplo de código lo que es tan sorprendente al respecto? ¿Es como la svn blame ?


git bisect run automatic bisect

Si tiene un script automatizado ./test que tiene estado de salida 0 si la prueba es correcta, puede encontrar automáticamente el error con la 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 el script de prueba ./test se realiza un seguimiento de git, no desaparece en un cometer anterior durante la bisección.

Descubrí que muy a menudo puedes escapar simplemente copiando la secuencia de comandos del árbol y, posiblemente, jugando con PATH similares a PATH y ejecutándolas desde allí.

Por supuesto, si la infraestructura de prueba de la que depende la test divide 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.

Mas consejos

Permanezca en el primer commit fallido después de bisect en lugar de volver al master :

git bisect reset HEAD

start + inicial bad y good de una sola 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_BAD_COMMIT

Vea lo que se ha probado hasta ahora (por good o bad manual o 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

Mostrar referencias buenas y malas en el registro de git para obtener una mejor noción del tiempo:

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

Esto solo muestra las confirmaciones con una referencia correspondiente, lo que reduce el ruido en gran medida, pero incluye referencias de tipo autogeneradas:

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

Los cuales nos dicen cuales compromisos marcamos como buenos o malos.

Considera este repo de prueba si quieres jugar con el comando.

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

Algunas veces:

  • el fallo ocurre rápido, 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 interesan

Para esos casos, por ejemplo, suponer que la falla siempre ocurre dentro de 5 segundos, y si somos perezosos para hacer la prueba más específica como deberíamos, podemos usar el timeout como en:

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

Esto funciona ya que el timeout sale de 124 mientras que la falla de test-command sale de 1 .

Estados de salida mágica

git bisect run es un poco exigente con los estados de salida:

  • cualquier cosa por encima de 127 hace que la bisección falle con algo como:

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

    En particular, una assert(0) C assert(0) conduce a un SIGABRT y sale con el estado 134, muy molesto.

  • 125 es mágico y hace que la carrera se git bisect skip con git bisect skip

Ver man git-bisect para los detalles.

Así que quizás quieras usar algo como:

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

Probado en git 2.16.1.


La idea detrás de git bisect es realizar una búsqueda binaria en la historia para encontrar una regresión particular. Imagina que tienes el siguiente historial de desarrollo:

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

Usted sabe que su programa no funciona correctamente en la revisión current y que funcionó en la revisión 0 . Así que la regresión fue probablemente introducida en uno de los compromisos 1 , 2 , 3 , 4 , 5 , current .

Puede intentar comprobar cada compromiso, compilarlo, verificar si la regresión está presente o no. Si hay un gran número 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 hace el comando git bisect . En cada paso, trata de reducir a la mitad la cantidad de revisiones potencialmente malas.

Usarás el comando así:

$ 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, git comprobará una confirmación. En nuestro caso, se comprometerá 3 . Debe construir su programa y verificar si la regresión está presente o no. También deberá decirle a git el estado de esta revisión con git bisect bad si está presente la regresión, o git bisect good si no lo está.

Supongamos que la regresión se introdujo en commit 4 . Entonces, la regresión no está presente en esta revisión, y se la decimos a git .

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

A continuación, se comprueba otra confirmación. Ya sea 4 o 5 (ya que solo hay dos confirmaciones). Supongamos que escogió 5 . Después de una compilación, probamos el programa y vemos que la regresión está presente. Entonces le decimos a 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 ya que es el que introdujo la regresión, le decimos a git :

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

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

Una vez que haya encontrado el compromiso que introdujo la regresión, puede estudiarlo para encontrar el problema. Una vez hecho esto, utiliza git bisect reset para volver a poner todo en el estado original antes de usar el comando git bisect .


Nota: los términos good y bad no son los únicos que puede usar para marcar un compromiso con o sin una determinada propiedad.

Git 2.7 (Q4 2015) introdujo nuevas opciones git bisect .

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

Con la documentación agregando:

A veces no está buscando el compromiso que introdujo una ruptura, sino un compromiso que causó un cambio entre algún otro estado "antiguo" y "nuevo" .

Por ejemplo, podría estar buscando el compromiso que introdujo una solución particular.
O tal vez esté buscando el primer compromiso en el que los nombres de los archivos de código fuente finalmente se convirtieron al estándar de denominación de su empresa. O lo que sea.

En tales casos, puede ser muy confuso usar los términos "bueno" y "malo" para referirse a "el estado anterior al cambio" y "el estado posterior al cambio".

Así que en lugar de eso, puedes usar los términos " old " y " new ", respectivamente, en lugar de " good " y " bad ".
(Pero tenga en cuenta que no puede mezclar " good " y " bad " con " old " y " new " en una sola sesión).

En este uso más general, usted proporciona a git bisect un compromiso " new " tiene alguna propiedad y un compromiso " old " que no tiene esa propiedad.

Cada vez que git bisect verifica un compromiso, usted prueba si ese compromiso tiene la propiedad:
Si lo hace, marque el commit como " new "; De lo contrario, márquelo como " old ".

Cuando se haga la bisección, git bisect informará qué compromiso introdujo la propiedad.

Consulte commit 06e6a74 , commit 21b55e3 , commit fe67687 (29 de junio de 2015) por Matthieu Moy ( moy ) .
Ver commit 21e5cfd (29 de junio de 2015) por Antoine Delaite ( CanardChouChinois ) .
(Fusionada por Junio ​​C Hamano - gitster - in commit 22dd6eb , 05 de octubre de 2015)


Sólo para añadir un punto más:

Podemos especificar un nombre de archivo o una ruta al git bisect start en caso de que sepamos que el error proviene de archivos particulares. Por ejemplo, supongamos que sabíamos que los cambios que causaron la regresión se encontraban en el directorio com / workingDir, entonces podemos ejecutar git bisect start com/workingDir Esto significa que solo se comprobarán las confirmaciones que cambiaron el contenido de este directorio, y esto hace que Las cosas aún más rápido.

Además, si es difícil saber si un compromiso en particular es bueno o malo, puedes ejecutar git bisect skip , que lo ignorará. Dado que hay suficientes otras confirmaciones, git bisect usará otra para limitar la búsqueda.


$ git bisect .. bisect $ git bisect .. básicamente una herramienta de Git para depurar . ''Git Bisect'' se corrige al pasar por las confirmaciones anteriores desde su última confirmación (conocida) de trabajo. Utiliza la búsqueda binaria para pasar por todos esos compromisos, para llegar al que introdujo la regresión / error.

$ git bisect start # Iniciando bisect

$ git bisect bad # que indica que la confirmación actual (v1.5) tiene el punto de "mala" de regresión / configuración

$ git bisect good v1.0 # mencionándolo como el último compromiso de trabajo bueno (sin regresión)

Esta mención de puntos "malos" y "buenos" ayudará a git bisect (búsqueda binaria) a elegir el elemento central (commit v1.3). Si la regresión está allí en commit v1.3, la establecerá como el nuevo punto ''malo'', es decir ( Bueno -> v1.0 y Malo -> v1.3 )

$ git bisect bad

o similarmente, si el commit v1.3 está libre de errores, lo configurará como el nuevo ''Punto bueno'', es decir (* Bueno -> v1.3 y Mal -> v1.6).

$ git bisect good