Finding bugs with git bisect
In this post, I’m going to talk about git bisect and how it helps finding buggy commits or those who don’t meet some kind of requirement. By using it, git will suggest commits where a breaking change might be introduced. Let’s see how we can use it.
Let’s say we have a Go project in a git repo with this history:
$ git log --oneline
da86694 Change 4
081944f Change 3
eb62d12 Change 2
1d5d4fe Change 1
2d07264 Release 2.0
2d07264
is working fine, but some tests are not passing in da86694
. Let’s use git bisect to find out the breaking commit.
First, we inform git of a “good” and a “bad” commit, so it can start bisecting between those boundaries.
$ git bisect start
$ git bisect good 2d07264 //Release 2.0
$ git bisect bad da86694 //Change 4
Bisecting: 1 revision left to test after this (roughly 1 step)
[eb62d12] Change 2
git suggests eb62d12
as the first candidate of breaking commit. By default, git bisect will checkout to the suggested commit.
$ go test algorithm_test.go
--- FAIL: TestAlgorithm (0.45s)
FAIL _/home/johndoe/algorithm 0.451s
Test are not passing in this commit. This commit has buggy code but not necessarily mean this is where it was introduced. Thus, we need to keep looking for more candidates. To do so, we mark this commit as “bad” and git will move on:
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
1d5d4fe Change 1
git suggests a new candidate: 1d5d4fe
. Again, after run tests on this commit we get an error. Mark it as bad again:
$ go test algorithm_test.go
--- FAIL: TestAlgorithm (0.45s)
FAIL _/home/johndoe/algorithm 0.451s
$ git bisect bad
1d5d4fe Change 1
After that, git has inferred that 1d5d4fe
is the root bad commit since the previous one 2d07264
was marked as good. We are done.
This time, it took just two bisecting operations. In the worst case, it would take a maximum of log(n) bisecting operations where n is the number of commits between the good and the bad one.