What Is Git Bisect? Finding a Bad Commit Fast
git bisect finds the exact commit that introduced a bug by binary-searching your commit history, cutting the search space in half each step.
git bisect is a built-in git command that finds the exact commit that introduced a bug by binary-searching your commit history. You tell it a known-good commit and a known-bad one, and it checks out commits in between, asking you (or a script) to mark each as good or bad, until it narrows the culprit down to a single commit.
The value is in the math: a linear search through history means checking commits one by one until you hit the bad one. A binary search cuts the remaining range in half on every step, so a bug hiding somewhere in a thousand commits takes about ten checks to find, not up to a thousand. See what Big O notation is for why halving the search space each time — O(log n) — beats checking one at a time.
Running a bisect session
Start a session, then mark the two ends of the range:
git bisect start
git bisect bad # HEAD is broken
git bisect good v1.4.0 # this tag was known to work
Git checks out a commit roughly halfway between the two and waits. You build and test that commit, then tell git what you found:
git bisect good # this commit works — bug is later
git bisect bad # this commit is broken — bug is earlier
Git checks out the new midpoint of whatever range remains and repeats. When only one commit is left, it reports that commit as the first bad one, along with its message, author, and diff. Run git bisect reset afterward to return to the branch and commit you started from — bisect leaves you in a detached-HEAD state while it’s active, similar to checking out a commit directly rather than a branch.
Automating it with a script
Manually testing each commit works, but it’s tedious for a bug that takes real setup to reproduce. If you can express “is this commit broken” as an exit code, git bisect run does the whole search unattended:
git bisect start
git bisect bad HEAD
git bisect good v1.4.0
git bisect run npm test -- --testPathPattern=checkout
Any command that exits 0 for good and non-zero for bad works — a test file, a build script, a shell one-liner that curls an endpoint and greps the response. Git runs it at each midpoint automatically and reports the first bad commit without further input. This is the form worth reaching for when a regression is easy to detect programmatically but tedious to check by hand: bisecting fifteen commits by eye is fine, bisecting a thousand is not.
Where it fits versus other debugging steps
Bisect doesn’t tell you why a commit broke something — it tells you which commit did, and once you have that, git log -p on the identified commit or git blame on the specific lines usually gets you the rest of the way. It pairs naturally with a git worktree: run the bisect in a second worktree so your main working directory, with whatever you were doing before the bug report came in, stays untouched. It’s also unrelated to git rebase — bisect only reads history, it never rewrites it, so it’s safe to run on a branch you don’t want to touch; see rebase vs merge if the distinction between reading and rewriting history isn’t clear.
Bisect vs a linear search
git bisect | Checking commits one by one | |
|---|---|---|
| Steps for n commits | ~log₂(n) | Up to n |
| Example: 1,000 commits | ~10 checks | Up to 1,000 checks |
| Requires | A reliable pass/fail test per commit | Same |
| Automatable | Yes, via git bisect run | Only with the same test, run manually |
The catch is the phrase “reliable pass/fail test.” Bisect assumes the bug is monotonic — that once it’s introduced, every later commit is also bad, with no good commits reappearing after it. Flaky tests, environment-dependent bugs, or a bug that was fixed and later reintroduced can confuse the search; git has a git bisect skip for commits that can’t be tested (say, a commit that doesn’t build), which excludes them from consideration without treating them as good or bad.
The takeaway
git bisect turns “find the commit that broke this” from a linear slog into a binary search, typically needing only a handful of checks even across a long history. Mark a known-good and known-bad commit, test each midpoint git hands you, and let it converge — or better, wrap the test in a script and hand it to git bisect run so the whole search happens unattended. It’s one of the highest-leverage git commands for the specific problem of “this used to work, now it doesn’t, and I don’t know when it changed.”
Tagged
Keep reading
The Lycoris Team · · 4 min read What Is Git Reflog? Recovering Lost Commits
Git reflog records every place HEAD and branch tips have pointed, letting you recover commits that look lost after a reset, rebase, or deleted branch.
The Lycoris Team · · 5 min read What Are Conventional Commits? A Commit Convention
Conventional Commits structures commit messages as type(scope): description so tools can auto-generate changelogs and version bumps from git history.
The Lycoris Team · · 4 min read Git Stash Explained: Shelve Changes Without Committing
Git stash saves uncommitted work to a hidden stack so you can switch branches cleanly. How stash, pop, apply, and stash branches actually work.