Finding Bugs with Git Bisect: A Practical Guide
Use git bisect to binary search through your commit history and pinpoint the exact commit that broke your code. Covers manual, automated, and advanced bisect workflows.
What you'll learn
- ✓How git bisect performs binary search on commits
- ✓Running manual bisect sessions step by step
- ✓Automating bisect with test scripts
- ✓Handling merge commits and skipping untestable commits
- ✓Real-world debugging strategies with bisect
Prerequisites
- •Basic Git commands (log, checkout, commit)
- •Ability to identify and reproduce a bug
Why Binary Search Your Commits
You shipped a release last Friday and everything worked. On Monday you pull the latest changes — 150 new commits — and the search feature is broken. Nobody knows which commit caused it. Testing each one manually would take hours.
git bisect applies binary search to your commit history. Instead of checking 150 commits, you check about 7 (log2 of 150). Each step cuts the remaining range in half until Git identifies the single commit that introduced the bug.
150 commits between good and bad
Step 1: check commit 75 -> bad (range: 1-75)
Step 2: check commit 37 -> good (range: 37-75)
Step 3: check commit 56 -> bad (range: 37-56)
Step 4: check commit 46 -> good (range: 46-56)
Step 5: check commit 51 -> bad (range: 46-51)
Step 6: check commit 48 -> good (range: 48-51)
Step 7: check commit 49 -> BAD <- first bad commit found! Manual Bisect: The Basic Workflow
Step 1: Start the session
git bisect start
Step 2: Mark the bad commit
Tell Git where the bug exists. Usually this is HEAD:
git bisect bad
Or specify a commit explicitly:
git bisect bad abc1234
Step 3: Mark a known good commit
Identify a commit where the bug did not exist. Use a tag, a date, or a commit hash:
# Using a tag
git bisect good v2.3.0
# Using a commit hash
git bisect good f7e8d9c
# Using a date-based reference
git bisect good main@{2026-06-30}
Git immediately checks out the midpoint commit:
Bisecting: 74 revisions left to test after this (roughly 7 steps)
[d4a5b6c] Refactor search indexer
Step 4: Test and mark
Test whether the bug exists at this commit. Then tell Git:
# If the bug is present at this commit
git bisect bad
# If the bug is NOT present at this commit
git bisect good
Git checks out the next midpoint and prints how many steps remain. Repeat until Git finds the first bad commit:
d4a5b6c7890 is the first bad commit
commit d4a5b6c7890
Author: Alice <alice@example.com>
Date: Sat Jul 5 14:30:00 2026 -0500
Add fuzzy matching to search results
src/search/indexer.js | 42 ++++++++++++++++++++----
1 file changed, 36 insertions(+), 6 deletions(-)
Step 5: Reset
Always reset when done to return to your original branch:
git bisect reset
Automated Bisect with Scripts
Manual bisect works, but automated bisect is far more powerful. Write a script that tests for the bug and let Git run the entire session unattended.
Exit code convention
Your test script must use these exit codes:
- 0 — the commit is good (bug not present)
- 1-124, 126, 127 — the commit is bad (bug present)
- 125 — the commit is untestable (skip it)
Example: Testing with your test suite
git bisect start HEAD v2.3.0
git bisect run npm test
This runs npm test at each midpoint. If the tests pass (exit 0), the commit is marked good. If they fail (exit non-zero), it is marked bad.
Example: Custom test script
Create a script that checks for the specific bug:
#!/bin/bash
# test-search-bug.sh
# Build the project (skip if build fails)
npm run build 2>/dev/null || exit 125
# Start the server in background
npm start &
SERVER_PID=$!
sleep 3
# Test the search endpoint
RESULT=$(curl -s http://localhost:3000/api/search?q=test | jq '.results | length')
# Clean up
kill $SERVER_PID 2>/dev/null
# Check the result
if [ "$RESULT" -gt 0 ]; then
exit 0 # Good: search returns results
else
exit 1 # Bad: search is broken
fi
Run it:
chmod +x test-search-bug.sh
git bisect start HEAD v2.3.0
git bisect run ./test-search-bug.sh
Git runs the script at each step, marks commits automatically, and reports the first bad commit.
Example: Using a single test file
If you know which test covers the bug:
git bisect start HEAD v2.3.0
git bisect run npx jest --testPathPattern="search.test.js"
Handling Tricky Situations
Untestable commits
Some commits might not compile or have broken dependencies. Use git bisect skip:
# During manual bisect
git bisect skip
# In automated scripts, exit with code 125
exit 125
Git will try adjacent commits instead. If too many consecutive commits are untestable, Git may not find the exact culprit but will narrow the range.
Merge commits
Bisect works on the linear commit history, so merge commits are included. If a merge commit itself is the culprit, bisect will find it. To investigate which side of the merge introduced the problem, run bisect again within that merge’s range:
# After bisect identifies merge commit abc1234
git log --oneline abc1234^1..abc1234^2 # Commits from the merged branch
git bisect start abc1234 abc1234^2 # Bisect within the merge
Bisect with path limiting
If you know the bug is in a specific directory, you can speed things up by testing only relevant changes:
git bisect start HEAD v2.3.0 -- src/search/
This limits bisect to commits that touched files in src/search/.
Viewing Bisect Progress
During a session, inspect the current state:
# See the bisect log
git bisect log
# Visualize the remaining range
git bisect visualize --oneline
The log is useful for reproducing a session or sharing it with your team:
# Save the log
git bisect log > bisect-session.log
# Replay a saved session
git bisect replay bisect-session.log
Real-World Debugging Strategy
Here is a practical workflow combining bisect with other debugging techniques:
1. Reproduce the bug and define a test
Before bisecting, make sure you can reliably reproduce the bug and determine pass/fail:
# Can you reproduce it?
npm start
curl http://localhost:3000/api/search?q=test
# Empty response -- bug confirmed
2. Find the known good point
# Check when the feature last worked
git log --oneline --since="2026-06-28" -- src/search/
# f7e8d9c 2026-06-29 Update search config
# a1b2c3d 2026-06-28 Release v2.3.0
# Verify v2.3.0 is actually good
git stash # if needed
git checkout v2.3.0
npm install && npm start
curl http://localhost:3000/api/search?q=test
# Results returned -- confirmed good
3. Run automated bisect
git bisect start HEAD v2.3.0
git bisect run ./test-search-bug.sh
4. Analyze the bad commit
# Bisect found commit d4a5b6c
git show d4a5b6c
git diff d4a5b6c^ d4a5b6c
5. Fix and verify
git bisect reset
git checkout -b fix/search-results
# Apply the fix
git commit -m "fix: restore search results after fuzzy matching change"
Tips for Effective Bisecting
-
Write deterministic tests. Flaky tests make bisect unreliable. If a test sometimes passes and sometimes fails, bisect will give wrong results.
-
Use exit code 125 generously. If a commit does not compile, does not have the feature you are testing, or has unrelated failures, skip it rather than marking it good or bad.
-
Start with a wide range. It is better to include too many commits than to accidentally exclude the bad one. Binary search handles large ranges efficiently.
-
Automate the build step. Your test script should handle building the project, not just running tests. Older commits may need different build steps.
-
Combine with git blame. After bisect finds the commit, use
git blameon the affected file to understand the change in full context:
git blame -L 45,65 src/search/indexer.js
- Log your sessions. Use
git bisect logto save and share your debugging process. It helps teammates understand how a bug was tracked down.
Wrap-Up
git bisect turns hours of debugging into minutes. The binary search algorithm guarantees you will find the offending commit in logarithmic time, and automated bisect with git bisect run makes the process entirely hands-off. The hardest part is writing a reliable test script — once you have that, bisect does the rest. Start using it the next time someone says “it worked last week” and nobody knows what changed.
Related articles
- Git Git Bisect: Find the Commit That Introduced a Bug
Learn how to use git bisect to perform binary search through your commit history and pinpoint the exact commit that introduced a bug in your codebase.
- Git Git Bisect Tutorial: Find the Bad Commit Fast
Use git bisect to binary-search through history and pinpoint the commit that introduced a regression, with manual and automated examples.
- Git Debugging with Git Bisect
Learn to use git bisect to find the exact commit that introduced a bug. Covers manual bisect, automated bisect with scripts, and practical strategies.
- Productivity Dotfiles Management: Sync Your Dev Setup Across Machines
Learn to manage dotfiles with GNU Stow, chezmoi, or a bare git repo. Bootstrap any new machine in minutes with your exact config.