A bug report says: "it worked last week." Somewhere between then and now, a commit broke it — and there are two hundred commits in between. git bisect finds the culprit with binary search: you mark one known-good and one known-bad commit, and git walks you through ~8 testable steps to the guilty one.

The basic session #

Bisecting by hand
$ git bisect start
$ git bisect bad                     # current state is broken
$ git bisect good v1.4.0             # this tag was fine
Bisecting: 100 revisions left to test after this (roughly 7 steps)
$ # test the checked-out commit...
$ git bisect bad                     # still broken
$ git bisect good                    # this one works
...
f3e2d1c is the first bad commit
$ git bisect reset                   # return to where you were

Log₂(200) ≈ 8 — eight decisions instead of two hundred builds. Git narrows the range each time you classify the commit it checks out, and the final report names the first bad commit with its full log context.

Automating the test #

When a script can judge the commit, bisect runs itself:

The machine takes the wheel
$ git bisect start HEAD v1.4.0
$ git bisect run ./test-regression.sh
running '...' ...
f3e2d1c is the first bad commit

bisect run executes the command at each step; exit 0 means good, non-zero means bad. The test script can be anything — a build plus assertion, a curl against a deployed build, a one-off shell script:

test-regression.sh — the judge
#!/usr/bin/env bash
set -e
npm ci --silent
npm run build --silent
grep -q 'max-age=31536000' dist/_headers

The flags that matter #

NeedFlag
Skip a commit that will not buildgit bisect skip
Test a range of commitsgit bisect start HEAD v1.4.0 -- path/ (narrow by path)
View current status/termsgit bisect log
Reuse/save the sessiongit bisect log > bisect.log
End the sessiongit bisect reset

-- path/ narrows the search to commits touching a directory — when the symptom is clearly in one area, the range halves before you start.

After the verdict #

The report names the first bad commit — then the real work starts: read that commit's diff, decide whether to revert it or fix forward, and note in the fix commit that bisect found it. The bisect session itself ends with reset — forgetting it leaves you on a detached HEAD in the middle of history.

The recovery tools around it are reflog and pickaxe log search; the Git series continues.