Finding bugs with git bisect

Git · Advanced · 12 min

It finds the culprit among thousands of commits in a dozen steps, often fully automatically.

When something worked in v2.3.0 and is broken now, the bug was introduced by one commit in between. `git bisect` binary-searches that range: it checks out the midpoint, you say whether it's good or bad, and it halves the range each time. 1,000 commits take about 10 steps.

The manual flow:

git bisect start
git bisect bad              # current commit is broken
git bisect good v2.3.0      # this one was fine

Git checks out a commit in the middle. Test it, then answer git bisect good or git bisect bad. Repeat until Git prints "<hash> is the first bad commit". git bisect reset returns you to where you started.

If a commit can't be tested (it doesn't build, for example), git bisect skip picks a nearby one instead.

The real power is `git bisect run <script>`: Git runs the script at each step and reads its exit code. 0 means good, 125 means skip, any other code from 1 to 127 means bad. A failing test case makes a perfect script, and the whole hunt runs unattended.

Bisect works best when every commit builds and passes tests on its own, one more reason for small, self-contained commits. For merge-heavy histories, git bisect start --first-parent follows only the mainline, so it identifies which merged PR caused the issue.

The terms don't have to be good and bad: git bisect start --term-old=slow --term-new=fast finds when something improved.

Example

cat > /tmp/check.sh <<'END'
#!/bin/sh
make -s build || exit 125          # can't build: skip this commit
./bin/app --selftest-date-parsing  # exits non-zero when the bug is present
END
chmod +x /tmp/check.sh

git bisect start HEAD v2.3.0       # bad, then good
git bisect run /tmp/check.sh
# 7e1f3c2 is the first bad commit
# Author: ... Date: ...  "Switch date parser to strptime"
git bisect log > bisect.txt        # keep a record
git bisect reset

Remember

  • Bisect halves the suspect range each step: ~log2(n) tests
  • git bisect run automates it: exit 0 good, 125 skip, 1-127 bad
  • Always finish with git bisect reset

Watch out for

  • Writing a run script that exits non-zero for unrelated reasons (like a build failure), so bisect blames the wrong commit — exit 125 to skip.

Check yourself

  1. In git bisect run, what should the script exit with when a commit can't be tested?
  2. About how many test steps does bisect need for 1,000 candidate commits?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: git-scm.com/docs/git-bisect

Builds on

Unlocks

Nothing builds on this yet.