Git Bisect: Binary Search for the Commit That Broke It
A regression with no obvious cause and hundreds of commits to search: git bisect halves the range each step, and with a test script it can find the culprit on its own.
On this page
My 2023 post on git bisect was short: when a bug appears and nobody knows when it was introduced, bisect checks out
the commit halfway between a known good and a known bad state, you mark it good or bad, and it repeats until it finds the
first bad commit. Divide and conquer. Even thousands of commits take only a handful of steps.
That’s all still true. Here’s the fuller version I wish I’d written.
Why it’s so fast
It’s binary search. Each step halves the range, so 1,000 commits take about 10 steps and 10,000 take about 14. Finding when a bug arrived is often most of the work of understanding why, because the offending diff is usually small.
The manual loop
git bisect start
git bisect bad # the current commit is broken
git bisect good v2.3.0 # this tag was fine
# git checks out a commit in the middle; test it, then:
git bisect good # or: git bisect bad
# …repeat until git names the first bad commit
git bisect reset # back to where you started
If a commit can’t be tested (it doesn’t build, say), git bisect skip moves on without guessing.
The automated loop
The real power is git bisect run. Give it a command that exits 0 for good and non-zero for bad, and it does the whole
search on its own:
git bisect start HEAD v2.3.0
git bisect run npm test -- src/pricing.test.ts
Write a small, focused test that reproduces the bug first. Then bisect finds the commit while you make a coffee, and the test becomes the regression test for the fix. That’s a neat combination with TDD as a Feedback Loop: reproduce, bisect, fix, keep the test.
Things that make bisect work better
- Small, focused commits. Bisect points at a commit; if that commit touches forty files, you’ve only narrowed the search a little. This is one more argument for small merge requests.
- Every commit builds. If half your history doesn’t compile, bisect spends its time skipping. Squash-merging pull requests helps here.
- Fast installs between steps. In a JavaScript project, dependencies change across history. A worktree per bisect session keeps your working copy clean while it hops around (Git Worktrees: A Desk per Branch).
- Know what “bad” means. Flaky tests make bisect lie. Make the check deterministic before you trust the answer.
When not to bother
If you can read the code and reason about the bug in a few minutes, do that. Bisect is for the regression that arrived some time in the last few hundred commits with no obvious suspect, which is exactly when it saves hours.
Originally written in 2023 → Git Bisect
- #git
- #debugging
- #regressions
- #binary-search
- #automation
↩ Linked from (0)
Nothing links here yet — it’s a fresh shoot.
↪ Links to (2)
Related by topic
- Growing
Fast Feedback from Deploy Previews
Developer tooling - Growing
Removing Secrets from Git History
Testing, quality - Growing
A Tiling Window Manager Workflow, Then and Now
Developer tooling - Growing
Contributing to Open Source, Then and Now
Career