Git

What Is Git Bisect? Debugging with Binary Search

What Is Git Bisect? Debugging with Binary Search

Something broke in your code, and you have no idea which commit caused it. You could scroll through dozens of diffs manually. Or you could let Git find it for you in under a minute.

That’s what git bisect does. It’s a built-in Git command that uses binary search to pinpoint the exact commit that introduced a bug into your project. Instead of checking commits one by one, it cuts the search space in half with each step.

This article covers how git bisect works, the full command syntax, how to automate it with test scripts, and where it fits compared to tools like git log and git blame. You’ll also see the common mistakes that trip developers up and how to avoid them.

What is Git Bisect

maxresdefault What Is Git Bisect? Debugging with Binary Search

Git bisect is a built-in Git command that uses binary search to find the exact commit that introduced a bug into your project. Instead of manually checking dozens or hundreds of commits, bisect splits the commit history in half repeatedly until the faulty commit is isolated.

The command ships with every standard Git installation. No plugins, no extensions. It works directly from the CLI.

You give it two reference points: a “bad” commit (where the bug exists) and a “good” commit (where things still worked). Git then checks out the midpoint between those two commits and asks you to test it.

Based on your answer, it eliminates half the remaining commits and repeats. The whole process runs in logarithmic time, which means testing roughly 7 commits out of 128, or about 10 out of 1,000.

Hutte research shows that approximately 15% of developers have used git bisect to identify the commit that introduced a bug. That number is low considering how effective the tool is, and it likely reflects that many developers don’t know it exists.

Debugging eats time. ACM Queue data indicates developers spend 35-50% of their time validating and debugging software, with the cost of debugging accounting for 50-75% of total project budgets. Git bisect directly attacks this problem by automating the search for where things broke.

The command isn’t limited to functional bugs either. You can use it to track down performance regressions, find the commit that accidentally fixed something, or locate when any observable behavior changed in your codebase.

Why is GitHub the heart of open source?

Uncover GitHub statistics: developer community growth, repository trends, collaboration patterns, and the platform that powers modern software development.

Explore GitHub Data →

How Git Bisect Works

maxresdefault What Is Git Bisect? Debugging with Binary Search

The binary search algorithm is what makes git bisect fast. It’s the same divide-and-conquer approach used in computer science for sorted data, but applied to your Git repository’s commit history.

Here’s the logic. You have a range of commits between “good” and “bad.” Git picks the one in the middle. You test it. If the bug exists there, the problem is in the first half. If it doesn’t, the problem is in the second half. Repeat.

Each step cuts the remaining suspects by 50%.

The time complexity is O(log n), where n is the number of commits in the range. For practical purposes:

Commits in RangeSteps to Find Bug
16~4
128~7
1,000~10
10,000~13

Compare that to checking every commit one by one. A linear search through 1,000 commits could take 1,000 tests. Bisect does it in 10.

Looking to sharpen your Git skills? Branching, merging, rebasing, and everything else you need - including git rebase, git stash, and commit workflows - is on one page in the Git Cheat Sheet.

Manual vs. Automatic Mode

Manual mode: Git checks out a commit, you build and test it yourself, then mark it as good or bad. This works fine when the test is something visual or hard to script, like a UI glitch you need to see with your own eyes.

Automatic mode: You pass a test script to git bisect run, and Git handles the entire loop without you. The script’s exit code tells Git whether the commit is good (exit 0) or bad (exit 1). Exit code 125 means “skip this commit, I can’t test it.”

Manual mode is simpler to start with. Automatic mode is where the real power is, especially for teams that already have unit testing in place.

Git Bisect Commands and Syntax

The full command set is smaller than most people expect. You can run an entire bisect session with just four or five subcommands.

Core commands:

  • git bisect start initializes the session
  • git bisect bad [commit] marks a commit as containing the bug
  • git bisect good [commit] marks a commit as bug-free
  • git bisect reset ends the session and returns to your original branch

You can also pass both boundaries at once: git bisect start HEAD v2.0 sets HEAD as bad and the v2.0 tag as good in a single line.

Additional subcommands:

  • git bisect skip tells Git to skip a commit that can’t be tested (won’t compile, missing dependency, etc.)
  • git bisect log prints a log of the current session’s decisions
  • git bisect replay [logfile] replays a saved session from a log file
  • git bisect visualize opens a graphical view of remaining suspect commits
  • git bisect run [script] automates the entire process with a test command

The official Git documentation also supports old and new as alternatives to good and bad. This is handy when you’re not looking for a bug, but tracking when a behavior changed. Using “good” and “bad” to describe a performance improvement, for example, gets confusing fast.

You can even define custom terms with --term-old and --term-new flags.

How to Use Git Bisect to Find a Bug

maxresdefault What Is Git Bisect? Debugging with Binary Search

Walk through a real scenario. Your app’s login page broke sometime in the last two weeks. You know the current HEAD is broken, and you know the v3.1 release worked fine.

Start the session:

git bisect start git bisect bad HEAD git bisect good v3.1 `

Git responds with something like: Bisecting: 45 revisions left to test after this (roughly 6 steps). It checks out a commit in the middle of that range.

Now you test. Build the project, open the login page, see if it works.

If the bug is there, run git bisect bad. If it's not, run git bisect good. Git immediately checks out the next midpoint.

Repeat this five or six more times. Eventually Git outputs the SHA of the first bad commit, along with the commit message and diff. That’s your culprit.

Clean up with git bisect reset. This puts you back on whatever branch you were on before the session started.

The whole process usually takes under ten minutes for a manual bisect. Took me forever to realize how much time I was wasting scrolling through git log output before I started using this.

Tip: Pick a “good” commit you’re confident about. A release tag or a known deployment SHA works well. If you pick a commit that already had the bug, bisect will give you a wrong answer and you’ll waste the whole session.

Automating Git Bisect with a Test Script

maxresdefault What Is Git Bisect? Debugging with Binary Search

The git bisect run subcommand is where bisect goes from useful to seriously powerful. You hand it a script, and Git runs the entire binary search without any manual input.

The rules are simple. Your script exits with:

  • 0 for a good commit (test passes)
  • 1-124, or 126-127 for a bad commit (test fails)
  • 125 to skip a commit that can’t be tested

Here’s a basic example using an existing test suite:

` git bisect start HEAD v3.1 git bisect run pytest tests/testlogin.py `

That’s it. Git checks out each midpoint commit, runs pytest against your login tests, reads the exit code, and keeps going until it finds the first bad commit.

For compiled projects, you might need a wrapper script. Something like:

` #!/bin/sh make || exit 125 ./runtests --suite=login `

The exit 125 on build failure tells bisect to skip that commit instead of marking it bad. This matters because older commits sometimes won't compile due to dependency changes or missing config. Without the skip, you'd get a false result.

Ingo Molnar, a Linux kernel developer, described running fully automated bisect sessions that build and boot kernels automatically, using serial logs and timeouts to determine pass/fail. If kernel hackers can automate it, most application developers definitely can.

Teams that practice test-driven development get the most out of git bisect run. If you already have tests that cover the broken behavior, the automation is almost free. Write a new test that exposes the regression, run bisect, go get coffee.

Andreas Ericsson, a Git developer, put it well on the Git mailing list. His team’s entire automated testing workflow revolves around git bisect run, and bugs shipped to customers are rare as a result.

When Git Bisect is Most Useful

Git bisect shines in specific situations. It’s not the right tool for every debugging problem, but when the conditions match, nothing else comes close.

Regressions That Aren’t Obvious from Code Review

Some bugs don’t show themselves in a diff. A one-line change in a utility function can break something three modules away. Git blame will tell you who changed a specific line, but it won’t tell you which change caused a specific behavior to break.

Bisect tests actual runtime behavior, not just code diffs. That’s the difference.

Large Commit Histories

RhodeCode data from 2025 shows 93.87% of developers now use Git as their primary version control system. Projects on platforms like GitHub routinely accumulate thousands of commits.

Manually inspecting each commit in a 500-commit range is not realistic. Bisect cuts that to about 9 steps.

Performance Regressions

Not just functional bugs. If your API response time jumped from 200ms to 800ms, bisect can find exactly when that happened. Write a script that curls the endpoint and checks the response time, pass it to git bisect run, and let it narrow things down.

The official Git docs confirm this use case explicitly, noting you can track any observable property change across commits.

When Bisect is Less Useful

There are real limitations.

  • If many commits in the range don’t compile, you’ll spend more time skipping than testing
  • Heavily squashed histories reduce the granularity of your search
  • If the bug depends on external state (a database migration, a third-party API change), bisect can’t isolate it from the commit alone

Projects with solid continuous integration and small, atomic commits get the best results. The Linux kernel team, where Linus Torvalds originally built Git, has used bisect extensively because their commit discipline supports it.

Git Bisect vs. Git Log and Git Blame

Three debugging tools, three different jobs. Developers often reach for git diff or log output first when something breaks. But these tools answer different questions, and picking the wrong one wastes time.

ToolWhat It DoesBest ForLimitation
git logShows commit history by file, author, or keywordTracking file evolution over timeDoesn’t test behavior
git blameShows who last changed each lineFinding who touched a specific lineOnly shows the most recent change
git bisectBinary search through commit historyIsolating the commit that broke somethingNeeds reproducible test

Key difference: git log and git blame look at code. Git bisect tests actual runtime behavior.

Atlassian’s documentation puts it clearly: blame shows the last author to modify a line, but tracking when a line was originally added requires a combination of flags and is often easier with git log’s -S option instead.

CloudBees research explains that blame is “too shallow” because it only reports a single change (the most recent one). If the bug’s origin spans multiple commits or files, blame can’t connect those dots.

Here’s when I actually use each one. Blame when I already know which file and which line is the problem. Log when I want to see the history of a specific function or file path. Bisect when something broke and I have no idea where to start looking.

They work well together. Use bisect to find the bad commit hash, then use blame to see exactly which lines changed, then use git show to read the full diff. That workflow handles most regression hunting scenarios.

Common Mistakes with Git Bisect

maxresdefault What Is Git Bisect? Debugging with Binary Search

Bisect is straightforward, but there are tricky spots that can ruin a session or give you a wrong answer. Most of these come from not understanding how the tool manages your working tree during the search.

Forgetting to Reset

This is the most common one. During a bisect session, Git puts you in a detached HEAD state. That’s expected. Git needs to check out arbitrary commits during the binary search without changing your branch pointer.

The problem happens when you forget to run git bisect reset after finding your answer. You're stuck on a random commit with no branch, and any work you do there can get lost.

Fix: Always end with git bisect reset. If you forgot and already switched around, git bisect reset still works and cleans up the bisect state.

Choosing the Wrong “Good” Commit

If you mark a commit as “good” that already contained the bug, bisect will search the wrong half of the history. It will still give you an answer, but it’ll be the wrong one.

Graphite’s debugging guide warns that this is particularly tricky because bisect won’t tell you the result is invalid. It trusts your markings.

Safeguard: Before starting, check out your “good” commit and actually test it. Spending two minutes verifying saves you from wasting a whole session.

Build Failures During Automated Runs

Older commits might not compile because of dependency changes, missing config files, or environment differences. If you’re using git bisect run and your script exits with code 1 on a build failure, bisect marks it as "bad" when it's really just untestable.

The Git docs specify exit code 125 for this exact situation. Your test script should exit 125 when a commit can’t be built, so bisect skips it instead of misclassifying it.

Merge Commits and Non-Linear History

Bisect handles merge commits, but they add complexity. The bug might only appear when two branches are combined. Bisect could point to the merge commit as the first bad commit, which is technically correct but not very useful for defect tracking.

The –first-parent flag helps here. It tells bisect to follow only the main branch's history, skipping commits from merged feature branches.

Dirty Working Directory

Uncommitted changes in your working tree can conflict with bisect’s checkouts. Git will refuse to switch commits if there are conflicts with your local changes.

Solution: Stash your changes before starting a bisect session. Run git stash, do the bisect, then git stash pop when you're done.

Git Bisect in GUI Tools and IDEs

Not every developer lives in the terminal. GUI tools can make bisect more visual, but support varies a lot across different clients.

JetBrains IDEs

IntelliJ IDEA, WebStorm, and the other JetBrains products don’t include native bisect support in their built-in Git client. But a third-party plugin called “Git Bisect Run” brings the git bisect run workflow directly into the IDE.

DZone’s review of JetBrains Git plugins notes the tool automates the entire process. It runs your tests at each commit and shows a popup notification when it finds the bad commit. Language-agnostic, so it works across all JetBrains IDEs.

VS Code

VS Code doesn’t have built-in bisect support either. You run bisect through the integrated terminal. Microsoft did create a vscode-bisect tool, but that's specifically for bisecting VS Code's own insider builds, not a general-purpose bisect GUI.

The practical approach: open VS Code’s terminal, run your bisect commands there, and use VS Code’s code review features to inspect each commit as bisect checks it out.

GitKraken and Sourcetree

GitKraken currently does not support git bisect natively. It’s been a requested feature on their feedback board since 2021, with ongoing community upvotes. For now, you’d need to drop into a terminal.

Sourcetree (by Atlassian) also lacks a dedicated bisect interface. You can view commit history and diffs visually, which helps during manual bisect, but the actual bisect commands still run in the terminal.

ToolNative BisectWorkaround
JetBrains IDEsPlugin available“Git Bisect Run” plugin
VS CodeNoIntegrated terminal
GitKrakenNoExternal terminal
SourcetreeNoExternal terminal

The reality is that bisect remains primarily a CLI tool. And that’s fine. The command set is small enough that you don’t need a GUI for it. Most developers I’ve talked to who use bisect regularly just run it from the terminal anyway, even if they use a GUI for everything else.

If your team follows a structured Git workflow with clean, atomic commits, bisect sessions are quick regardless of whether you’re using a graphical client or the command line.

For teams running DevOps pipelines, integrating bisect into your build pipeline through scripts is often more practical than any GUI could be. Write the test, wire it into git bisect run, and let the CI server find the regression overnight.

FAQ on What Is Git Bisect

What does git bisect do?

Git bisect uses a binary search algorithm to find the specific commit that introduced a bug. You mark a good and bad commit, and Git checks out midpoints until the faulty commit is isolated.

How do I start a git bisect session?

Run git bisect start, then mark boundaries with git bisect bad HEAD and git bisect good [commit]. Git immediately checks out a commit halfway between those two points for you to test.

What is git bisect run?

The git bisect run subcommand automates the search by running a test script at each step. The script's exit code tells Git whether a commit is good (0), bad (1-124), or untestable (125).

How do I stop a git bisect session?

Run git bisect reset. This ends the session and returns your working tree to the branch you were on before bisecting. Forgetting this step leaves you in a detached HEAD state.

Can git bisect find performance regressions?

Yes. Git bisect can track any observable behavior change across commits, not just functional bugs. Write a script that measures response time or memory usage, then pass it to git bisect run.

What is the difference between git bisect and git blame?

Git blame shows who last modified a specific line of code. Git bisect tests runtime behavior across commits to find when something broke. Blame identifies authors. Bisect identifies the breaking change.

How many steps does git bisect take?

Git bisect runs in O(log n) time. For 1,000 commits, that’s roughly 10 steps. For 10,000 commits, about 13. Each step eliminates half the remaining suspect commits.

What does exit code 125 mean in git bisect?

Exit code 125 tells git bisect to skip the current commit because it can’t be tested. This is common when older commits won’t compile due to missing dependencies or changed build configurations.

Does git bisect work with merge commits?

It does, but merge commits can complicate results. The –first-parent flag restricts the search to the main branch history, which avoids false positives from broken commits in merged feature branches.

Can I use git bisect in a GUI tool?

Most GUI clients like GitKraken and Sourcetree lack native bisect support. JetBrains IDEs offer it through a plugin. In practice, bisect’s small command set makes the terminal the fastest option.

Conclusion

Git bisect turns regression hunting from guesswork into a structured, repeatable process. For any developer working inside a large source control environment, it’s one of the most practical debugging commands available.

The binary search approach means you’re testing 10 commits instead of 1,000. Pair it with git bisect run` and an existing test suite, and the whole thing runs hands-free.

Clean commit history matters here. Small, atomic commits make bisect sessions faster and results more accurate. Teams that follow solid development best practices get the most out of it.

Whether you’re tracking down a broken API endpoint, a UI glitch, or a performance drop across your software system, bisect gets you to the root cause without the manual grind. Learn the five core commands, and you’ll wonder how you debugged without it.

50218a090dd169a5399b03ee399b27df17d94bb940d98ae3f8daff6c978743c5?s=250&d=mm&r=g What Is Git Bisect? Debugging with Binary Search

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.