Git Bisect: The Complete Guide for 2026
You just hit a regression: a test started failing, a page renders wrong, or a performance graph fell off a cliff. You know it used to work—but the codebase has hundreds of commits since the last known-good build.
git bisect solves this problem with a fast binary search through your history. You mark one revision as good and one revision as bad, and Git walks you through a sequence of checkouts until you find the exact commit that introduced the bug.
Table of Contents
1. What git bisect does
Bisect is a classic binary search:
- You provide one good commit (bug is not present).
- You provide one bad commit (bug is present).
- Git checks out a commit roughly halfway between them.
- You test it and mark it good or bad.
In about log2(N) steps, you narrow down from N commits to the single change that introduced the regression.
| If you have… | Bisect takes about… |
|---|---|
| 32 commits | 5 checks |
| 256 commits | 8 checks |
| 1024 commits | 10 checks |
2. Quick start (manual)
This is the core workflow. Replace <good> and <bad> with any commit, tag, or branch name.
# Start a bisect session
git bisect start
# Mark the current revision as bad (bug is present)
git bisect bad
# Mark a known-good revision
git bisect good <good>
Git checks out a candidate commit. Now you run your reproduction:
# Run your test / reproduction
./run-tests.sh
# If the bug is present:
git bisect bad
# If the bug is NOT present:
git bisect good
Repeat until Git prints the first bad commit:
xxxxxxx is the first bad commit
commit xxxxxxx
Author: ...
Date: ...
Add caching layer to widget loader
3. Automated bisect with git bisect run
If you can express “good vs bad” as an exit code, you can let Git drive the whole process. This is the fastest and least error-prone approach.
# Example: Node
git bisect start
git bisect bad HEAD
git bisect good v1.8.0
git bisect run npm test
git bisect run interprets exit codes like this:
0=> good1–127(except 125) => bad125=> skip (cannot test this commit)
4. Choosing good and bad refs
Good/bad can be anything that Git can resolve to a commit:
- A tag:
v2.3.1 - A branch tip:
main,release/2026-02 - A commit hash:
9fceb02 - A relative ref:
HEAD~50
Pick the closest known-good revision you trust. If your “good” commit is too old, you will waste time bisecting unrelated changes.
# Common pattern: bisect between a release tag and current main
git checkout main
git pull
git bisect start
git bisect bad HEAD
git bisect good v2.4.0
5. Skipping commits safely
Sometimes a commit cannot be tested:
- It doesn’t compile.
- It depends on a deleted external resource.
- Your test harness cannot run on that revision.
In those cases, tell Git to skip:
git bisect skip
If you already know a range is untestable (for example, “everything before the build system rewrite”), you can skip a set of commits:
# Skip a specific commit
git bisect skip 1a2b3c4
# Skip a range
git bisect skip 1a2b3c4..9fceb02
6. Handling flaky tests and non-determinism
Bisect assumes your “good vs bad” signal is consistent. If it’s not, you can converge on the wrong commit.
Strategies that work in real teams:
- Prefer a deterministic reproduction: create a unit test, a minimal fixture, or a local script.
- Run the test multiple times per commit: treat mixed results as
skip. - Disable background work: caches, network calls, time-based behavior, and random seeds.
#!/usr/bin/env bash
# bisect-test.sh - exit 0 good, 1 bad, 125 skip
set -euo pipefail
# Run up to 3 times to reduce flake
pass=0
fail=0
for i in 1 2 3; do
if ./run-tests.sh; then
pass=$((pass+1))
else
fail=$((fail+1))
fi
done
if [ "$pass" -gt 0 ] && [ "$fail" -gt 0 ]; then
exit 125
fi
if [ "$fail" -gt 0 ]; then
exit 1
fi
exit 0
Then:
git bisect run ./bisect-test.sh
7. Bisecting with merge commits
Bisect works best on a roughly linear history, but it can still be useful with merges. A few practical rules:
- If your merges are regular “merge main into feature”, your “first bad commit” might be a merge commit.
- If that happens, examine both parents: the bug is usually introduced on one side of the merge.
- For release branches, it often makes sense to bisect that branch (not main) to avoid unrelated changes.
8. Cleaning up (reset) and next steps
After Git identifies the first bad commit, you usually want to:
- Record the result (commit hash, commit message, and why it’s bad).
- End the session and return to your branch tip.
# End the bisect session and go back
git bisect reset
From there, common follow-ups include:
- Revert the commit (if it was already pushed): git revert vs reset
- Cherry-pick a fix onto a release branch: Git cherry-pick guide
- Open a PR with the minimal fix and a regression test
FAQ
Do I need a clean working tree to use git bisect?
It’s strongly recommended. Bisect checks out many revisions, so you should commit or stash changes first. If you must keep local changes, consider using a temporary worktree (see our Git worktrees guide).
Why does git bisect say “first bad commit” but the bug is elsewhere?
The most common causes are a flaky test, a non-deterministic reproduction (timing, network), or a “good” commit that wasn’t actually good. Tighten your reproduction and rerun the bisect.