Prod broke. The tag from two weeks ago was fine. Somewhere in the 400 commits between then and now, something introduced the regression. Eyeballing the log is hopeless. git bisect does a binary search across history for you — log₂(N) checkouts instead of N.
The flow:
git bisect start
git bisect bad # current HEAD is broken
git bisect good v1.4.0 # this tag was known-good
Git checks out a commit halfway between. You reproduce the bug (or not) and tell it:
git bisect good # the bug is NOT here, look later
git bisect bad # the bug IS here, look earlier
Repeat 8-10 times for hundreds of commits. Git narrows the range and eventually prints:
abc123def is the first bad commit
When you're done, always:
git bisect reset
That returns you to the branch you started from. Forgetting this leaves you in a detached HEAD on a random commit — a classic source of confusion when a colleague pings you mid-bisect.
Gotchas to know:
- If a midpoint commit doesn't build (unrelated breakage), use
git bisect skip — Git picks an adjacent commit instead.
- The "good" anchor has to actually be good; if you guess wrong, bisect points at the wrong commit and you wasted an hour. Re-verify your starting points.
- Bisect works on any property, not just "broken." You can binary-search for when a perf number crossed a threshold or when a string first appeared.