Something that worked last week is broken now, and dozens of changes have landed since. Reading every one to find the guilty change would eat your whole day, and staring at the current code tells you nothing about when it went wrong. This chapter gets you to the exact change that broke it, fast, by halving the search instead of walking it.
7.4.1Find when it last worked
You need two markers: a past point where the feature worked, and a point where it is broken, usually right now. Every change between them is a suspect.
Instead of checking each suspect in order, check the one in the middle. Is the bug there or not? That single test tells you which half to throw away.
To bisect is to cut the range in two, test the midpoint, and keep only the half that still contains the break. A hundred suspects fall to seven tests.
7.4.2Narrow it with git
Git does this bookkeeping for you with git bisect. You hand it one commit where the feature worked and one where it is broken. It then checks out the midpoint for you to test, over and over, until one change is left.
This is where committing in small green slices pays off. Because each saved step did one thing, the change bisect lands on is a short, readable diff, not an afternoon of braided edits you cannot untangle.
7.4.3Halve the history each time
Three things trip up a first bisect, so clear them before you start:
- Git refuses to begin with uncommitted changes, so save or stash your work first.
- A checkout from weeks ago may need its dependencies reinstalled before the app will even start, because
package.jsonchanged in between. - Some checkouts will not run at all, for reasons unrelated to your bug. That is what
git bisect skipis for.
Then you start it, mark each checkout good or bad, and git narrows the range every time until it stops on the culprit. You mark today's broken state with HEAD, git's name for the commit you are sitting on right now.
7.4.4Land on the bad change
Git prints the first bad commit: the exact change that introduced the break. Open its diff and the cause is a handful of lines you can actually read, not a needle in the whole codebase. When you are done, run git bisect reset to return to where you started.
If testing each step by hand is tedious, hand the whole hunt to your agent:
Do this now: on your next mystery bug, start a bisect with a known-good commit and today's HEAD, and let it walk you to the first bad commit.