Git Bisect: Find the Commit That Broke Your App

September 20, 2026 · 1 views
Git Bisect: Find the Commit That Broke Your App

You pushed a release last week, and today a checkout test that passed for months is failing. There are 140 commits between the last good tag and main, and reading them one by one is not an option. This is exactly what git bisect is for: it performs a binary search through your commit history and finds the single commit that introduced a bug in about seven steps instead of 140.

This guide explains how git bisect works, walks through both the manual and the fully automated workflow, and covers the edge cases that trip people up in real projects.

What Is Git Bisect and Why Does It Work?

Git bisect takes two points in history, one where the code was good and one where it is bad, and repeatedly checks out the commit in the middle. You tell Git whether that commit is good or bad, and it discards half of the remaining range. Because each step halves the search space, the number of steps is roughly log2(n). A range of 128 commits needs 7 tests, 1,000 commits need 10, and 10,000 commits need only 14.

The result is the first bad commit, along with its author, message, and diff. That is usually enough to understand the bug in minutes rather than hours.

Git bisect only works well when two things are true. The bug must be reproducible with a deterministic check, and you must know at least one commit where the bug did not exist. If you have both, git bisect beats any amount of manual git log reading.

Manual Git Bisect Step by Step

Start a session by marking the current commit as bad and a known-good tag or commit hash as good:

git bisect start
git bisect bad                # current HEAD is broken
git bisect good v2.3.0        # this release worked

Git checks out a commit roughly halfway between the two and prints how many steps remain. Run your reproduction, whether that is a test, a manual click-through, or a curl request, and report the result:

git bisect good   # this commit works, bug is in a later commit
# or
git bisect bad    # this commit is broken, bug is in an earlier commit

Repeat until Git prints a line such as a1b2c3d is the first bad commit, followed by the commit details. You can also shorten the setup into one command with git bisect start HEAD v2.3.0.

When you are done, always return to your original branch:

git bisect reset

Forgetting git bisect reset is the most common mistake. Until you run it, you are sitting on a detached HEAD in the middle of your history, and any new commits you make there will be easy to lose.

Automating Git Bisect With git bisect run

Marking commits by hand gets tedious past four or five steps. The real power of git bisect is git bisect run, which executes a command at every step and uses its exit code to decide whether the commit is good or bad.

The rules for the exit code are simple:

  • Exit code 0 means the commit is good.
  • Exit codes 1 to 127, except 125, mean the commit is bad.
  • Exit code 125 means the commit cannot be tested, so Git skips it.
  • Exit codes above 127 abort the bisect entirely.

Here is a small script that runs a single failing test and skips commits that do not even build:

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

npm install --silent || exit 125      # cannot test, skip this commit
npm run build --silent || exit 125    # broken build is not our bug

npx jest tests/checkout.test.js       # exit 0 = good, non-zero = bad

Then let Git do all the work:

chmod +x bisect-test.sh
git bisect start HEAD v2.3.0
git bisect run ./bisect-test.sh

Git will check out commits, run the script, and print the first bad commit without any further input from you. Keep the script outside the working tree, for example in /tmp, because every checkout can overwrite tracked files, and an untracked script can otherwise disappear or change between steps.

Handling Untestable Commits With git bisect skip

Real histories contain commits that do not compile, half-finished migrations, or broken dependency versions. If you land on one of these, tell Git to skip it:

git bisect skip

Git will pick a nearby commit instead. If too many commits are skipped, Git may only be able to report a range of suspects rather than a single culprit. That is still a huge improvement over the full history, and you can inspect that shortlist manually.

Useful Git Bisect Options and Tricks

A few features make bisecting far more comfortable once you know they exist.

Custom terms instead of good and bad

"Good" and "bad" can be confusing when you are hunting for the commit that fixed something. Use custom terms to keep your head clear:

git bisect start --term-old=broken --term-new=fixed
git bisect broken v1.0
git bisect fixed HEAD

Save and replay a session

If you need to pause or share your progress with a teammate, export the log and replay it later:

git bisect log > bisect.log
git bisect reset
git bisect replay bisect.log

Visualize the remaining range

git bisect visualize opens gitk when a graphical display is available. In a plain terminal it falls back to git log, so git bisect visualize --oneline prints the remaining suspect commits. This is helpful when you want to sanity-check the range before trusting the result.

Bisect only merge commits

On repositories that use pull requests and merge commits, git bisect start --first-parent follows only the mainline history. You will find the merge that introduced the bug first, and you can then bisect inside that branch if needed.

Common Git Bisect Mistakes

  • Flaky tests. A test that fails randomly will send bisect down the wrong path. Run the check several times, or use a retry loop in your script, before declaring a commit bad.
  • Wrong good commit. If the "good" commit actually contains the bug, the result is meaningless. Verify it yourself before starting.
  • Testing the wrong thing. A test that fails for an unrelated reason, such as a missing environment variable, will mark every commit as bad. Make sure the failure matches the symptom you care about.
  • Uncommitted changes. Stash or commit your work before starting, since bisect checks out many different revisions.

Frequently Asked Questions

How many steps does git bisect need?

About log2 of the number of commits in the range. A range of 1,000 commits takes roughly 10 steps, which is why git bisect scales so well on large repositories.

Can I use git bisect without automated tests?

Yes. The manual workflow only needs you to reproduce the bug by hand and answer good or bad at each step. Automation with git bisect run simply removes the repetition.

What is the difference between git bisect and git blame?

git blame shows who last changed each line of a file, while git bisect finds the commit that introduced a specific behavior. Blame answers "who touched this line", and bisect answers "when did this stop working".

Does git bisect change my history?

No. It only checks out commits and records progress in temporary state. Running git bisect reset returns you to the branch you started on with your history unchanged.

Conclusion

Git bisect turns a vague "something broke sometime this month" into a precise answer with a single commit hash. Start with the manual workflow to learn the mechanics, then move to git bisect run with a small script that returns exit code 125 for untestable commits. The next time a regression appears, write a one-line failing test, run git bisect start HEAD <last-good-tag> followed by git bisect run, and let Git find the commit for you.

#debugging #git #git-bisect #version-control #regression-testing
Share this article:

0 Comments

No comments yet — be the first to share your thoughts.

Leave a comment

Never published.