
Git Bisect: Binary Search for Bug Hunting
If you haven't heard of it, git bisect
is a fantastic tool for finding where breaking changes were introduced into your codebase. It performs a binary search through your commit history to identify the exact commit that introduced a regression.
What is it?
git bisect
automates the process of finding a problematic commit by repeatedly dividing the search space in half. Instead of manually checking commits one by one (O(n)), binary search finds the target in O(log n) time.
With 1,024 commits between "working" and "broken," bisect finds the culprit in 10 steps. With 10,000 commits, it takes only 14 steps.
How does it work?
The bisect process follows this algorithm:
- Start a bisect session
- Mark a commit as "bad" (contains the bug)
- Mark a commit as "good" (doesn't contain the bug)
- Git checks out the midpoint commit
- Test the commit and mark it good or bad
- Repeat until git identifies the first bad commit
Basic usage
Consider a CLI tool where the --verbose
flag is broken. It worked at commit a1b2c3d
but fails at HEAD
(commit z9y8x7w
). Here's the bisect workflow:
git bisect start
git bisect bad z9y8x7w # current broken commit
git bisect good a1b2c3d # known working commit
Git responds:
Bisecting: 25 revisions left to test after this (roughly 5 steps)
[m5n6o7p] Refactor CLI argument parser
Git has checked out the midpoint. Test the behavior:
./cli-tool --verbose
If it works, mark it good. If it fails, mark it bad:
git bisect good # or 'git bisect bad'
Git checks out the next commit to test. Repeat until complete:
e4f5g6h is the first bad commit
commit e4f5g6h1i2j3k4l5m6n7o8p9
Author: Developer <dev@example.com>
Date: Thu Oct 3 15:42:18 2025
Switch to new argument parsing library
Once finished:
git bisect reset
This returns you to your original HEAD
.
What are the use cases?
Test failures: Find when a specific test started failing.
npm test -- --grep "authentication flow"
Build breakages: Locate commits that broke compilation.
make clean && make
Can it be automated?
Yes, using git bisect run
with a test script. The script should exit with code 0 for "good" and 1-127 (except 125) for "bad".
#!/bin/bash
# test.sh
./cli-tool --verbose > /dev/null 2>&1
exit $?
Run the automated bisect:
git bisect start HEAD a1b2c3d
git bisect run ./test.sh
Git will automatically test each commit and identify the first bad one.
For more complex scenarios, use exit code 125 to skip untestable commits (e.g., won't build):
#!/bin/bash
make || exit 125 # skip if build fails
./run-tests || exit 1 # bad if tests fail
exit 0 # good if tests pass
Advanced tips and resources
Specify terms: Use custom terms instead of "good/bad":
git bisect start --term-old=fast --term-new=slow
git bisect slow
git bisect fast c4d5e6f
Skip commits: If a commit is untestable:
git bisect skip
Visualize progress: See the bisect state visually:
git bisect visualize
Start with range: Combine start and good/bad:
git bisect start HEAD a1b2c3d
More Resources
- Git bisect documentation — Official reference
- Pro Git: Debugging with Git — Comprehensive guide