[!NOTE] Stop guessing. Start bisecting.
You discovered a bug. It wasn’t there last week. Since then, 500 commits have been added. How do you find the one that broke the code?
You could check them one by one (Linear Search: O(N)). Or, you can use Git Bisect (Binary Search: O(log N)).
The Math: Why Bisect Wins
If you have 1,000 commits:
- Linear Search: You might have to check 1,000 commits.
- Binary Search: You check
log2(1000)≈ 10 commits.
Git Bisect works by picking the middle commit between a known “Good” state and a known “Bad” state. It halves the search space with every step.
The Bisect Simulator
Before running commands, let’s play a game. The bug was introduced in one of the commits below. You know the first commit is Good (Green) and the last commit is Bad (Red).
Find the bad commit in as few steps as possible.
Steps to Use git bisect
1. Start Bisect
Tell Git you want to start hunting.
git bisect start
2. Define Boundaries
You need to tell Git one “Bad” commit (usually HEAD) and one “Good” commit (a hash from last week, or a tag like v1.0).
# Current version is broken
git bisect bad
# v1.0 was working fine
git bisect good v1.0
3. Test and Repeat
Git will automatically checkout a commit in the middle. Now, run your tests or check your app.
- If it works:
git bisect good - If it’s broken:
git bisect bad
Git will repeat this process, narrowing down the range until only one commit is left.
4. The Culprit
Once found, Git will print:
a1b2c3d is the first bad commit
commit a1b2c3d...
Author: You <you@example.com>
Date: Mon Feb 14 12:00:00 2024
refactor: optimize login logic
5. Cleanup
Important! When you are done, you are in a Detached HEAD state. You must end the bisect session to go back to your branch.
git bisect reset
Automating Bisect
If you have a script that can verify the bug (e.g., npm test or a python script), you can let Git do the work for you.
Create a script verify.py:
import sys
import os
# Exit 0 if GOOD
# Exit 1 if BAD
# Example: Check if a specific file exists
if os.path.exists("buggy_file.txt"):
sys.exit(1) # Bad! Bug is present
else:
sys.exit(0) # Good
Run it automatically:
git bisect run python3 verify.py
Git will run the command on every step.
- If the command exits with
0: It marks it Good. - If the command exits with
1to127(except 125): It marks it Bad. - If the command exits with
125: It skips the commit (untestable).
You can literally go grab a coffee while Git hunts down the bug for you.