git bisect
Siempre que quiero usar git bisect, como lo hago de pascuas a ramos, me olvido y lo tengo que buscar en la documentación de git, que si bien es bastante exhaustiva es poco didáctica. Así que aprovecho que me lo estoy apuntando para escribir esta mini-receta por si le puede servir a alguien más.
Para los que no lo conozcan, git bisect es un comando de git para, dados un problema conocido en la revisión actual del software, y una revisión pasada que se sabe que no lo tiene, localizar el commit que introduce el problema usando búsqueda binaria. Un ejemplo de esta búsqueda binaria:
Pongamos que tenemos un problema en la revisión actual (115) que sabemos que no existía en la revisión 100:
- Git nos lleva a la revisión intermedia (108) para que comprobemos si existe el problema
- Pongamos que sí existe, se lo decimos y Git nos lleva a la intermedia entre la última buena conocida (la 100 de momento), y la primera mala (108), es decir la 104, para que lo volvamos a comprobar
- Pongamos que aquí el problema no existe, Git vuelve a repetir el proceso (nos lleva a la intermedia entre la última buena conocida (la 104, ahora), y la primera mala (108), esta vez la 106)
- Repitiendo el proceso vamos a llegar al commit ofensor
Más esquemáticamente:

Seguro que muchos de vosotros aprendísteis esto en la universidad; a mí me lo enseñó mi padre para buscar cortocircuitos en el Scalextric :-P
Pues bueno, en git eso se hace así:
$ git bisect start $ git bisect bad [commit/branch/tag/etc] $ git bisect good [commit/branch/tag/etc]
El commit se puede omitir y te refieres al actual. El caso es que con esa información git ya nos lleva a su primer candidato (el commit intermedio). Ahora nosotros deberemos comprobar si existe o no el problema. Dependiendo de lo que se trate, habrá que ejecutar algo, cargar una página en un navegador, lo que sea que reproduzca (o no) el problema. Y entonces, haremos:
$ git bisect good/bad
Git nos hará saltar otra vez al siguiente candidato. Repetimos el proceso y Git acabará por decirnos algo como:
61abbbfb73e6abb6629f73297656aaf642058d21 is the first bad commit
Que era lo que queríamos saber, ahora ya puedes usar tu arsenal habitual para resolverlo (principalmente, git show 61abbbfb73e6abb6629f73297656aaf642058d21 para ver el diff).
Importante acordarse de dos cosas antes de terminar:
- Git nos ha dejado en el último commit que hemos probado (que no es ni siquiera necesariamente el commit malo). Según lo que queramos hacer, tendremos que hacer
git checkout HEADogit checkout 61abbbfb73e6abb6629f73297656aaf642058d21) - Git guarda la información necesaria como tags, que ya no necesitamos. Usa
git bisect resetpara borrarla o la próxima vez que lo quieras usar puedes liarte un poco ;-)
¡Mamá, sin manos!
Lo que de verdad hace de git bisect la releche, es que ese proceso se puede automatizar. Escribe un test de unidad, un script, algo que reproduzca (o no) el problema, y git bisect lo ejecutará por tí las veces necesarias para averiguar cuál es el primer commit que hace tu prueba fallar. Simplemente crea un script (puede valer algo que ya tengas) que tenga código de salida 0 si la prueba pasa y cualquier otro si no (todas las herramientas de testing que yo he usado alguna vez cumplen eso) y (por ejemplo):
$ git bisect start $ git bisect bad $ git bisect good wadus $ git bisect run spec spec/bisect_spec.rb
Si el test es costoso y/o hay muchos commits entre wadus y HEAD vete a por un café, pero vamos, el caso es que cuando vuelvas tendrás en tu pantalla al malo de la peli ;-)
IMPORTANTE:
Ten en cuenta que git va a hacer checkouts para cambiar entre revisión y revisión, así que:
- No inicies el proceso con cambios sin comitear o los perderás
- Si vas a usar un test que está en el código del repositorio, también el test cambiará de versión y puede que en determinadas revisiones no reproduzca el problema (o ni siquiera exista). Lo más cómodo es crear uno nuevo y no hacer
git add. Una vez ejecutado el proceso puedes considerar añadirlo a los ya existentes o no (según convenga).




cientifico dijo
Mola. Siempre se me olvida la sintaxis y/o la forma de uso.
2 Noviembre 2009 | 06:03 PM