Finding Bad Commits Using Git Bisect
Figure out which commit introduced that new bug
“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.