- El concepto de búsqueda binaria (binary search) no solo se usa en preguntas de entrevista, sino también en una herramienta de desarrollo real como Git
- En un entorno de monorepo a gran escala, cuando las pruebas fallan de repente, puede darse una situación en la que sea difícil rastrear la causa solo con los logs
- Un colega marcó un commit bueno y uno malo, y ejecutó una búsqueda automática con
git bisect, encontrando con precisión el commit problemático donde comenzó el bug
- En cada etapa se ejecuta un script para clasificar automáticamente los commits según el resultado de la prueba, e identificar el primer commit que falló
git bisect, que aprovecha el principio de la búsqueda binaria, es una herramienta poderosa para rastrear rápidamente la causa de bugs en bases de código grandes
Algoritmos y un caso real
- El algoritmo de búsqueda binaria (binary search) va más allá de ser un simple problema de entrevista: también funciona como principio clave en herramientas reales de depuración
git bisect puede usarse como una herramienta que utiliza búsqueda binaria para encontrar el “primer commit malo (first bad commit)” que introdujo el bug
- Funciona con un principio similar al problema “First Bad Version” de Leetcode
El problema en un entorno de trabajo real
- En un entorno que usa un monorepo grande, pueden producirse cientos o miles de commits al día
- Es difícil rastrear la causa de una falla de prueba solo con los logs
- La causa de la falla fue un cambio de cadena en un archivo de configuración necesario para obtener el token de una llamada remota, lo que hizo que se referenciara otra cuenta y provocó la falla de la prueba
- Ese cambio pasó las pruebas de integración, pero en la práctica causó problemas, y era difícil encontrar en qué punto exacto ocurrió entre tantos commits
Resolver el problema con git bisect
- Un colega de otro equipo usó el comando
git bisect para identificar rápidamente el commit problemático
- Después de indicar un commit bueno (good) y uno malo (bad), fue haciendo checkout automático de los commits intermedios, ejecutando pruebas y acotando la causa
- Cada ejecución de prueba tomaba tiempo, pero al final encontró exactamente el commit que introdujo el problema
- Al revertir ese commit, todas las pruebas volvieron a la normalidad
Cómo se ejecuta git bisect
Conclusión
git bisect es una herramienta práctica que aplica el principio de la búsqueda binaria al recorrido del historial de código
- Incluso en repositorios grandes o historiales de cambios complejos, permite rastrear rápidamente el momento en que se introdujo un bug
- Combinado con automatización de pruebas, hace posible una depuración estable incluso en bases de código grandes
2 comentarios
Por este tipo de problemas se usa TBD (trunk-based development).
Opiniones de Hacker News
Cuando antes trabajaba en una base de código enorme, sin cobertura de pruebas y con abstracciones desastrosas,
git bisectera casi la única herramienta realmente útilEl código era tan complejo que seguir un bug de forma lógica era imposible, así que era mucho más fácil encontrar en qué commit apareció el problema
Pero en bases de código de alta calidad no hacía tanta falta bisect. Se podía probar cada componente de forma independiente y la observabilidad también estaba bien resuelta, así que quedaba claro dónde mirar
git bisectsea algo prescindible. No solo sirve para encontrar bugs, también ayuda a entender por qué ocurrió ese bugSi es un proyecto con buenos mensajes de commit, bisect permite captar el contexto de commits pasados y reflejarlo en el commit que corrige el bug. Ese ciclo refuerza la cultura de commits en sí
Rastrearlo manualmente era imposible, pero escribí un script de bisect, lo dejé correr unos 30 minutos y encontró exactamente el commit problemático
git bisectse introdujo originalmente para encontrar regresiones del kernel de LinuxIncluso en casos imposibles de probar, como drivers de hardware, hizo posible que usuarios comunes hicieran bisect del kernel por su cuenta para identificar el commit causante
Antes había que pedir ayuda a desarrolladores por correo electrónico, pero ahora los usuarios podían acotar el problema por sí mismos
Por ejemplo, sirve para rastrear el alcance de datos procesados incorrectamente o para decidir si “esto es un bug o una funcionalidad”
Por ejemplo, si un cliente sufre el problema en una versión de hace 6 años, puedes comprobar si se resuelve al actualizar a una versión de hace 4 años
O si el código tuvo un refactor grande, también puedes ver si la corrección fue intencional o accidental
git bisectes excelente cuando funciona bien, pero no puede encontrar todos los bugsAlgunos bugs no muestran síntomas cuando se introducen y solo salen a la luz más tarde por otros cambios
En esos casos se rompe la premisa de bisect: que el bug aparece una sola vez entre un commit bueno y uno malo
Los commits que no se pueden probar se pueden marcar con
skip, pero si justo ese es el commit problemático, el resultado se vuelve ambiguoHace poco usé
git bisecten serio por primera vez, y fue casi mágicoHabía dos funciones con el mismo nombre, y durante un trabajo de formateo de código se eliminó el import de la función correcta, provocando el problema
Revisé el código varias veces, pero no entendí la causa hasta que bisect identificó el commit problemático
Normalmente ya sé en qué archivo o función apareció el bug, así que no uso bisect tan seguido
En cambio, sigo el historial de cambios de una función específica con el comando
git log -L :func_name:path/to/file.cHace falta configurar
.gitattributes.gitattributes. Quería saber qué hacía falta exactamentegit log -Les débil. Cuesta seguir una versión concreta entre funciones sobrecargadas con el mismo nombre.gitattributes, otra opción es usargit log -Spara encontrar commits que contienen una cadena específicaConviene conocer el exit code 125 en scripts de prueba
Si no puedes determinar el resultado del test, por ejemplo por un fallo de compilación, devolver 125 hace que bisect salte ese commit
Lo resumí en una entrada de mi blog
git bisect --first-parentAsí puedes encontrar rápido “qué PR introdujo el bug”, y luego hacer un bisect más detallado dentro de esa rama
Cuando aparece un flaky test, bisect realmente brilla
Si por una race condition tienes que correr una prueba cientos de miles de veces para estar seguro, dejar un script de bisect corriendo en segundo plano puede volverlo algo solucionable en la práctica
Hace poco encontré la causa de un bug con bisect en un proyecto de reproductor musical hecho con Svelte (lets-make-sweet-music.com)
No había pruebas ni logs de error, y como había muchos commits por actualizaciones de
dependabot, rastrearlo era difícilGracias a bisect encontré el commit problemático, y la causa fue que el archivo que reemplacé no implementaba la funcionalidad de binding múltiple de eventos
Si mantienes los commits pequeños, es mucho más rápido acotar la causa del problema encontrado con bisect
Alguien dijo que obligar a aprender búsqueda binaria para entrevistas era forzado, pero
git bisectes un gran ejemplo real de ese conceptoAunque no hace falta implementarla a mano. La mayoría de los lenguajes ya la ofrecen en su biblioteca estándar
Si calculas el índice medio con
(low + high) / 2, puede producirse overflowEs uno de los mejores ejercicios para entrenar el pensamiento basado en invariantes
Además de bisect, Git tiene excelentes herramientas para explorar código, como
log -L,log -SyblameHace tiempo escribí una entrada de blog sobre este tema