The git bisect command provides a way to speed up the bug detection process. It lets you pinpoint the problem faster. With git bisect, you can define a range of commits that you suspect have the problematic code and then use binary elimination methods to find the start of the problem. Finding bugs become faster and easier.
Let’s set up an example and run a few test cases to see how it works.
Example Setup
In our example, we will create a test.txt file and add a new line to the file with each commit. After 16 commits, the final state of the file will look like this:
Here is my good code 2
Here is my good code 3
Here is my good code 4
Here is my good code 5
Here is my good code 6
Here is my good code 7
Here is my good code 8
Here is my bad code 1 <-- BUG INTRODUCED HERE
Here is my bad code 2
Here is my bad code 3
Here is my bad code 4
Here is my bad code 5
Here is my bad code 6
Here is my bad code 7
Here is my bad code 8
Here is my bad code 9
In the above example, the bug got into the code after 8 commits. We kept developing the code even after introducing the bug.
You can create a folder called my_bisect_test and use the following commands from inside the folder to create the example situation:
echo "Here is my good code 1" > test.txt
git add -A && git commit -m "My commit 1"
echo "Here is my good code 2" >> test.txt
git add -A && git commit -m "My commit 2 (v1.0.0)"
echo "Here is my good code 3" >> test.txt
git add -A && git commit -m "My commit 3"
echo "Here is my good code 4" >> test.txt
git add -A && git commit -m "My commit 4"
echo "Here is my good code 5" >> test.txt
git add -A && git commit -m "My commit 5 (v1.0.1)"
echo "Here is my good code 6" >> test.txt
git add -A && git commit -m "My commit 6"
echo "Here is my good code 7" >> test.txt
git add -A && git commit -m "My commit 7 (v1.0.2)"
echo "Here is my good code 8" >> test.txt
git add -A && git commit -m "My commit 8"
echo "Here is my bad code 1" > test.txt
git add -A && git commit -m "My commit 9"
echo "Here is my bad code 2" >> test.txt
git add -A && git commit -m "My commit 10"
echo "Here is my bad code 3" >> test.txt
git add -A && git commit -m "My commit 11"
echo "Here is my bad code 4" >> test.txt
git add -A && git commit -m "My commit 12 (v1.0.3)"
echo "Here is my bad code 5" >> test.txt
git add -A && git commit -m "My commit 13"
echo "Here is my bad code 6" >> test.txt
git add -A && git commit -m "My commit 14"
echo "Here is my bad code 7" >> test.txt
git add -A && git commit -m "My commit 15 (v1.0.4)"
echo "Here is my bad code 8" >> test.txt
git add -A && git commit -m "My commit 16"
Checking History
If you look at the history of the commits, you see the following:
commit 3023b63eb42c7fadc93c2dd18b532a44a0a6888a
Author: Zak H
Date: Sun Dec 31 23:07:27 2017 -0800
My commit 17
commit 10ef0286d6459cd5dea5038a54edf36fc9bfe4c3
Author: Zak H
Date: Sun Dec 31 23:07:25 2017 -0800
My commit 16
commit 598d4c4acaeb14cda0552b6a92aa975c436d337a
Author: Zak H
Date: Sun Dec 31 23:07:23 2017 -0800
My commit 15 (v1.0.4)
commit b9678b75ac93d532eed22ec2c6617e5a9d70fe7b
Author: Zak H
Date: Sun Dec 31 23:07:21 2017 -0800
My commit 14
commit eb3f2f7b0ebedb732ecb5f18bee786cd3cbbb521
Author: Zak H
Date: Sun Dec 31 23:07:19 2017 -0800
My commit 13
commit 3cb475a4693b704793946a878007b40a1ff67cd1
Author: Zak H
Date: Sun Dec 31 23:07:17 2017 -0800
My commit 12 (v1.0.3)
commit 0419a38d898e28c4db69064478ecab7736700310
Author: Zak H
Date: Sun Dec 31 23:07:15 2017 -0800
My commit 11
commit 15bc59201ac1f16aeaa233eb485e81fad48fe35f
Author: Zak H
Date: Sun Dec 31 23:07:13 2017 -0800
My commit 10
commit a33e366ad9f6004a61a468b48b36e0c0c802a815
Author: Zak H
Date: Sun Dec 31 23:07:11 2017 -0800
My commit 9
commit ead472d61f516067983d7e29d548fc856d6e6868
Author: Zak H
Date: Sun Dec 31 23:07:09 2017 -0800
My commit 8
commit 8995d427668768af88266f1e78213506586b0157
Author: Zak H
Date: Sun Dec 31 23:07:07 2017 -0800
My commit 7 (v1.0.2)
commit be3b341559752e733c6392a16d6e87b5af52e701
Author: Zak H
Date: Sun Dec 31 23:07:05 2017 -0800
My commit 6
commit c54b58ba8f73fb464222f30c90aa72f60b99bda9
Author: Zak H
Date: Sun Dec 31 23:07:03 2017 -0800
My commit 5 (v1.0.1)
commit 264267111643ef5014e92e23fd2f306a10e93a64
Author: Zak H
Date: Sun Dec 31 23:07:01 2017 -0800
My commit 4
commit cfd7127cd35f3c1a55eb7c6608ecab75be30b208
Author: Zak H
Date: Sun Dec 31 23:06:59 2017 -0800
My commit 3
commit 3f90793b631ddce7be509c36b0244606a2c0e8ad
Author: Zak H
Date: Sun Dec 31 23:06:57 2017 -0800
My commit 2 (v1.0.0)
commit cc163adb8a3f7b7b52411db2b3d8bab9b7fb191e
Author: Zak H
Date: Sun Dec 31 23:06:55 2017 -0800
My commit 1
Even with only a handful of commits, you can see that it is difficult pinpointing the commit that started the bug.
Finding the Bug
Let’s use git log –online to see a more cleaned up version of the commit history.
3023b63 My commit 17
10ef028 My commit 16
598d4c4 My commit 15 (v1.0.4)
b9678b7 My commit 14
eb3f2f7 My commit 13
3cb475a My commit 12 (v1.0.3)
0419a38 My commit 11
15bc592 My commit 10
a33e366 My commit 9
ead472d My commit 8
8995d42 My commit 7 (v1.0.2)
be3b341 My commit 6
c54b58b My commit 5 (v1.0.1)
2642671 My commit 4
cfd7127 My commit 3
3f90793 My commit 2 (v1.0.0)
cc163ad My commit 1
We want to find the situation where the line “Here is my bad code 1 <– BUG INTRODUCED HERE” entered the picture.
Situation 1
Suppose we remember that our code was good until v1.0.2 and we want to check from that moment until the latest commit. We first start the bisect command:
We provide the good boundary and the bad boundary (no hash means the latest code):
$ git bisect bad
Output:
[3cb475a4693b704793946a878007b40a1ff67cd1] My commit 12 (v1.0.3)
The bisect command has found the middle point in our defined range and automatically moved the code to commit 12. We can test our code now. In our case, we are going to output the content of test.txt:
Output:
Here is my good code 2
Here is my good code 3
Here is my good code 4
Here is my good code 5
Here is my good code 6
Here is my good code 7
Here is my good code 8
Here is my bad code 1 <-- BUG INTRODUCED HERE
Here is my bad code 2
Here is my bad code 3
Here is my bad code 4
We see that the state of test.txt is in the post-bug state. So it’s in the bad state. So we let bisect command know:
Output:
[a33e366ad9f6004a61a468b48b36e0c0c802a815] My commit 9
It moves our code to commit 9. We test again:
Output:
Here is my good code 2
Here is my good code 3
Here is my good code 4
Here is my good code 5
Here is my good code 6
Here is my good code 7
Here is my good code 8
Here is my bad code 1 <-- BUG INTRODUCED HERE
We see that we have found the starting point of the bug. The commit “a33e366 My commit 9” is the culprit.
Finally, we put everything back to normal by:
Output:
Switched to branch 'master'
Situation 2
In the same example, let’s try a situation where another developer starts with the premise that the bug was introduced between v1.0.0 and v1.0.3. We can start the process again:
$ git bisect good 3f90793
$ git bisect bad 3cb475a
Output:
[8995d427668768af88266f1e78213506586b0157] My commit 7 (v1.0.2)
Bisect has moved our code to commit 7 or v1.0.2. Let’s run our test:
Output:
Here is my good code 2
Here is my good code 3
Here is my good code 4
Here is my good code 5
Here is my good code 6
Here is my good code 7
We don’t see any bad code. So, let git bisect know:
Output:
[a33e366ad9f6004a61a468b48b36e0c0c802a815] My commit 9
It has moved us to commit 9. We test again:
Output:
Here is my good code 2
Here is my good code 3
Here is my good code 4
Here is my good code 5
Here is my good code 6
Here is my good code 7
Here is my good code 8
Here is my bad code 1 <-- BUG INTRODUCED HERE
We have again found the commit that introduced the bug. It was the commit “a33e366 My commit 9”. Even though we started with the different suspicion range, we found the same bug in a few steps.
Let’s reset:
Output:
Switched to branch 'master'
Conclusion
As you can see from the example, git bisect lets us pinpoint a problem faster. It is a great tool to enhance your productivity. Instead of going through the whole history of commits, you can take a more systematic approach to debugging.
Further Study:
https://git-scm.com/docs/git-bisect
https://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git