6.1 KiB
Module 14: Bisect - Finding Bugs with Binary Search
Learning Objectives
By the end of this module, you will:
- Understand what git bisect is and when to use it
- Use binary search to find the commit that introduced a bug
- Mark commits as good or bad during bisection
- Automate bisect with test scripts
- Understand the efficiency of binary search for debugging
Challenge Description
A bug has appeared in your calculator application, but you don't know which commit introduced it. The project has many commits, and manually checking each one would take too long. You'll use git bisect to efficiently find the culprit commit using binary search.
Your task is to:
- Start a bisect session
- Mark the current commit as bad (bug exists)
- Mark an old commit as good (bug didn't exist)
- Test commits and mark them good or bad
- Let Git find the first bad commit
- Identify what change introduced the bug
Key Concepts
What is Git Bisect?
Git bisect uses binary search to find the commit that introduced a bug. Instead of checking every commit linearly, it cuts the search space in half with each test, making it extremely efficient.
Binary Search Efficiency
Linear Search (manual checking):
- 100 commits = up to 100 tests
- 1000 commits = up to 1000 tests
Binary Search (bisect):
- 100 commits = ~7 tests
- 1000 commits = ~10 tests
Formula: log₂(n) tests needed for n commits
How Bisect Works
Commits: A---B---C---D---E---F---G---H
✓ ✓ ✓ ? ? ? ? ✗
1. Start: Mark H (bad) and A (good)
2. Git checks middle: E
3. You test E: bad ✗
Commits: A---B---C---D---E
✓ ✓ ✓ ? ✗
4. Git checks middle: C
5. You test C: good ✓
Commits: C---D---E
✓ ? ✗
6. Git checks: D
7. You test D: bad ✗
Result: D is the first bad commit!
When to Use Bisect
Use bisect when:
- You know a bug exists now but didn't exist in the past
- You have many commits to check
- You can reliably test for the bug
- You want to find exactly when something broke
Useful Commands
# Start bisect session
git bisect start
# Mark current commit as bad
git bisect bad
# Mark a commit as good
git bisect good <commit-hash>
git bisect good HEAD~10
# After testing current commit
git bisect good # This commit is fine
git bisect bad # This commit has the bug
# Skip a commit (if you can't test it)
git bisect skip
# End bisect session and return to original state
git bisect reset
# Visualize bisect process
git bisect visualize
git bisect view
# Automate with a test script
git bisect run <test-script>
git bisect run npm test
git bisect run ./test.sh
# Show bisect log
git bisect log
Verification
Run the verification script to check your solution:
.\verify.ps1
The verification will check that:
- You completed a bisect session
- You identified the correct commit that introduced the bug
- You understand which change caused the problem
Challenge Steps
- Navigate to the challenge directory
- View the bug: run the calculator and see it fails
- Start bisect:
git bisect start - Mark current as bad:
git bisect bad - Mark old commit as good:
git bisect good HEAD~10 - Git will checkout a middle commit
- Test the current commit (run the test or check manually)
- Mark it:
git bisect goodorgit bisect bad - Repeat testing until Git identifies the bad commit
- Note the commit hash and message
- End bisect:
git bisect reset - Check the identified commit:
git show <bad-commit-hash> - Create a file named
bug-commit.txtwith the bad commit hash - Run verification
Tips
- Always start with a known good commit (far enough back)
- Keep a clear way to test each commit (script or manual steps)
- Use
git bisect logto see your progress git bisect resetreturns you to your original state- You can bisect on any criteria, not just bugs (performance, features, etc.)
- Automate with
git bisect runfor faster results - Each bisect step cuts remaining commits in half
- Skip commits you can't build/test with
git bisect skip
Manual vs Automated Bisect
Manual Bisect
git bisect start
git bisect bad
git bisect good HEAD~20
# For each commit Git checks out:
npm test
git bisect good # or bad
git bisect reset
Automated Bisect
git bisect start
git bisect bad
git bisect good HEAD~20
git bisect run npm test
# Git automatically tests each commit
git bisect reset
The test script should exit with:
- 0 for good (test passes)
- 1-127 (except 125) for bad (test fails)
- 125 for skip (can't test this commit)
Bisect Workflow Example
Finding a Performance Regression
# App is slow now, was fast 50 commits ago
git bisect start
git bisect bad
git bisect good HEAD~50
# Create test script
echo '#!/bin/bash\ntime npm start | grep "Started in"' > test.sh
chmod +x test.sh
git bisect run ./test.sh
# Git finds the commit that made it slow
Finding When a Feature Broke
git bisect start
git bisect bad
git bisect good v1.0.0 # Last known good version
# For each commit
npm test -- user-login.test.js
git bisect good # or bad
# Found! Commit abc123 broke login
git show abc123
Common Bisect Pitfalls
Pitfall 1: Testing Incorrectly
- Make sure your test is consistent
- Automate when possible to avoid human error
- Use the same test for every commit
Pitfall 2: Wrong Good Commit
- If the "good" commit actually has the bug, bisect will fail
- Choose a commit you're confident was working
Pitfall 3: Multiple Bugs
- Bisect finds one commit at a time
- If multiple bugs exist, they might confuse the search
- Fix found bugs and bisect again for others
What You'll Learn
Git bisect is a powerful debugging tool that turns a tedious manual search into an efficient automated process. By leveraging binary search, you can quickly pinpoint problematic commits even in repositories with thousands of commits. This is invaluable for debugging regressions, performance issues, or any situation where something that worked before is now broken. Mastering bisect makes you a more effective debugger and shows deep Git proficiency.