Skip to content
matthewcm.dev

    ↑ ↓ move · ↵ open · tab scopeopen graph →

    Git Bisect: Binary Search for the Commit That Broke It

    A regression with no obvious cause and hundreds of commits to search: git bisect halves the range each step, and with a test script it can find the culprit on its own.

    Growingtended planted 2 min read
    On this page

    My 2023 post on git bisect was short: when a bug appears and nobody knows when it was introduced, bisect checks out the commit halfway between a known good and a known bad state, you mark it good or bad, and it repeats until it finds the first bad commit. Divide and conquer. Even thousands of commits take only a handful of steps.

    That’s all still true. Here’s the fuller version I wish I’d written.

    Why it’s so fast

    It’s binary search. Each step halves the range, so 1,000 commits take about 10 steps and 10,000 take about 14. Finding when a bug arrived is often most of the work of understanding why, because the offending diff is usually small.

    The manual loop

    git bisect start
    git bisect bad                 # the current commit is broken
    git bisect good v2.3.0         # this tag was fine
    # git checks out a commit in the middle; test it, then:
    git bisect good                # or: git bisect bad
    # …repeat until git names the first bad commit
    git bisect reset               # back to where you started

    If a commit can’t be tested (it doesn’t build, say), git bisect skip moves on without guessing.

    The automated loop

    The real power is git bisect run. Give it a command that exits 0 for good and non-zero for bad, and it does the whole search on its own:

    git bisect start HEAD v2.3.0
    git bisect run npm test -- src/pricing.test.ts

    Write a small, focused test that reproduces the bug first. Then bisect finds the commit while you make a coffee, and the test becomes the regression test for the fix. That’s a neat combination with TDD as a Feedback Loop: reproduce, bisect, fix, keep the test.

    Things that make bisect work better

    • Small, focused commits. Bisect points at a commit; if that commit touches forty files, you’ve only narrowed the search a little. This is one more argument for small merge requests.
    • Every commit builds. If half your history doesn’t compile, bisect spends its time skipping. Squash-merging pull requests helps here.
    • Fast installs between steps. In a JavaScript project, dependencies change across history. A worktree per bisect session keeps your working copy clean while it hops around (Git Worktrees: A Desk per Branch).
    • Know what “bad” means. Flaky tests make bisect lie. Make the check deterministic before you trust the answer.

    When not to bother

    If you can read the code and reason about the bug in a few minutes, do that. Bisect is for the regression that arrived some time in the last few hundred commits with no obvious suspect, which is exactly when it saves hours.


    Originally written in 2023 → Git Bisect

    • #git
    • #debugging
    • #regressions
    • #binary-search
    • #automation

    Nothing links here yet — it’s a fresh shoot.

    ↪ Links to (2)