Home/Engineer/Git / CI·CD/The Complete git bisect Guid…
Git / CI·CDIntermediateubuntumacoswindowsgitbisectdebugging

The Complete git bisect Guide — Find the Commit Where a Bug First Appeared with Binary Search

Pinpoint where a regression was introduced among hundreds of commits using binary search. Covers manual bisect, automating with git bisect run, exit-code rules, and custom test scripts.

Contents
  1. What is git bisect — Finding the Culprit Commit with Binary Search
  2. Manual bisect — Basic Flow
  3. Ending the Session — reset Is Required
  4. Automation — git bisect run
  5. Custom Test Scripts
  6. skip and Logs
  7. Custom Terms — Instead of good/bad
  8. Practical Tips

"A feature that worked yesterday is broken today. And there have been 200 commits in between." Instead of walking through commits one by one, git bisect uses binary search to quickly find the commit that first introduced the bug.

The idea is simple. Tell Git a "good" (working) commit and a "bad" (broken) commit, and Git checks out the midpoint between them. You test and answer good or bad, and Git moves to the midpoint of the remaining half. Even 1,000 commits take only about 10 steps (log₂1000 ≈ 10).

Knowing the exact commit that introduced a regression makes root-cause analysis dramatically easier. You pinpoint "the commit that changed this one line" instead of a 200-line merge commit.


Manual bisect — Basic Flow

Bash
# 1. Start the session
git bisect start

# 2. Mark the current commit as broken
git bisect bad

# 3. Mark a commit you know was healthy (tag, commit hash, or relative ref all work)
git bisect good v1.4.0

At this point Git automatically checks out the midpoint commit and tells you how many candidates remain.

CODE
Bisecting: 63 revisions left to test after this (roughly 6 steps)
[a1b2c3d...] Refactor payment handler

Now build and test this commit, then report the result.

Bash
# If the bug reproduces here
git bisect bad
# If this commit is healthy
git bisect good

Git narrows the range by half again and moves to the next commit. Repeat until it names the culprit.

CODE
b9f0e1a2c3... is the first bad commit
commit b9f0e1a2c3...
    Cache user session in memory

Ending the Session — reset Is Required

When the search is done (or if you need to abort), you must return to the original branch.

Bash
git bisect reset          # return to the original HEAD
git bisect reset <commit>   # end the session and return to a specific commit

During a search, git bisect hops between commits and leaves you in a detached HEAD state. If you skip reset, you'll keep working on some midpoint commit, so make it a habit to run git bisect reset when you're done.


Automation — git bisect run

This is the most powerful feature. Pass a command or script that decides good/bad, and Git runs the entire search unattended.

The verdict is determined by the exit code.

Exit codeMeaning
0good (working)
1~124, 126, 127bad (broken)
125skip (this commit cannot be tested)
128+abort the search
Bash
git bisect start
git bisect bad
git bisect good v1.4.0

# exit 0 (good) if the test passes, exit 1 (bad) if it fails
git bisect run npm test -- payment.spec.js

Git checks out each candidate, runs the command, prints the first bad commit, and stops. Grab a coffee and it'll be done when you get back.


Custom Test Scripts

If you need a build step or a custom check, write a script. Just follow the exit-code rules.

Bash
#!/usr/bin/env bash
# bisect-test.sh

# Skip commits that don't even compile
make build || exit 125

# Judge good/bad by whether a specific symptom reproduces
if ./run-app --check-feature; then
  exit 0    # good
else
  exit 1    # bad
fi
Bash
chmod +x bisect-test.sh
git bisect run ./bisect-test.sh

exit 125 (skip) means "this commit cannot be judged good or bad" (for example, it doesn't build), so Git skips to a nearby commit.


skip and Logs

You can skip commits by hand or save a log of the session.

Bash
git bisect skip              # current commit cannot be tested → skip it
git bisect skip <commit1> <commit2>

git bisect log > bisect.log  # save the good/bad record so far
git bisect replay bisect.log # replay that record as-is

You can also inspect the remaining search range with bisect visualize (or view) in gitk or the log.


Custom Terms — Instead of good/bad

When good/bad feels awkward — for example with a performance regression — you can rename the terms.

Bash
git bisect start --term-old=fast --term-new=slow
git bisect slow      # current commit is slow
git bisect fast v1.4.0
git bisect run ./perf-check.sh

Practical Tips

  • Automate the repro first. If you have a one-liner to pass to bisect run, the search is many times faster.
  • Pick a generous good point. Mark an older tag you know was healthy as good. If your "good" commit was already broken, the result will be wrong.
  • Isolate tests: If each commit needs a fresh install or cache, put that in the script (npm ci, etc.). Otherwise leftovers from a previous commit can give a false result.
  • Watch merge commits: If the first bad commit is a merge, you can bisect inside that branch to narrow it to a specific commit.

When you don't know when a bug landed, scanning the log by eye is a linear search. Automate the verdict with git bisect run and you can pinpoint the culprit among hundreds of commits in logarithmic time.

#git#bisect#debugging#regression
Editorial note

AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us

Topic-related official docs (auto-linked · not per-claim sources)Git documentation ↗

Questions & answers

Ask a question about this guide. We'll review and reply.