git bisect — Binary Search for Bugs
1000 commits ho gaye, aur achanak test fail ho gaya. Kaunsa commit ne toda? Bisect se 10 steps mein pakdo!
A bug appeared in your code. You know it worked before, but now it is broken. Which commit introduced it?
The manual approach: check out each commit one by one, test, move to the next. For 100 commits, that is 100 tests. For 1000 commits, impossible.
git bisect uses BINARY SEARCH: cut the search space in half at each step.
1000 commits → 500 → 250 → 125 → 62 → 31 → 15 → 7 → 3 → 1. Found in approximately 10 steps!
The math: log2(1000) ≈ 10 steps. log2(1,000,000) ≈ 20 steps. Even a million commits → only 20 tests.
You only need to know TWO things: a commit where the bug EXISTS (bad), and a commit where the bug DID NOT exist (good).
Bisect is the most powerful debugging tool in Git that most developers have never used.
# The manual nightmare — checking every commit
git checkout HEAD~1 # test... still broken
git checkout HEAD~2 # test... still broken
git checkout HEAD~3 # test... still broken
# ... 47 more checkouts later ...
git checkout HEAD~50 # test... works! Bug is between 50 and 49
# Total time: hours. Energy: zero. Patience: gone.
# The git bisect way — binary search
git bisect start
git bisect bad # current commit is buggy
git bisect good v1.0.0 # this version worked
# Bisect checks out the middle commit
# You test it and say:
git bisect good # or git bisect bad
# Repeat ~10 times for 1000 commits
# Git finds the EXACT commit that introduced the bug
Bisect maintains a range: [known-good ... known-bad]
At each step, Git checks out the MIDDLE commit of that range.
You test that commit and tell Git: good (bug not present) or bad (bug present).
- If good: the bug was introduced AFTER this commit → search the upper half
- If bad: the bug was introduced AT or BEFORE this commit → search the lower half
Git repeats: middle → test → narrow range → middle → test → narrow range → found!
When the range narrows to one commit, Git announces: "X is the first bad commit"
Git shows you the diff of that commit — this is the change that introduced the bug.
You can then git show <hash> to see the full commit details.
# Example: 1000 commits, bug introduced at commit #623
git bisect start
git bisect bad HEAD # commit 1000 is bad
git bisect good HEAD~999 # commit 1 is good
# Step 1: Git checks out commit 500 (middle)
# You test: it works
git bisect good
# Range is now: commit 501 to 1000
# Step 2: Git checks out commit 750 (new middle)
# You test: it is broken
git bisect bad
# Range is now: commit 501 to 750
# Step 3: Git checks out commit 625 (new middle)
# You test: it is broken
git bisect bad
# Range is now: commit 501 to 625
# Step 4: Git checks out commit 563 (new middle)
# You test: it works
git bisect good
# Range is now: commit 564 to 625
# ... continues narrowing ...
# Step 10: Git finds it!
# abc1234 is the first bad commit
# abc1234 is commit #623 — the exact one that introduced the bug!Step 1: git bisect start — begin the bisect session
Step 2: git bisect bad — mark current HEAD as bad (bug exists here)
Step 3: git bisect good <hash-or-tag> — mark a known-working commit as good
Step 4: Git automatically checks out the middle commit
Step 5: You TEST the checked-out code (run the app, run tests, reproduce the bug)
Step 6: Report to Git: git bisect good (no bug) or git bisect bad (bug exists)
Step 7: Repeat steps 5-6 until Git says "X is the first bad commit"
Step 8: git bisect reset — EXIT bisect and return to your original branch
CRITICAL: Do not forget git bisect reset! Without it, you are stuck in a detached HEAD state.
git bisect reset when done to return to your branch.Scenario: Your React app crashes on page load. It worked fine 2 weeks ago.
Step 1: Find a known-good reference. A tag (v2.1.0) or a date-based ref (git log --before="2024-01-15" -1).
Step 2: Start bisect with the known bounds.
Step 3: At each step, run your app or test suite to check if the bug exists.
Step 4: Once bisect finds the culprit, examine that commit carefully.
Pro tip: if you can write a test that fails for the bug, use git bisect run (next chapter) to fully automate this.
After finding the commit: git show <hash> → read the message → understand the change → fix the bug.
# Real-world scenario: App crashes on login page
# Last known working version: v2.1.0 (2 weeks ago)
# Start bisect
git bisect start
# Current code is broken
git bisect bad HEAD
# v2.1.0 was working
git bisect good v2.1.0
# Bisecting: 87 revisions left to test after this
# [checkout middle commit]
# Test the app
npm start
# App crashes! Bug exists here
git bisect bad
# Bisecting: 43 revisions left to test after this
# Test again
npm start
# App works fine! No bug here
git bisect good
# Bisecting: 21 revisions left to test after this
# Continue testing...
# After several more iterations:
# a1b2c3d4 is the first bad commit
# commit a1b2c3d4
# Author: Ravi Kumar
# Date: Mon Jan 22 10:30:00 2024
#
# feat: add new auth middleware
# Found it! Ravi's auth middleware change introduced the bug
git show a1b2c3d4 # see the full diff
# Return to normal
git bisect resetUse tags or branch names instead of hashes for good/bad markers — easier to remember.
git bisect skip — if a commit cannot be tested (build broken, unrelated error), skip it. Git tries a nearby commit.
git bisect log — see the history of your bisect session (which commits you marked good/bad).
git bisect replay <logfile> — redo a bisect session from a log file (useful if you made a mistake).
git bisect visualize — see which commits are left to test in gitk or git log.
If you accidentally mark a commit wrong, you cannot undo it directly — use git bisect log > logfile, edit the file to remove the wrong entry, then git bisect reset and git bisect replay logfile.
Non-deterministic bugs (intermittent) are hard to bisect — the test must be reliable.
Lo kar liya — Key Points:
- ✅ git bisect uses binary search to find which commit introduced a bug — log2(N) steps instead of N
- ✅ You need a known-bad commit (bug exists) and a known-good commit (bug does not exist)
- ✅ At each step, Git checks out the middle commit — you test and report good or bad
- ✅ 1000 commits = ~10 steps, 1 million commits = ~20 steps — binary search is exponentially faster
- ✅ Always run git bisect reset when done to return to your original branch
- ✅ Use git bisect skip when a commit cannot be tested (broken build, unrelated error)
- ✅ Bisect works with any testable condition — crashes, failing tests, visual bugs, performance regressions
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login