Tracking Bugs In Git

Tracking bugs in Git

Bugs are common place in development. Sometimes a bug will arise in an old feature that you know didn’t previously exist.

You have hundreds of commits of small changes that touch this part of the code, so where do you start in finding the causal commit of this bug.

Most developers will checkout arbitrary commits and one by one hope that the problem is non existent. This is often time consuming and tedious.

Introducing Git Bisect.

Git bisect

Git bisect is a tool built in to Git that allows for walking through a range of commits one by one and deciding if each one is good or bad

Start a bisect:

git bisect start

This command begins Git’s walk-through to finding your problem. After starting Git needs to know the starting and ending range of the history to explore.

You start by telling Git which commit is bad. You can either select it’s revision.

A revision can be a selection of things, from commit id’s to branch names, to tags etc.

git bisect bad <revision>

Or in most cases use the HEAD ref. Note the HEAD argument below can be emitted as it is the default argument

git bisect bad HEAD

In a similar process you need you to tell Git which revision was the last known working version

git bisect good <revision>

Having your bad and good revisions selected gives Git a range to search within. The wider this range is, the longer the proceeding process will take. This is where the importance of verbose commit messages helps in finding your range.

Git now checks out a revision half way between your bad and good revision.

From here is up to you to decide on each revision if it is a good or bad revision, good or bad being is the bug existing or not.

git bisect good|bad

This process carries on for each revision as Git selects the next revision half way between this smaller range. And you make the same decision again, is this revision good or bad. This is not unlike the process of how a binary search works.

Eventually you will be presented with the originating bad revision

<hash> is the first bad commit

After you’ve found your culprit you have to tell Git that you’ve finished and want to exit the git bisect. This can be done with

git bisect reset

This entire process works, but it is very manual and slow. Thankfully we can automate this process.

Automating Git bisect

Git bisect has a command that can automate this entire job

git bisect run <command>

The run command accepts any command as an argument for example

git bisect run python test-bug-fix.py

The run command follows the same process as above but makes the decisions for a good or bad revision based on the exit code returned from the command.

Most if not all modern day unit test frameworks support exit codes and follow the simplest rule that an exit code of 0 is good and anything else is bad. Git bisect enforces it’s own rules over this, only supporting exit codes from 0-127 inclusive and 125 is reserved for a special case. The special case for exit code is 125 is used if the current revision should be skipped, normally because the unit test can’t be relied on to decide if it’s a good or bad revision. An example of this would be possibly a compilation error in the code that stops the unit test from being run.