Bisect: encontrando o commit que introduziu um bug
1. O que é o Git Bisect e por que usá-lo?
O Git Bisect é uma ferramenta de busca binária automatizada que percorre o histórico de commits de um repositório para identificar exatamente qual commit introduziu um bug ou comportamento indesejado. Em vez de verificar manualmente dezenas ou centenas de commits, o bisect reduz o problema a uma complexidade O(log n), onde n é o número de commits entre o ponto "bom" (sem o bug) e o ponto "ruim" (com o bug).
O cenário típico é familiar: você descobre que um bug existe na versão atual (HEAD), mas sabe que ele não estava presente em uma versão anterior (por exemplo, v1.0). Em vez de inspecionar cada commit manualmente, o bisect divide o intervalo ao meio repetidamente até isolar o commit culpado. Com 1000 commits, você precisa testar apenas cerca de 10 commits — uma economia dramática de tempo e esforço.
2. Preparando o ambiente para o bisect
Antes de iniciar o bisect, você precisa identificar dois pontos no histórico:
- Commit "bom": um commit onde o bug não existe
- Commit "ruim": um commit onde o bug está presente (geralmente o HEAD)
Para encontrar esses commits, você pode usar tags, referências relativas ou hashes:
# Encontrar commits relevantes
git log --oneline --all
# Exemplo: tag v1.0 é boa, HEAD é ruim
git log --oneline v1.0..HEAD
Certifique-se de que seu repositório está limpo — sem alterações não commitadas ou arquivos não rastreados que possam interferir nos testes:
git status
# Se houver alterações, faça stash ou commit
git stash
Dicas para escolher os pontos de referência:
- Use tags semânticas:
v1.0,v2.3.1 - Use referências relativas:
HEAD~50(50 commits atrás) - Use hashes específicos:
a1b2c3d4
3. Iniciando e executando o bisect passo a passo
O processo manual do bisect segue um ciclo claro. Primeiro, inicie o bisect e marque os pontos inicial e final:
# Iniciar o bisect
git bisect start
# Marcar o commit ruim (onde o bug existe)
git bisect bad HEAD
# Marcar o commit bom (onde o bug não existe)
git bisect good v1.0
O Git então calcula o ponto médio e faz checkout automaticamente para esse commit:
Bisecting: 47 revisions left to test after this (roughly 6 steps)
[3a4b5c6d] Commit message do ponto médio
Agora você testa esse commit. Compile, execute os testes relevantes e verifique se o bug está presente:
# Exemplo: compilar e testar
make compile
./run_tests.sh
# Se o bug não está presente neste commit:
git bisect good
# Se o bug está presente neste commit:
git bisect bad
O Git continua dividindo o intervalo até restar apenas um commit — o culpado.
4. Automatizando o processo com scripts
Para projetos com testes automatizados, o comando git bisect run elimina o trabalho manual. Você fornece um script que retorna 0 para "bom" e qualquer outro código (geralmente 1) para "ruim":
# Criar script de teste
cat > test_bug.sh << 'EOF'
#!/bin/bash
make compile && ./run_tests.sh
if [ $? -eq 0 ]; then
exit 0 # Bom: testes passam
else
exit 1 # Ruim: testes falham
fi
EOF
chmod +x test_bug.sh
# Executar bisect automatizado
git bisect start HEAD v1.0
git bisect run ./test_bug.sh
O Git executa o script para cada commit no intervalo. Quando o script retorna 1 (falha), o Git marca o commit como "ruim" e continua a busca. O resultado final é exibido automaticamente:
3a4b5c6d is the first bad commit
commit 3a4b5c6d
Author: João Silva <joao@exemplo.com>
Date: Mon Jan 15 14:30:00 2024 -0300
Refatoração do módulo de autenticação
Cuidados importantes com scripts automatizados:
- O script deve ser determinístico — mesmo commit, mesmo resultado
- Evite dependências de estado externo (arquivos temporários, rede)
- Garanta que o script lide com erros de compilação adequadamente
5. Lidando com situações especiais
Commits que não compilam
Às vezes, commits intermediários podem estar em um estado inconsistente. Use git bisect skip para pular esses commits:
git bisect skip
# Ou pular commits específicos
git bisect skip a1b2c3d e4f5g6h
Bugs intermitentes
Para bugs que aparecem e desaparecem, o bisect pode ser impreciso. Estratégias:
- Execute o script várias vezes e use a maioria dos resultados
- Use
git bisect skippara commits com resultados inconsistentes - Considere usar um script que detecta o bug de forma mais robusta
Múltiplos pontos de referência
Você pode refinar a busca marcando commits adicionais como bons ou ruins:
git bisect good v1.1 # Outro commit bom conhecido
git bisect bad v2.0 # Outro commit ruim conhecido
6. Finalizando e interpretando os resultados
Quando o bisect encontra o commit culpado, você precisa sair do modo bisect e analisar o resultado:
# Sair do modo bisect e voltar ao HEAD original
git bisect reset
# Analisar o commit culpado
git show 3a4b5c6d
# Ver o diff completo
git diff 3a4b5c6d^..3a4b5c6d
# Ver arquivos alterados
git show --stat 3a4b5c6d
Para confirmar se o bug foi realmente introduzido naquele commit, você pode verificar manualmente:
# Checkout no commit anterior
git checkout 3a4b5c6d^
# Testar se o bug não está presente
# Checkout no commit suspeito
git checkout 3a4b5c6d
# Testar se o bug está presente
7. Boas práticas e dicas avançadas
Integração com CI/CD
Muitos sistemas de CI permitem acionar um bisect automaticamente quando um bug é detectado. Exemplo com GitHub Actions:
# workflow.yml
jobs:
bisect:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run bisect
run: |
git bisect start HEAD v1.0
git bisect run ./test_bug.sh
Visualizando o progresso
Use git bisect visualize para ver o estado atual do bisect:
git bisect visualize
# Abre o gitk ou git log mostrando os commits marcados
Limitações importantes
- Histórico não linear: bisect funciona melhor em históricos lineares. Merges complexos podem confundir o algoritmo
- Bisect em branches: você pode iniciar o bisect em qualquer branch, mas os resultados podem ser imprecisos se os branches divergiram significativamente
- Commits de merge: o bisect pode pular commits de merge se eles não introduzirem mudanças de código
Dicas avançadas
- Use
git bisect replay <arquivo>para repetir uma sessão de bisect anterior - Combine bisect com
git blamepara identificar o autor do commit culpado - Para projetos grandes, considere usar
git bisect skipem commits que alteram apenas documentação ou formatação
O Git Bisect é uma ferramenta poderosa que transforma a caça a bugs de uma tarefa frustrante em um processo sistemático e eficiente. Com prática, você pode reduzir o tempo de diagnóstico de horas para minutos.
Referências
- Documentação oficial do Git Bisect — Referência completa com todos os comandos e opções do bisect
- Git Tools - Debugging with Bisect (Pro Git Book) — Capítulo detalhado do livro Pro Git sobre debugging com bisect
- Using Git Bisect to Find Bugs (Atlassian) — Tutorial prático com exemplos do mundo real pela Atlassian
- Git Bisect Run: Automating Bug Hunting (DEV Community) — Guia prático sobre automação do bisect com scripts
- Fighting Bugs with Git Bisect (GitHub Blog) — Artigo do GitHub Engineering sobre casos reais de uso do bisect
- Git Bisect - A Practical Guide (FreeCodeCamp) — Guia prático com exemplos detalhados para iniciantes