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 Release 2.0 is working fine, but some tests are not passing in
da86694 Make change 4.
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
eb62d12 Change 2 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 Change 1. 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 Change 1 is the root bad commit since the previous one
2d07264 Release 2.0 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.