CLI AI

git bisect: ache o commit que quebrou tudo

2026-07-20

git bisect start && git bisect bad && git bisect good <hash-antigo> inicia uma busca binária pelo histórico, e git bisect run ./check.sh termina o serviço sem nenhuma resposta manual. Quem decide é o código de saída do script: 0 é bom, diferente de zero é ruim e 125 significa "este commit não dá para julgar, pule".

1. Marque os limites

clai
$ clai comece a procurar o commit que quebrou a soma, o bom conhecido é fa5873a→ git bisect start && git bisect bad && git bisect good fa5873aBisecting: 4 revisions left to test after this (roughly 2 steps)[37a14229ef73e1801a49defb16a86a26c122aa41] refactor step 5

bad sem argumento significa o HEAD atual. O git já pula para o meio do intervalo e diz quantos passos faltam: dez commits são três ou quatro verificações, mil são dez.

2. Responda a cada passo

clai
$ clai este commit funciona→ git bisect goodBisecting: 2 revisions left to test after this (roughly 1 step)[cbae02ada1b9e211691957bc7daff38a214a5a13] speed up addition

Testa, responde good ou bad e o git segue. Cada resposta joga fora metade do que sobrou.

3. A resposta

clai
$ clai este commit está quebrado→ git bisect badcbae02ada1b9e211691957bc7daff38a214a5a13 is the first bad commitcommit cbae02ada1b9e211691957bc7daff38a214a5a13Author: Demo <[email protected]>Date:   Thu Aug 27 22:52:21 2026 +0700    speed up addition calc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)

O git nomeia o primeiro commit ruim e já imprime o diffstat dele. Um git show <hash> depois fica claro que o "speed up addition" trocou um mais por um menos.

4. A mesma coisa sem nenhuma resposta manual

clai
$ clai ache o commit culpado automaticamente, o teste é ./check.sh→ git bisect run ./check.shrunning './check.sh'Bisecting: 0 revisions left to test after this (roughly 0 steps)[e0991601aa7cd6c25d3ac78b486319a7ee55713e] refactor step 6running './check.sh'cbae02ada1b9e211691957bc7daff38a214a5a13 is the first bad commitbisect found first bad commit

É esta a parte que vale lembrar. O script devolve 0 para um commit bom e qualquer coisa diferente de zero para um ruim, e pode ser uma linha só: test "$(./calc.sh 2 3)" = "5".

5. Commits que nem compilam

clai
$ clai pule os commits que não compilam→ git bisect run ./check125.sh

O código 125 é especial: significa "sobre este commit não dá para opinar, pule". Esse passo aparece no git bisect log como uma linha # skip:. O formato usual é: build quebrou → exit 125, teste falhou → exit 1.

6. Volte para onde começou

clai
$ clai encerre o bisect e me devolva para a minha branch→ git bisect resetPrevious HEAD position was cbae02a speed up additionSwitched to branch 'main'

Durante um bisect o repositório fica em detached HEAD. O reset devolve você à branch de onde partiu. Esquecer disso rende uma noite inteira se perguntando por que a cópia de trabalho está cheia de código velho.

Gotchas

  • Uma resposta errada estraga a busca inteira. Testado num repositório real: responder bad no lugar de good num único passo fez o git culpar e099160 em vez do verdadeiro cbae02a. A cura é o git bisect log: salve, corrija a linha errada e refaça com git bisect replay.
  • git bisect run lê códigos de saída, não a saída. Um script que imprime "FAILED" e sai com 0 conta como sucesso. Qualquer valor acima de 127 aborta o bisect inteiro.
  • Mantenha o script de teste fora do repositório. Um arquivo não rastreado sobrevive aos checkouts, mas um script que só existe nos commits recentes some assim que o git pula para um antigo — levando o seu bisect junto.

Related questions

E se eu não souber nenhum commit bom? Pegue um claramente velho: git bisect good HEAD~200. Se ele também estiver quebrado, o git avisa logo no primeiro passo.

Dá para bisectar por uma string na saída? Dá, com qualquer comando: git bisect run sh -c '! ./app 2>&1 | grep -q "NullPointer"'. O que importa é que 0 signifique bom.

Como vejo o que o commit culpado mudou? git show <hash> imprime o diff completo, git show --stat <hash> só a lista de arquivos.

See also

O CliAI escreve os comandos do bisect e o script de teste de uma linha a partir de uma descrição comum, e mostra os dois antes de rodar. Instale em uma linha.