Find the Bad Commit with git bisect
Use git bisect to binary-search through commits and find the exact one that introduced a bug or test failure.
git bisect is git's built-in binary search for finding the commit that introduced a bug. Mark a known-good commit, mark a known-bad commit, and git checks out commits in the middle until it finds the exact one that broke things. With a test script, it runs hands-free and pinpoints the regression in minutes.
Tested on git 2.43+.
When to Use This
- Hunting a regression that appeared "sometime last week"
- Finding which commit broke a specific test that used to pass
- Identifying when a performance regression was introduced
- Tracing the origin of a bug across hundreds of commits you didn't write
Don't use this when you already know the suspect commit (just git show it) or when commits are not independently buildable (squash them first).
Code
# Manual bisect — you check each commit yourself
git bisect start
git bisect bad # current commit is bad
git bisect good v1.2.0 # last known good tag
# Git checks out the midpoint. Test it, then:
git bisect good # if the bug is gone
# or
git bisect bad # if the bug is still there
# Repeat until git tells you "X is the first bad commit"
# When done
git bisect resetThe output of the final step looks like:
abc123def is the first bad commit
commit abc123def
Author: Someone <someone@example.com>
Date: Wed May 7 14:32:00 2026
refactor: extract validation helper
That's your culprit.
Usage
The killer feature: automated bisect with a test script.
# 1) Write a script that exits 0 for good, non-zero for bad
cat > /tmp/test-regression.sh <<'EOF'
#!/usr/bin/env bash
npm install --silent
npm test -- --testNamePattern "user can login"
EOF
chmod +x /tmp/test-regression.sh
# 2) Start bisect with the bounds
git bisect start HEAD v1.2.0
# 3) Hand it the script and walk away
git bisect run /tmp/test-regression.sh
# 4) Git runs the script at every checkout, prints the bad commit, exits.
# 5) Reset
git bisect resetFor a 1000-commit range, this takes about 10 checkouts to find the bad commit. Manual bisect on the same range takes hours; automated takes minutes.
Pitfalls
- The script must be reliable. A flaky test gives bisect false positives, and you'll chase ghosts. Run the test 3 times before bisecting if it's flaky.
- The script is run from a clean checkout each time. It must reinstall dependencies and reset state.
npm installin the script catches changes topackage.json. - Skip commits that don't compile. Use
git bisect skip(manual) or exit code 125 from the script (auto). Bisect will route around them. - Always
git bisect resetwhen done. Otherwise you stay on a detached HEAD and can lose work if you forget. - Bisect needs a working tree on the bad commit. If the bad commit references files that no longer exist, your test script may fail for the wrong reason.
- Don't bisect across merge commits if you can avoid it. Bisect handles them, but the output is less precise. Linear history makes bisect cleaner.
Related Snippets & Reading
- Recover a Deleted Branch with reflog — for when bisect reveals a commit you accidentally deleted
- Interactive Rebase to Squash Commits — clean up history before bisecting
- git bisect official docs — full reference and advanced patterns
Frequently Asked Questions
What does git bisect actually do?
git bisect performs a binary search across your commit history. You mark one commit as good (bug-free) and one as bad (bug present), and bisect checks out the midpoint. You test, mark it good or bad, and bisect picks the next midpoint. It finds the exact bad commit in log2(N) steps.
Can git bisect run automatically?
Yes. git bisect run takes a script that exits 0 for good and non-zero for bad. Bisect runs your script at every step and converges on the bad commit with no manual intervention. This is the killer feature for regression hunting.