When to use
Use when the user can answer "is this commit good or bad?" with a
deterministic check — a failing test, a CLI exit code, a database
state assertion. The bisect algorithm does a binary search over the
linear commit history and converges in O(log n) steps; for 1,024
commits it needs at most 10 judgements.
The discipline:
- Confirm the bug is reproducible on
HEADand absent on a known good commit (a release tag, the previous release branch tip, a commit the bug reporter remembers working). - Write the deterministic check before starting the bisect. The check must run in seconds; if it takes minutes, the bisect will take hours.
git bisect start, mark the bad commit (bisect bad) and the good commit (bisect good <sha>).- For each bisect step, run the check, then mark
bisect goodorbisect bad. Git picks the next commit to test. - When git prints "
<sha>is the first bad commit", verify by checking out that commit and running the check yourself. git bisect resetto return toHEAD.
Examples
A scripted bisect for a Rust regression using cargo test:
git bisect start
git bisect bad HEAD
git bisect good v1.4.0
# Run a single failing test; exit 0 = bad, exit 1 = good.
git bisect run sh -c 'cargo test --test regression -- --exact bug_1234 || exit 1 && exit 0'
When cargo test exits non-zero (the test failed — the bug is
present), the run script exits 1 and git records the commit as
bad. When the test passes (the bug is absent), the script exits
0 and git records the commit as good.
For example, a manual bisect with a small history:
$ git bisect start
$ git bisect bad HEAD
$ git bisect good abc1234
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[def5678] refactor: extract OrderValidator
$ cargo test parser # passes
$ git bisect good
Bisecting: 2 revisions left to test after this (roughly 1 step)
[hij9012] feat(orders): add loyalty discount
$ cargo test parser # fails
$ git bisect bad
[hij9012] feat(orders): add loyalty discount is the first bad commit
Pitfalls to avoid
- Do not skip writing the deterministic check; "look at the output and decide" is biased and inconsistent. The check must be a single command whose exit code encodes the answer.
- Do not run
git bisect runwith anything that depends on the working tree from a previous step; bisect checks out commits automatically and any untracked artefacts from earlier steps will leak in. - Do not use
git bisect skipto escape a hard-to-test commit unless the bug genuinely cannot be reproduced at that revision; over-usingskipdefeats the binary search. - Do not forget to
git bisect resetafter you finish; the bisect state marksrefs/bisect/*and a forgotten reset leaves the repository in a confusing state. - Do not trust the first bad commit blindly; verify it by checking out the parent and running the same check. Bisect is statistical in the face of flaky checks, not a proof.