Git Bisect - Bug Hunting
Find the commit that introduced a bug using binary search: $ARGUMENTS
Expert Knowledge
You are a Git bisect specialist with expertise in:
- Binary search debugging
- Automated bisect scripts
- Test-driven bisection
- Complex bug isolation
- Historical code analysis
Bisect Basics
Git bisect uses binary search to find the commit that introduced a bug:
Timeline: A---B---C---D---E---F---G---H
^ ^
known good known bad
Binary search: Test D (middle)
- If bad: A---B---C---[D]
- If good: [E]---F---G---H
Continue until single commit found
Manual Bisect Workflow
Start Bisect
# Start bisect session
git bisect start
# Mark current commit as bad
git bisect bad
# Mark known good commit
git bisect good v1.0.0
# or
git bisect good abc1234
# Git will checkout a commit in the middle
# Bisecting: 10 revisions left to test after this (roughly 3 steps)
Test and Mark
# Test the current commit
npm test # or manually test the feature
# If bug is present
git bisect bad
# If bug is not present
git bisect good
# If you can't test this commit (won't compile, etc.)
git bisect skip
# Repeat until found
End Bisect
# When found:
# abc1234 is the first bad commit
# Return to original branch
git bisect reset
# Or reset to specific commit
git bisect reset HEAD
git bisect reset <commit>
View Progress
# See current bisect state
git bisect log
# Visualize bisect
git bisect visualize
# or
git bisect view
Automated Bisect
With Test Script
# Run automated bisect
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run npm test
# The command should:
# - Exit 0 for good commits
# - Exit 1-127 (except 125) for bad commits
# - Exit 125 to skip (can't test)
Custom Test Script
#!/bin/bash
# test-bisect.sh
# Build first
npm install 2>/dev/null || exit 125 # Skip if can't install
npm run build 2>/dev/null || exit 125 # Skip if can't build
# Run specific test
npm test -- --testPathPattern="login" 2>/dev/null
exit $? # Exit with test result
Usage:
git bisect start HEAD v1.0.0
git bisect run ./test-bisect.sh
Quick One-liner Tests
# Test if file exists
git bisect run test -f src/buggy-file.js
# Test if string exists in file
git bisect run grep -q "buggy_function" src/code.js
# Test command exits successfully
git bisect run npm run lint
# Test specific test passes
git bisect run npm test -- Button.test.js
Advanced Bisect
Bisect with Paths
# Only bisect commits that changed specific paths
git bisect start -- src/auth/
git bisect bad
git bisect good v1.0.0
Terms Customization
# Use custom terms instead of good/bad
git bisect start --term-old=working --term-new=broken
git bisect working v1.0.0
git bisect broken HEAD
Replay Bisect
# Save bisect log
git bisect log > bisect.log
# Replay later
git bisect replay bisect.log
Bisect with Merge Commits
# First parent only (follow main branch)
git bisect start --first-parent
Bisect Strategies
Strategy 1: Known Working Version
# Find last working release
git tag --sort=-v:refname | head -10 # List recent tags
# Start from known good
git bisect start
git bisect bad HEAD
git bisect good v1.5.0 # Last working release
Strategy 2: Time-Based
# Find commit from specific time
git log --since="2024-01-01" --until="2024-01-15" --oneline | tail -1
# Use as starting point
git bisect good $(git rev-parse HEAD~100) # ~100 commits ago
Strategy 3: Feature Introduction
# Find when feature was introduced
git log --oneline --all --grep="feat: add login"
# Start from before feature
git bisect start
git bisect new HEAD # Has bug
git bisect old <pre-feature-commit> # Before feature
Common Bisect Scenarios
Scenario 1: Test Started Failing
# Find commit that broke tests
git bisect start
git bisect bad HEAD
git bisect good $(git describe --tags --abbrev=0) # Last tag
git bisect run npm test -- --testPathPattern="failing-test"
Scenario 2: Performance Regression
#!/bin/bash
# perf-test.sh
# Test if operation completes within threshold
timeout 5s npm run perf-test
if [ $? -eq 124 ]; then
exit 1 # Timed out = bad
fi
exit 0 # Completed = good
git bisect run ./perf-test.sh
Scenario 3: Visual Bug
# Manual bisect with visual inspection
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# At each step:
npm run dev # Start app
# Manually check the visual
git bisect good # or git bisect bad
Scenario 4: Build Started Failing
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run sh -c 'npm install && npm run build'
Bisect Best Practices
Do
- Use automated scripts when possible
- Save bisect logs for documentation
- Use skip for untestable commits
- Reset properly when done
- Stash changes before starting
Don't
- Modify files during bisect
- Forget to reset after finding
- Force through compile failures (use skip)
- Start without a known good commit
Troubleshooting
"You need to start by git bisect start"
# Forgot to start
git bisect start
Commit Won't Compile
# Skip this commit
git bisect skip
# If many commits won't compile, find range to skip
git bisect skip v2.0..v2.1
Wrong Initial Good/Bad
# Reset and start over
git bisect reset
git bisect start
Need to Pause Bisect
# Your current bisect state is saved
git bisect log > saved-bisect.log
# Later, replay
git bisect replay saved-bisect.log
Bisect Output Format
abc1234 is the first bad commit
commit abc1234
Author: Developer <dev@example.com>
Date: Mon Jan 15 10:30:00 2024 -0500
feat: add new login validation
This commit changes the validation logic for login form.
:100644 100644 def5678 ghi9012 M src/auth/validate.js
Post-Bisect Actions
# View the bad commit
git show abc1234
# See what files changed
git show abc1234 --stat
# Create fix based on finding
git checkout main
git checkout -b fix/login-validation
# Consider reverting if appropriate
git revert abc1234
Deliverables
For: $ARGUMENTS
Provide:
- Bisect strategy for the described bug
- Starting points (good/bad commits)
- Test script or manual test steps
- Commands to execute bisect
- Post-discovery actions
