Guía9 min

git bisect para coding agents: start, skip, run 125, siempre reset

Resumen

git bisect busca por binario el commit que introdujo un bug. Un agente lo corre en worktree propio, marca good/bad o skip, y siempre termina con reset. git bisect run: 0 bueno, 125 no testeable, 1-127 malo. Cero reset --hard. Git 2.50.1.

GitHub
Búsqueda binaria entre un commit good y uno bad; HEAD detached hasta reset

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

git bisect no es “culpa al commit del medio”. El man (Git 2.50.1 / Apple Git-155): búsqueda binaria para hallar el commit que introdujo un bug. Le das un commit bad (tiene el bug) y uno good (antes del bug). Bisect elige un commit intermedio, hace checkout y pregunta. Al terminar, refs/bisect/bad apunta al primer bad.

También sirve para cualquier propiedad que aparezca en la historia (un fix, un rename masivo, una regresión de bench). Ahí los términos son old/new, no good/bad. No se mezclan en la misma sesión.

Esta guía no sustituye worktrees ni PRs con gh. El contrato: cuándo un agente puede bisectar, qué códigos de run valen, y cómo salir sin dejar HEAD detached.

Bisect mueve HEAD

git bisect start deja el árbol en detached HEAD en cada iteración. No es reset ni pull. Es un checkout de un SHA intermedio.

git bisect reset limpia el estado y vuelve al HEAD original (el de antes de start). Un start nuevo también limpia la sesión anterior. Con argumento: git bisect reset <commit> aterriza ahí; reset HEAD no cambia de commit — te deja en el SHA actual.

Un agente no bisecta el checkout del humano. Worktree propio, limpio, sin MERGE_HEAD ni rebase.

good y bad cierran el rango; cada paso hace checkout de un SHA

Lo que el agente sí / no corre

QuieroComandoTrampa
Abrir sesióngit bisect start <bad> <good> [-- <path>]Sin --, un path que parezca rev se come
Marcargit bisect good / git bisect badMezclar old/new con good/bad aborta el contrato de términos
No testeablegit bisect skipSi skippea el vecino del primer bad, Git no puede decir cuál fue
Automatizargit bisect run <cmd>Exit 125 = skip; 0 = good/old; 1–127 salvo 125 = bad/new; otro aborta
Salirgit bisect resetSin reset, HEAD detached queda en el árbol
Solo primer padregit bisect start --first-parent …Merges rotos en la rama topic no cuentan como introductores

Prohibido en autónomo:

  • Bisect en el worktree del humano o sobre main local. Detached HEAD + tests = sandbox ajeno.
  • git reset --hard “para probar un vecino”. El man lo sugiere (HEAD~3 si el SHA propuesto no interesa). Un agente usa git bisect skip o skip <rev> <range>. --hard es reset, no bisect.
  • Dejar la sesión abierta. Siempre git bisect reset al terminar, falle o no.
  • git bisect run con un script dentro del repo. El man: es más seguro que test.sh y el check vivan fuera, para que checkout no pise el oráculo.
  • Tratar exit -1 como “bad”. El man: exit(-1) deja $? = 255 (& 0377) y aborta el run.
  • Confundir 126/127 con skip. POSIX: 127 = comando no encontrado, 126 = no ejecutable. Eso aborta, no skipea. Skip es solo 125.
  • Mezclar términos. good/bad o old/new o --term-old/--term-new. git bisect terms recuerda cuál.
  • Commit, force-push o push desde detached HEAD de la sesión.
  • --no-checkout si el test necesita el árbol. Esa flag solo actualiza BISECT_HEAD; asume repo bare si el repo es bare.

git bisect skip v2.5..v2.6 salta después de v2.5 hasta v2.6 inclusive. Para incluir v2.5: git bisect skip v2.5 v2.5..v2.6.

Receta (60 segundos)

Solo en un worktree propio:

git status -sb                  # limpio; no MERGE_HEAD / rebase / BISECT
git bisect start HEAD <good> -- src/lib/foo.ts
git bisect run ~/oracles/foo.sh
git bisect reset

El oráculo fuera del repo:

#!/bin/sh
pnpm test -- src/lib/foo.test.ts || exit 1
exit 0

Build roto que no es el bug:

#!/bin/sh
pnpm build || exit 125
pnpm test -- src/lib/foo.test.ts

El man (ejemplo make || exit 125): 125 = “no se puede testear este SHA”.

Si run no aplica (oráculo no determinista, pide humano):

git bisect start HEAD <good> --
# testea el árbol, luego:
git bisect good    # o bad, o skip
git bisect reset   # siempre, también si abortas a mitad

Cero --continue inventado. Cero borrar .git/BISECT_* a mano.

run 0/125/1; reset vuelve al HEAD original

run, skip y --first-parent

git bisect run <cmd>: 0 → good/old; 1–127 salvo 125 → bad/new; 125 → skip; cualquier otro → aborta la sesión. El man eligió 125 porque 126/127 ya los usa el shell.

--first-parent (en start): en un merge, solo sigue el primer padre. El man: sirve cuando la rama mergeada tenía commits rotos pero el merge estaba bien — sin esto, bisect acusa un SHA interno que nunca llegó a main.

Pathspec en start recorta el grafo a los paths del bug (git bisect start -- src/lib/foo.ts). Varios good después del bad estrechan el rango: git bisect start <bad> <good1> <good2> --.

git bisect log / replay <file>: si marcaste mal, el man pide reset + replay del log editado, no parchear refs a mano.

Pro Git (Debugging with Git, HTTP 200, 2026-09-03): misma receta startbad/good → checkout intermedio → repetir. No añade flags que el man no tenga.

Checklist

  • Worktree propio, git status -sb limpio, sin bisect previo (git bisect reset si hay duda).
  • start con bad + good conocidos; pathspec si el bug es de un dir.
  • Oráculo fuera del repo. Exit 0 / 125 / 1 — nada de -1.
  • No testeable → skip, no reset --hard.
  • Al acabar: git bisect reset. Reporta refs/bisect/bad antes del reset si hace falta el SHA.
  • Cero push, commit o --hard en detached HEAD.
  • El fix va a commits/PR, no a revert a ciegas del SHA acusado.

FAQ

¿Puedo bisectar en el repo del humano “un momento”? No. Cada paso hace checkout. Un archivo sucio o un editor abierto pelea. Worktree.

¿bisect run make test? El man lo muestra. Si make falla por un SHA que no compila, el test nunca corre y ese SHA queda bad. Usa make || exit 125 y después el test.

¿old/new para buscar un fix? Sí. git bisect start sin commits, luego git bisect new HEAD y git bisect old HEAD~10. O --term-old broken --term-new fixed. No mezclar con good/bad.

¿Qué queda después? El man: refs/bisect/bad apunta al primer bad hasta el reset. Copia el SHA, luego reset.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. Bisect no es sandbox (sandboxing) ni undo de untracked (clean).

Verificado 2026-09-03 contra git-bisect(1) (Git 2.50.1 / Apple Git-155), git-scm.com/docs/git-bisect (HTTP 200) y Pro Git “Debugging with Git” (HTTP 200).