Finding Problems with Git Bisect
Git-bisect is an amazing tool for fixing problems. It uses a binary search algorithm to weed out the offending commit so you can fix whatever problem was introduced.
Binary Search Algorithm #
It’s not important to get too deep in the weeds on this but I do want to explore exactly what git-bisect is going and why a binary search algorithm is a good approach to identifying the problem with the repository.
A binary search algorithm is used to quickly find a target in a sequence (could be an array of data or a collection like the commits in Git). In our case we are looking for a commit that introduced a bug.
Let’s say we have seven commits in our sequence.
r1 r2 r3 r4 r5 r6
We know that r1 is a good commit (no bug apparent) and r6 is a bad commit (shows the bug). We need to find where that bug was introduced.
The algorithm splits the sequence of commits (determined by the boundaries we set by telling git-bisect the last good commit and a bad commit) in half and checks out the middle commit.
r1 r2 r3 (r4) r5 r6
If the checked out commit doesn’t have the bug introduced then the algorithm will go later in the sequence, setting the new boundaries to r4..r6. We know that r4 and below won’t have the bug so those are tossed out and no longer evaluated.
r1 r2 r3 r4 (r5) r6
Now git-bisect checks out r6 and we check whether it is good or bad. Does it have the bug? Indeed it does. Instead of checking out and testing six commits, we only had to check two. This doesn’t look impressive with a small sequence but imagine how quick this works on a large project with hundreds of commits.
Using git-Bisect #
Using git-bisect looks like this:
$ git bisect start
$ git bisect good 69e8f1923
$ git bisect bad e58f8776
Git-bisect will then split your commit range in half and check out a commit for you to check to see if the bug existed in the commit. You can think of this as “divide and conquer.”
If the bug still exists you reply to Git with:
$ git bisect bad
And then git-bisect will split the commits in half again and check one out for you to test. If you are at a commit that doesn’t have the bug present, you reply to Git with:
git bisect good
Do this until you (with the help of git-bisect) have narrowed down the offending commit. Git will come back to you identifying the offending commit.
97797cb24118068e0a28fedef19fabb5dd129b4d is the first bad commit
We now know where the bug was introduced and review the code to plan a fix.
To get the repository back in a working state, we need finish up our git-bisect section.
git bisect reset
Changing Terms in Git Bisect #
Now that we know how to use git-bisect
let’s talk about how we can make the terminology a little easier to understand.
Previously we used “good” and “bad” as a way to describe the state of our project as we hunted for the introduction of a problem or bug.
But those terms don’t always make sense.
Maybe we are trying to where a file called needle.rb
was introduced. Sure, this is contrived example but stick with me. So instead of saying “good” or “bad” we want to say the repository has “needle” or “no-needle.”
To do this we need to run git-bisect
with our terms included as options.
$ git bisect start --term-good=no-needle --term-bad=needle
When the checked out version of the project doesn’t have the needle.rb
file then we can mark it as “no-needle” or, in the original language of git-bisect
: “good.” If the needle.rb
file is present, we can tell git-bisect
that that version of the project has the needle (or is “bad” because we don’t want the needle in our project).