Git Bisect: The Complete Guide for 2026

Published February 15, 2026 · 18 min read

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.

⚙ Related: Keep a reference open with the Git Commands Cheat Sheet. If you want to inspect changes quickly, try the Git Diff Viewer. For undo workflows after a bad change, see Git Undo: Reset vs Revert.

Table of Contents

  1. What git bisect does
  2. Quick start (manual)
  3. Automated bisect with git bisect run
  4. Choosing good and bad refs
  5. Skipping commits safely
  6. Handling flaky tests and non-determinism
  7. Bisecting with merge commits
  8. Cleaning up (reset) and next steps
  9. FAQ

1. What git bisect does

Bisect is a classic binary search:

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 commits5 checks
256 commits8 checks
1024 commits10 checks
Tip: Before you bisect, create a deterministic reproduction (a unit test, a small script, or a command that exits 0/1). The more reliable your signal, the faster bisect will converge.

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:

Watch out: Make sure your test command has a clear, stable exit code. If your test runner sometimes exits non-zero for infrastructure reasons (timeouts, missing deps, network), wrap it in a script that decides “skip” vs “bad”.

4. Choosing good and bad refs

Good/bad can be anything that Git can resolve to a commit:

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:

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:

#!/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:

Tip: If you often need to bisect, keep your main branch linear (rebase + fast-forward merges) or use squash merges for small PRs. It makes regressions easier to isolate.

8. Cleaning up (reset) and next steps

After Git identifies the first bad commit, you usually want to:

  1. Record the result (commit hash, commit message, and why it’s bad).
  2. 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:

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.

Related Resources

Git Undo (Reset vs Revert)
Safely undo changes locally or on shared branches
Git Log Complete Guide
Pretty graphs, filters, ranges, and searching history
Git Rebase Complete Guide
Rewrite history cleanly with interactive rebase
Git Merge Conflicts Guide
Resolve conflicts confidently with proven workflows
Git Worktrees Guide
Work on multiple branches without constant checkouts
Git Cherry-Pick Guide
Apply a fix commit onto release branches
Git Commands Cheat Sheet
Quick reference for daily Git workflows