git bisect: Find the Commit That Broke Your App
Something worked last week and doesn't now. git bisect binary-searches your history to find the exact commit that introduced a bug in a handful of steps. Manual bisecting, automating it with git bisect run and a test script, skipping untestable commits, and using it with AI agents.
"It worked on Monday." Since then there are 120 commits, some yours, some a teammate's, some from an AI agent. Which one broke it?
git bisect finds out with a binary search: it checks out the commit halfway between "known good" and "known bad", you say whether it works, and it halves the range again. 120 commits takes about 7 steps; 1,000 takes about 10.
Manual bisect
git bisect start
git bisect bad # the current commit is broken
git bisect good v1.4.0 # this tag (or commit hash) worked
Git checks out a commit in the middle:
Bisecting: 60 revisions left to test after this (roughly 6 steps)
[a1b2c3d] Refactor invoice totals
Test it — run the app, run a test, reproduce the bug — then tell Git:
git bisect good # this one works
# or
git bisect bad # this one is broken
Repeat. Eventually:
e4f5a6b is the first bad commit
commit e4f5a6b
Round totals before applying discount
That's your culprit. Finish:
git bisect reset # back to where you started
Now git show e4f5a6b tells you exactly what changed. (How to read a diff)
Finding a "good" commit
If you don't know one, try a tag, a release, or something from last week:
git log --oneline --since="2 weeks ago" | tail -1
Automating it: git bisect run
If you can write a command that exits 0 when the code is good and non-zero when bad, Git can do the whole search unattended:
git bisect start HEAD v1.4.0
git bisect run npm test -- invoice.test.ts
Or with a small script:
#!/usr/bin/env bash
# check.sh
npm ci --silent || exit 125 # 125 = can't test this commit, skip it
npm run build --silent || exit 125
node scripts/check-invoice-total.js # exits 1 if the bug is present
git bisect run ./check.sh
Exit code 125 tells bisect "this commit can't be tested" (it doesn't build, say) — it skips it.
A great pattern: first write a test that reproduces the bug (it fails now), then bisect run with that test. You find the cause and end up with a regression test. (TDD with Claude Code)
Useful extras
git bisect skip # can't test this one manually
git bisect log # what you've marked so far
git bisect visualize # remaining commits (or: git bisect view --oneline)
git bisect terms --term-old=fast --term-new=slow # for things that aren't "bugs", e.g. a performance regression
Custom terms are handy for "when did this get slow?" — mark commits fast or slow.
Tips
- Clean working tree — commit or stash changes first. (git stash explained)
- Reinstall dependencies at each step if
package.jsonchanges in the range, or results lie. (node_modules explained) - Database migrations in the range can make old commits incompatible with your current database; test against a scratch database.
- Merge commits and huge commits make the answer less precise — another reason for small commits. (How to squash commits)
With an AI agent
git bisect run is ideal to hand to a coding agent: "Write a script that reproduces the invoice rounding bug, then use git bisect run between v1.4.0 and HEAD to find the commit that introduced it, then explain the change." It's mechanical, verifiable, and the result is a specific diff to reason about. (Using Git with Claude Code)
EasySpawn keeps your repository, dependencies and a scratch database on a persistent server, so Claude Code can run a full automated bisect while you get on with something else. See how it works or join the waitlist.
Related: How to Undo Almost Anything in Git · Debugging for Beginners · git reset vs git revert · Using Git With Claude Code
Keep reading
How to Test Webhooks Locally: Stripe CLI, Tunnels, and Replays
Webhook providers can't reach localhost, so local testing needs a forwarder or a tunnel. How to use provider CLIs like stripe listen, general tunnels like ngrok and Cloudflare Tunnel, request-capture tools, and fixture replays in automated tests — plus the signature-verification gotchas.
Playwright Tutorial: End-to-End Tests That Aren't Flaky
Playwright drives real browsers to test your app the way users use it. Install it, write your first test, use role-based locators and auto-waiting assertions, log in once and reuse the session, run against a dev server, debug with UI mode and traces, and run it in CI.