Git Bisect: Finding the Bug with Binary Search

Summary: Use git bisect to find which commit introduced a bug.


Debugging code can often feel like searching for a needle in a haystack. When a bug sneaks into a project, tracking down the commit that introduced it can be time-consuming, especially in a repository with a long history. Luckily, git bisect provides a systematic way to pinpoint the problematic commit efficiently, using the principles of binary search. In this post, we’ll dive into how git bisect works and walk through how you can use it to squash bugs effectively.


What is Git Bisect?

git bisect is a powerful Git command that helps identify the commit that introduced a bug or regression by performing a binary search between a known good commit and a bad one. Instead of checking every commit sequentially, git bisect narrows the search space by dividing the commit history, making the process much faster.

When Should You Use Git Bisect?

Use git bisect when:

  • You know a bug was not present in an older commit.
  • The bug appeared in a newer commit.
  • The bug is reproducible through a test or clear set of steps.
  • You don’t know which of the many commits introduced the bug.

This method is ideal for locating regressions, unintentional changes, or performance issues that emerged over time.


How Git Bisect Works

The process involves:

  1. Marking a good commit (without the bug).
  2. Marking a bad commit (with the bug).
  3. Testing commits checked out by git bisect until the culprit is found.

Because the process halves the search range at each step, the number of checks grows logarithmically rather than linearly with your commit history.


Step-by-Step Guide: Using Git Bisect

Let’s work through a practical example.

1. Start the Bisect Session

Navigate to your repository in the terminal, then run:

git bisect start

2. Mark Bad and Good Commits

Assume your current HEAD (the latest commit) exhibits the bug.

git bisect bad

Now, mark a commit where you’re sure the bug was absent, usually from your project’s history:

git checkout <known-good-commit>
# For example:
git bisect good a1b2c3d4

Tip: Replace a1b2c3d4 with the hash of your known-good commit.

3. Test and Mark Each Commit

git bisect now checks out a commit roughly halfway between good and bad. Test your code to determine if the bug exists:

  • If it’s bad (bug present):
    git bisect bad
    
  • If it’s good (bug absent):
    git bisect good
    

Repeat the test-and-mark cycle. Each response brings you closer to the culprit.

4. Find the Problem Commit

Once the search is narrowed down, git bisect will display the first bad commit:

<commit hash> is the first bad commit
commit <commit hash>
Author: Jane Doe <jane@example.com>
Date:   2024-04-01

    Fix for issue #42

You can now view the changes introduced in this commit:

git show <commit hash>

5. End the Bisect Session

To reset your repo to its original state:

git bisect reset

Automating Tests with Git Bisect

If your bug is detectable through a script (for example, a failing test), you can automate the process:

git bisect run ./test-script.sh
  • The script should exit with status 0 for good, non-zero for bad.
  • Git will automatically mark each commit and step forward until it locates the bad one.

Tips & Best Practices

  • Make sure your tests are deterministic (always giving the same result on each run).
  • Narrow your commit range as much as possible before starting to save time.
  • Document the bug's symptoms or test criteria clearly for consistent evaluation.
  • Try to reproduce the bug reliably before using git bisect.

Conclusion

Hunting down bugs can be daunting, but git bisect transforms this process into a structured, efficient search. By leveraging the principles of binary search, you can quickly zero in on the problematic commit, understand what changed, and take corrective action.

Next time a regression slips through, reach for git bisect—and let Git do the hard investigative work for you.


Further Reading:

Happy debugging!