Skip to main content
Handbook/Debug/Page 59 · Bisecting

Finding What Broke It

Share

Share this page

Pass it to someone who needs it.

Star on GitHub

Key takeaway: Find the breaking change

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.

Each test halves the suspects until a single bad commit is left.

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.json changed in between.
  • Some checkouts will not run at all, for reasons unrelated to your bug. That is what git bisect skip is 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.

$ git bisect start $ git bisect bad HEAD $ git bisect good a1b2c3d Bisecting: 6 revisions left to test after this [e4f5a6b] feat: cache the user profile # test the app... bug is gone here $ git bisect good Bisecting: 3 revisions left to test after this [a0b1c2d] chore: bump the build tool # this one will not even start, so skip it $ git bisect skip Bisecting: 2 revisions left to test after this [b7c8d9e] refactor: reuse the fetch helper # test again... bug is back $ git bisect bad Bisecting: 1 revision left to test after this [c9d0e1f] fix: trim the search input # test... still broken $ git bisect bad c9d0e1f is the first bad commit

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:

Ready prompt
Act as a senior engineer running git bisect to find the change that broke a feature. Read the evidence I already captured on this bug first, so we do not re-derive it. Then walk me through it: - Confirm the bug is present now (bad), and pick a past commit where it worked (good). - Check I have no uncommitted work, then start the bisect, mark that commit good and HEAD bad, and tell me exactly what to test each step. - After I report good or bad, give the next command until we land on the first bad commit. If a checkout will not build or run at all, tell me to git bisect skip it instead of guessing. - If the check can be scripted, reuse a command I already run and put it under git bisect run. - End by showing the culprit's diff, then run git bisect reset. If it broke a rule my rules file does not yet state, give me that one line to add. If you need the full reasoning behind this step, read https://zalt.me/guides/vibe-coding/debug/bisecting What broke and when it last worked:

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.

Mahmoud Zalt

Mahmoud Zalt

Software engineer, 16+ yrs · built Sistava.com in 3 months, idea to production, using these methods

Resources
Star on GitHubContribute
Donate

Support my work

A small tip keeps the free work coming.

© 2026 Mahmoud Zalt. Free to read, not to republish.
Copyright & license