In the last weeks I have written about a couple of different ways to create clean git commit histories. Today we will learn about another feature of git with which we can really profit from a clean history. You probably know the situation where a bug is reported to you but you can’t tell, where this bug might come from. Luckily, git has a tool that can help us figure out where things went wrong.

To show this, I have made a little repository that contains 7 commits. The repository contains a super small node script that serves as a command line adder. You pass it two numbers and it prints the result:

$ node sum.js 1 2
3

This worked fine for the first commit but if you clone the repository and run this command on the latest commit, you will see the following output instead:

$ node sum.js 1 2 
210

As you can see, something broke in the process. Let’s figure out why. To do so, we are going to bisect the commits. Bisecting has three phases: First, we provide git with a commit in which the code worked and one in which it did not work anymore. Then git will chec out a commit that is in the middle of the two supplied commits and ask us if the code is still working as expected. We can execute our example command from above, check if the output is 3 or 210 and then tell git if the commit is good or bad. Git will then go on to pick another commit that is halfway between the good-state and the bad-state and ask us again until we are down to one commit. You can see this in the video below:

I start out by telling git that the current HEAD is broken and the very first commit (which I got from looking at git log) is fine. I than run my script and check the output and confirm the result with git bisect good or git bisect bad. This continues until git shows me in which commit I broke the code.

Since this can get a bit tedious, git also has a way to automate this. You can start a bisect as seen above and then use git bisect run <command> to execute a script. If this script exits with a zero exit code, the currently checked out commit is marked as good, otherwise it is marked as bad. In the example below I use the fish shell to automatically check the output of node sum.js 1 2.

As you can see, this ends up at the same commit that broke the code with much less effort from my side. Of course this is not always possible or sensible (imagine a situation where some CSS broke and you have to check manually if your website still looks correct or not) but if you have a test suite already this can come in really handy.

I hope that bisect will make it easier for you in the future to find where bugs slipped into your code. Again, in order for this to work it helps to have really small and focused commits. If you write atomic commits, the code you will have to look through in the commit that bisect identified should be easily scannable and you should be able to fix your bug in no time. Happy debugging!