Git Bisect — Find the Commit That Introduced a Bug
In this tutorial, you'll learn about Git Bisect. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
What You'll Learn
Use git bisect to perform binary search on your commit history — identify the exact commit that introduced a bug in minutes, not hours.
Why It Matters
When a bug appears and you don't know when it started, manually checking commits is slow. Git bisect automates the search — it finds the guilty commit in O(log n) steps.
Real-World Use
A test started failing and you have 200 commits since it last passed. Git bisect finds the culprit in 8 steps instead of checking 200 commits.
The Problem
Good commit (tests pass) → 200 commits → Bad commit (tests fail)
Without bisect: Check commits one by one (200 steps)
With bisect: Binary search (8 steps)
Basic Bisect
# Start bisect
git bisect start
# Mark the current commit as bad
git bisect bad # HEAD is broken
# Mark a known good commit
git bisect good a1b2c3 # This commit was working
# Git checks out a commit halfway between good and bad
# Test it, then tell git if it's good or bad
git bisect good # This commit is fine
# Git checks out another commit halfway
git bisect bad # This commit is broken
# Git narrows down more
# Repeat until Git shows you the first bad commit
# a1b2c3f4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90 is the first bad commit
The Full Workflow
# Start bisecting
git bisect start
# Mark the known state
git bisect bad # Current commit has the bug
git checkout v1.0 # Go to a tag where it worked
git bisect good # This version was clean
# Git now checks out a commit ~halfway between
# Test the current state (manually or with script)
npm test # or python -m pytest, etc.
# If tests pass:
git bisect good # Bug is in later commits
# If tests fail:
git bisect bad # Bug is in earlier commits
# Repeat until identified
# Git outputs the first bad commit
# When done:
git bisect reset # Return to original HEAD
Automating with a Script
# Create a test script
git bisect start HEAD v1.0
git bisect run npm test
# Or inline
git bisect start HEAD v1.0 --
git bisect run sh -c "npm test"
# Git automatically:
# 1. Checks out commits
# 2. Runs the command
# 3. Marks good/bad based on exit code
# 4. Repeats until found
# 5. Shows the culprit
The script should exit 0 for good (no bug) and exit 1-127 for bad (bug present).
Using a Python Script
#!/usr/bin/env python3
"""bisect-check.py: Run tests and report to git bisect."""
import subprocess
import sys
def is_bug_present():
"""Return True if the bug is present in this commit."""
# Your test logic here
result = subprocess.run(
["python", "-m", "pytest", "tests/test_login.py"],
capture_output=True
)
# Tests pass → no bug (good)
# Tests fail → bug present (bad)
return result.returncode != 0
if __name__ == "__main__":
if is_bug_present():
sys.exit(1) # bad
sys.exit(0) # good
git bisect start HEAD v2.0
git bisect run python bisect-check.py
Bisect with Specific Files
# Only bisect commits that touch certain files
git bisect start -- login.py auth/
# This skips commits that don't change these paths
Skipping Commits
Some commits can't be tested (broken build, missing dependency):
# Skip this commit
git bisect skip
# Skip a range
git bisect skip a1b2c3..d4e5f6
Visualizing Progress
git bisect log # Show the bisect log so far
git bisect visualize # Show git log with bisect state
When Done
git bisect reset # Go back to the original HEAD
Real Example
# Find what broke the login test
git checkout main
git bisect start
git bisect bad # main is broken
git checkout v2.0.0
git bisect good # v2.0.0 was working
# Git checks out commit #47 of 94
# Run test:
python -m pytest tests/test_login.py
# Test passes
git bisect good
# Git checks out commit #71
# Test fails
git bisect bad
# Narrowed to 24 commits
# Git checks out commit #62
# ... 5 more steps ...
# Result: a1b2c3f4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90 is the first bad commit
# commit a1b2c3f4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90
# Author: Jane
# Date: Mon Mar 4 14:30:00 2024
# Change authentication library
git bisect reset
# Now go fix Jane's commit!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro