git bisect
Aprenda o comando git bisect para fazer busca binária no histórico e encontrar o commit exato que introduziu um bug. Inclui automação com run.
O comando git bisect ajuda você a encontrar o commit exato que introduziu um bug realizando uma busca binária pelo seu histórico. Você informa ao Git um commit onde o código funcionava ("good") e um onde está quebrado ("bad"), e o Git verifica repetidamente o ponto médio para você testar, reduzindo o intervalo suspeito pela metade a cada vez, até restar um único culpado.
Este capítulo aborda como executar uma sessão de bisect manualmente, como interpretar o progresso que o Git exibe após cada resposta, como automatizar toda a busca com um comando de teste, como pular commits que não podem ser testados e como se recuperar caso você cometa um erro.
Definição
Por que busca binária
Se um bug apareceu em algum momento nos últimos 1.000 commits, verificá-los um a um seria exaustivo. A busca binária precisa de apenas cerca de dez testes para identificar o responsável, pois cada resposta corta os candidatos restantes pela metade — aproximadamente log2(N) etapas para N commits. O git bisect automatiza o controle para que você só precise responder "funciona aqui?"
Iniciando uma sessão de bisect
Inicie a sessão, depois marque o estado atual quebrado e um commit passado conhecido como bom:
git bisect start
git bisect bad # the current commit is broken
git bisect good v1.4.0 # this tag was known to workO Git faz checkout de um commit no meio do caminho entre eles. Você compila e testa essa revisão, depois informa o resultado:
git bisect good # this commit works — bug is newer
# or
git bisect bad # this commit is broken — bug is here or olderApós cada resposta, o Git exibe quanto do intervalo ainda resta e faz checkout do próximo ponto médio:
Bisecting: 7 revisions left to test after this (roughly 3 steps)
[a1b2c3d4...] Refactor the parserRepita o ciclo de testar-e-marcar até o Git anunciar o primeiro commit ruim:
a1b2c3d4 is the first bad commit
commit a1b2c3d4...
Refactor the parserLendo o resultado com git bisect log
A qualquer momento você pode revisar as respostas fornecidas até agora. Isso também é útil para manter um registro da sessão:
git bisect logSe você suspeitar ter marcado um commit de forma errada, redefina e reproduza um log corrigido em vez de começar tudo de novo:
git bisect log > bisect-run.txt # edit out the mistaken line
git bisect reset
git bisect replay bisect-run.txtEncerrando a sessão
Quando o Git relatar o culpado, retorne ao ponto de partida:
git bisect resetIsso restaura o HEAD para o branch em que você estava antes do bisect.
Automatizando com git bisect run
Se você puder expressar o teste como um script ou comando que retorna 0 para bom e diferente de zero para ruim, o Git executará toda a busca sem intervenção:
git bisect start HEAD v1.4.0
git bisect run npm testO Git faz checkout de cada ponto médio, executa o comando, interpreta o código de saída e para no primeiro commit com falha — sem necessidade de marcação manual.
O comando pode ser qualquer executável: uma linha simples, um script shell ou um binário. Código de saída 0 significa good, qualquer código entre 1 e 127 (exceto 125) significa bad. O código de saída especial 125 informa ao Git que o commit não pode ser testado e equivale a executar git bisect skip — use-o quando a própria compilação estiver quebrada nessa revisão:
#!/bin/sh
# test.sh — skip commits that don't even compile
make || exit 125
./run-the-failing-case # exits non-zero when the bug is presentgit bisect start HEAD v1.4.0
git bisect run ./test.shgit bisect run deve ser idempotente e autocontido. Se o seu teste deixar artefatos de compilação ou arquivos modificados para trás, adicione uma etapa de limpeza para que o próximo checkout comece limpo — caso contrário, um binário desatualizado pode fazer um commit bom parecer ruim.Pulando commits que não podem ser testados
Às vezes o commit que foi verificado está quebrado por uma razão não relacionada — não compila ou uma dependência está ausente — e você genuinamente não consegue dizer "good" ou "bad". Diga ao Git para deixá-lo de lado:
git bisect skipO Git escolhe um commit próximo e continua reduzindo o intervalo. Se muitos commits em uma região forem pulados, o Git pode reportar um intervalo de candidatos em vez de um único commit.
Opções comuns
| Comando | Descrição |
|---|---|
git bisect start | Inicia uma sessão de bisect. |
git bisect bad [<commit>] | Marca um commit como quebrado (padrão: commit atual). |
git bisect good [<commit>] | Marca um commit como funcionando. |
git bisect skip | Pula um commit que não pode ser testado (por exemplo, não compila). |
git bisect run <cmd> | Automatiza a busca usando o código de saída de um comando de teste. |
git bisect log | Exibe as respostas good/bad fornecidas até agora. |
git bisect replay <file> | Reproduz um log de bisect salvo. |
git bisect reset | Encerra a sessão e restaura o HEAD original. |
Comandos relacionados
Quando o bisect aponta para o culpado, estes comandos ajudam a inspecioná-lo e agir sobre ele:
- git show — visualize as mudanças exatas introduzidas pelo commit ruim.
- git blame — veja qual commit modificou pela última vez uma linha específica.
- git log — navegue pelo histórico que o bisect percorreu.
- git revert — desfaça o commit ruim sem reescrever o histórico.
- git checkout — como o Git move o
HEAD, o que o bisect usa internamente.