You've been selected for a chance to get one year of subscription to use Wikipedia for free!
Sometimes, while writing software you introduce a bug that you don't notice until a number of commits after you introduced it. Then you have to go through who-knows-how-many commits before you find the commit that caused the problem. git bisect
is a tool designed specifically to help you find that buggy commit.
To illustrate, I've prepared a Git Repo that has one commit in it that introduces a "bug", causing the program to print "Oh, no a bug!!!!" in the middle of execution. In this program it is super easy to find the line of code that causes the bug, and I can use use the GitHub blame feature to find out what commit introduced it, but in a real project it is not always so easy.
Just this week I ran into this issue with our web-site codebase. There was a commit somewhere in a list of about 40 commits that could have ben the cause of an issue with the SEO tags no longer registering properly with my SEO verifier. I had no idea what had caused it, and I had made hundreds of changes all over the site that could have caused this strange new behavior. That is when I pulled out git bisect
a tool that I had never used myself, but had seen someone else use once.
git bisect
worked beautifully. After just a minute of testing it had pointed me to the exact commit that caused the problem. A commit that added an extra invalid meta tag, which was trivially fixed, once I knew what caused the issue.
Now I'm going to show you how to do it so you can go find your own buggy commits!
Feel free to follow along. All you will need is Git bash installed to run through this example. First up, let's clone our buggy git repo:
$ git clone https://github.com/katharostech/git-bisect-demo.git
$ cd git-bisect-demo
Now let's run our little program to see how it behaves:
$ ./program.sh
Hello! Let's find out more about you.
What is your name: Zicklag
Hi Zicklag! My name is ./program.sh.
What is your favorite food: pizza
I like pizza, too!
But really, everybody likes pizza. ;)
Oh, no a bug!!!!
OK, next quesion, cats or dogs?: cats
Yep, cat's are totally better
What's your favorite TV show: Voltron
Voltron, huh? Not bad, my favorite is Lost in Space.
Last question, what is your _least_ favorite food: broccoli
Eeww, broccoli!? Gross!
So, right there in the middle we can see our bug manifesting itself. Time to start git bisect
. We'll tell git to start bisecting and we'll mark this commit as "bad" because it has the bug in it:
$ git bisect start
$ git bisect bad
Now we are going checkout a commit that we know doesn't have the bug. Because this repo only has 8 commits, we are just going to checkout the first one that had any code in it, but on a larger project you would checkout the newest commit that you knew of that didn't have the bug in it, such as your last release maybe.
$ git checkout 8f28c57
Now let's run our program and make sure we don't get the bug:
$ ./program.sh
Hello! Let's find out more about you.
What is your name: Zicklag
Hi Zicklag! My name is ./program.sh.
We're a lot of features behind, but there's no bug. Now we tell git bisect
that this is a "good" commit, without the bug:
$ git bisect good
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[be292aa967cce8fa624cc0fc41589d5565f7e2bc] Add Cats VS Dogs
Here's the cool part, git just decided for us what commit we need to test next and checked it out for us. Now we just have to run the program and check for the bug again:
$ ./program.sh
Hello! Let's find out more about you.
What is your name: Zicklag
What is your favorite food: pizza
Hi Zicklag! My name is ./program.sh.
I like pizza, too!
But really, everybody likes pizza. ;)
Oh, no a bug!!!!
OK, next quesion, cats or dogs?: cats
Yep, cat's are totally better
Because the bug is still there, we tell bisect it is another bad commit and test it again:
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 1 step)
[66968913d3cb86b6d750ad49d0193d3cdc0a125a] Add Pizza Check
./program.sh
Hello! Let's find out more about you.
What is your name: Zicklag
What is your favorite food: pizza
Hi Zicklag! My name is ./program.sh.
I like pizza, too!
But really, everybody likes pizza. ;)
Hey, look at that, this commit doesn't have the bug, so we tell bisect
that this is another good commit:
$ git bisect good
be292aa967cce8fa624cc0fc41589d5565f7e2bc is the first bad commit
commit be292aa967cce8fa624cc0fc41589d5565f7e2bc
Author: Zicklag <zicklag@katharostech.com>
Date: Tue May 19 23:51:17 2020 +0000
Add Cats VS Dogs
:100755 100755 529edfe431351df5539558b060ef9e7121dae097 1f3cf15dbaaddb545fca8fbe8476b1d0054d2fc0 M program.sh
And there we have it, git bisect
tells us that it found the first bad commit! Let's checkout that commit and get the diff on it to see where we went wrong:
$ git checkout be292aa9
$ git diff HEAD^
$ diff --git a/program.sh b/program.sh
index 529edfe..1f3cf15 100755
--- a/program.sh
+++ b/program.sh
@@ -10,3 +10,14 @@ if [ "$food" == "pizza" ]; then
echo "But really, everybody likes pizza. ;)"
fi
+echo "Oh, no a bug!!!!"
+
+read -p "OK, next quesion, cats or dogs?: " pet
+
+if [ "$pet" == "cats" ]; then
+ echo "Yep, cat's are totally better"
+elif [ "$pet" == "dogs" ]; then
+ echo "Eh, I'm more of a cat person really"
+else
+ echo "Well, that wasn't really an option, but I guess $pet are OK, too."
+fi
And there we have it, a mistakenly placed echo "Oh, no a bug!!!!"
in our code. Who'd have guessed it. Well, that's an easy enough fix. Let's get out of our bisect session and go fix that bug!
$ git bisect reset
Previous HEAD position was be292aa Add Cats VS Dogs
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ vi ./program.sh
# And the saga continues...
git bisect
is super easy to use and a powerful tool for finding long-lost bugs, but that's not all you can use it for. You could use git bisect
to find out where things like benchmarks improved, using it to identify what commit made your program faster. In that case you can use git bisect old
and git bisect new
instead of git bisect good
and git bisect bad
to mark commits.
Either way, now you've got a new utility to stick in your toolbox that might just save you some time while working on your own projects in the future.