Finding Bad Commits Using Git Bisect

Figure out which commit introduced that new bug

Maroun Maroun
Better Programming

--

Binoculars facing a lake
Image By Shane Hauser on Unsplash.

“git-bisect — Use binary search to find the commit that introduced a bug” — Git’s official docs

It’s best to go through a real example in order to understand this command and demonstrate how it works.

Let’s create an empty Git project and add the following commits:

git commit --allow-empty -m 'good commit 1'
git commit --allow-empty -m 'good commit 2'
git commit --allow-empty -m 'good commit 3'
git commit --allow-empty -m 'good commit 4'
git commit --allow-empty -m 'good commit 5'
git commit --allow-empty -m 'good commit 6'
git commit --allow-empty -m 'BAD COMMIT'
git commit --allow-empty -m 'good commit 7'
git commit --allow-empty -m 'good commit 8'
git commit --allow-empty -m 'good commit 9'
git commit --allow-empty -m 'good commit 10'

We have just discovered a bug, but we’re unsure which commit has introduced it. git bisect to the rescue!

We first need to run git bisect start in order to start the wizard:

git bisect start

Now we’ll need to tell Git what was the last commit known to us that introduced the bug. Assuming we’ve discovered the bug on the last commit:

git bisect bad HEAD

And of course, the oldest commit known to be good:

git bisect good HEAD~9
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[375c587c8da1c90d07fd58a2402fd8bcf842ffd2] good commit 6

Now Git will perform the binary search on our history and check out a commit that we’ll need to decide is either good or bad.

We’re now on good commit 6, a commit before the bug was introduced:

git bisect good
Bisecting: 2 revisions left to test after this (roughly 1 step)
[f14653c6730ef0537dbf8ec541997d7e9deb5e2a] good commit 7

This commit is not good, as the code already includes the BAD COMMIT. So we need to tell Git that it’s bad:

git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[421dab9fc7f885dfadb3c7a37d70fa7dfbb6f3d1] BAD COMMIT

And finally, the bad commit:

git bisect bad
421dab9fc7f885dfadb3c7a37d70fa7dfbb6f3d1 is the first bad commit

git log will now reveal that it's actually the BAD COMMIT that introduced the bug:

git log | grep "BAD COMMIT" -B 5
commit 421dab9fc7f885dfadb3c7a37d70fa7dfbb6f3d1
Author: MarounMaroun <maroun email>
Date: Sun Jan 19 11:28:03 2020 +0200
BAD COMMIT

Automating git bisect

“If you have a script that can tell if the current source code is good or bad, you can bisect by issuing the command:

$ git bisect run my_script arguments

Note that the script (my_script in the above example) should exit with code 0 if the current source code is good/old, and exit with a code between 1 and 127 (inclusive), except 125, if the current source code is bad/new.” — Git’s official docs

bisect can run a command on each iteration. If the command succeeds (exits with a zero code), it’ll automatically mark the commit as good. It’ll mark it as bad if it fails (exits with a non-zero code). For example, we can try building our application using the make utility (my_test.sh):

#!/usr/bin/env bashmake test || exit 1

Now we can run git bisect run ./my_test.sh to begin the automated debugging. If the script succeeds, it’ll return a zero code and git bisect will mark it as good. Otherwise, it’ll be marked as bad.

Summary

git bisect is a simple tool for tracking down a bug. It reduces debugging time significantly. It’s best to use it in situations when you have a bug that is hard to debug and it’s hard to find which commit introduced it. It’s extremely useful if you create small and consistent commits.

This command will be even more useful if you have automated tests that can be applied by the tool itself by writing a test scenario.

--

--