Skip to main content

git bisect β€” Finding the Broken Commit

Git Bisect Binary Search Bug Detector (`git bisect`)
1
git bisect start
Initializes binary search state. Mark current bad commit (git bisect bad) and last known good commit (git bisect good v1.0.0).
2
Git checks out midpoint commit (O(log N))
Git automatically checks out the middle commit between good and bad bounds.
3
Test & Mark (git bisect good / bad)
Run tests. If passes β†’ git bisect good. If fails β†’ git bisect bad. Search range is halved.
4
Culprit commit identified!
Git pinpointed exact bad commit SHA-1: a9f8e7d. Run git bisect reset to return to original HEAD.

What It Does

git bisect performs a binary search through commit history to efficiently find the exact commit that introduced a bug. Instead of checking commits one by one (which could take hours on a large repo), bisect narrows the search logarithmically β€” finding the culprit in logβ‚‚(N) steps.

For 1000 commits, bisect finds the bad commit in at most 10 steps.


Basic Manual Bisect

Step 1 β€” Start bisect and mark the boundaries

git bisect start

# Mark the current state as "bad" (the bug is present here)
git bisect bad HEAD

# Mark a known good commit (the bug was not present here)
git bisect good v1.1.0
# or by SHA:
git bisect good a3f9bc2

Git checks out the commit at the midpoint of the range.

Step 2 β€” Test and mark each commit

After each checkout, test whether the bug is present:

# If the bug IS present at this commit:
git bisect bad

# If the bug is NOT present at this commit:
git bisect good

Git narrows the range with each answer and checks out the next midpoint.

Step 3 β€” Git identifies the culprit

After enough answers, Git outputs:

b7e2a1f is the first bad commit
commit b7e2a1f
Author: Bob Johnson <[email protected]>
Date: Mon Jan 15 14:22:10 2024

refactor(transactions): extract date range logic to utility class

src/main/java/com/example/util/DateRangeUtils.java | 42 +++++
1 file changed, 42 insertions(+)

Step 4 β€” End bisect and return to your branch

git bisect reset
# HEAD is now back on your original branch

Automated Bisect with a Script

The real power of bisect is automation. Provide a script that returns exit code 0 for "good" and non-zero for "bad" β€” Git will run the entire search unattended.

Example: bisect using a Maven test

git bisect start
git bisect bad HEAD
git bisect good v1.1.0

# Run a specific test β€” pass/fail determines good/bad automatically
git bisect run ./mvnw -q test \
-Dtest="TransactionServiceTest#findTransactions_dateRangeFilter_returnsCorrectResults"

Git runs your test at each midpoint commit, automatically marking good/bad based on the exit code, and delivers the result without any manual input.

Example: bisect using a shell script

#!/bin/bash
# scripts/bisect-check.sh

# Build silently
./mvnw -q package -DskipTests 2>/dev/null || exit 125
# Exit 125 = "skip this commit" (e.g., build is broken β€” not the bug we're hunting)

# Run the specific test
./mvnw -q test -Dtest="TransactionServiceTest#findTransactions_emptyResult"
git bisect run bash scripts/bisect-check.sh
Exit Code 125

If a commit can't be tested (e.g., compile error unrelated to the bug), exit with 125. Git will skip that commit and move to the next one.


Bisect with Terms (Custom Good/Bad Labels)

For regressions that are not clearly "good/bad" (e.g., performance changes):

git bisect start --term-old fast --term-new slow
git bisect slow HEAD # current is slow
git bisect fast v1.1.0 # v1.1.0 was fast
# Git now prompts "is this commit fast or slow?"
git bisect fast # this commit is fast
git bisect slow # this commit is slow

Bisect Log and Replay

Save the bisect session to replay later:

git bisect log > bisect-session.log

# Replay a saved session
git bisect reset
git bisect replay bisect-session.log

Tips for Effective Bisect

TipDetail
Write a reproducible test firstAutomate with bisect run for speed and accuracy
Use tags as boundariesgit bisect good v1.0.0 β€” release tags are reliable known-good points
Skip broken buildsExit 125 from your script to skip non-compilable commits
Check reflog aftergit reflog shows all commits visited during bisect
Once found, git showgit show <bad-commit> shows the exact diff that introduced the bug

Bisect Saves Hours

On a repo with 500 commits between the last known-good release and HEAD, manually checking each commit would take all day. git bisect run with an automated test finds the exact culprit in under 10 steps β€” usually in a few minutes. Write the test first.

Interview Questions

  1. How do you prepare deterministic bisect scripts for flaky test environments?
  2. When should commits be skipped with exit code 125, and why?
  3. How do you bisect effectively across refactors and intermittent build failures?
  4. What post-bisect steps ensure the root cause is fully validated?

Short answer guide:

  • Use stable repro tests and isolate nondeterministic dependencies.
  • Skip only untestable commits to preserve binary-search integrity.
  • Combine manual checkpoints with automated bisect runs.
  • Confirm fix with forward/backward validation and regression tests.
Interview Focus

Show how git bisect run shortens mean-time-to-root-cause during regressions.

Interview Trap

Starting bisect without a deterministic reproduction or clear good/bad boundary.

πŸ“–
Track Page Progress0 / 635 Read
Knowledge Base Completion0%