Finding bugs with git bisect

Git provides a couple of tools to help you debug issues in your projects. These tools can be extremely useful, especially in the case of a software regression, a software bug which makes a feature stop functioning as intended after a certain revision. If you don't know where the bug is, and there have been dozens or hundreds of commits since the last state where you know the code worked, you'll likely turn to git bisect for help.

The bisect command searches semi-automatically step by step through the project history, trying to find the revision that introduced the bug. In each step, it bisects the history into roughly equal parts, and asks whether there is a bug in the dividing commit. It then uses the answer to eliminate one of the two sections, and reduces the size of the revision range where there can be a commit that introduced the bug.

Suppose version 1.14 of your project worked, but the release candidate, 1.15-rc0, for the new version crashes. You go back to the 1.15-rc0 version, and it turns out that you can reproduce the issue (this is very important!), but you can't figure out what is going wrong.

You can bisect the code history to find out. You need to start the bisection process with git bisect start, and then tell Git which version is broken with git bisect bad. Then, you must tell bisect the last-known good state (or set of states) with git bisect good:

$ git bisect start
$ git bisect bad  v1.15-rc0
$ git bisect good v1.14
Bisecting: 159 revisions left to test after this (roughly 7 steps)
[7ea60c15cc98ab586aea77c256934acd438c7f95] Merge branch 'mergetool'

Git figured out that about 300 commits came between the commit you marked as the last good commit (v1.14) and the bad version (v1.15-rc0), and it checked out the middle one (7ea60c15) for you. If you run git branch at this point, you'll see that git has temporarily moved you to (no branch):

$ git branch
* (no branch, bisect started on master)
  master

At this point, you need to run your test to check whether the issue is present in the commit currently checked out by the bisect operation. If the program crashes, mark this commit as bad with git bisect bad. If the issue is not present, mark it as correct with git bisect good. After about seven steps, Git would show the suspect commit:

$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <[email protected]>
Date:   Tue Jan 27 14:48:32 2009 -0800

    secure this thing

:040000 040000 40ee3e7… f24d3c6… M  config

The last line in the preceding example output is in so called raw diff output, showing which files changed in a commit. You can then examine the suspected commit with git show. From there, you can find the author of the said commit, and ask them for clarification, or to fix it (or to send them a bug report). If the good practice of creating small incremental changes was followed during the development of the project, the amount of code to examine after finding the bad commit should be small.

If at any point, you land on a commit that broke something unrelated, and is not a good one to test, you can skip such a commit with git bisect skip. You can even skip a range of commits by giving the revision range to the skip subcommand.

When you're finished, you should run git bisect reset to return you to the branch you started from:

$ git bisect reset
Previous HEAD position was b047b02... secure this thing
Switched to branch 'master'

To finish bisection while staying on located bad commit, you can use git bisect reset HEAD.

You can even fully automate finding bad revision with `git bisect run`. For this, you need to have a script that will test for the presence of bug, and exit the value of 0 if the project works all right, or non-0 if there is a bug. The special exit code, 125, should be used when the currently checked out code cannot be tested. First, you again tell it the scope of the bisect by providing the known bad and good commits. You can do this by listing them with the bisect start command if you want, listing the known bad commit first and the known good commit(s) second. You can even cut down the number of trials, if you know what part of the tree is involved in the problem you are tracking down, by specifying path parameters:

$ git bisect start v1.5-rc0 v1.4 -- arch/i386
$ git bisect run ./test-error.sh

Doing so automatically runs test-error.sh on each checked-out commit until Git finds the first broken commit. Here, we have provided the scope of the bisect by putting known bad and good commits with the bisect start command, listing the known bad commit first and the known good commit(s) second.

If the bug is that the project stopped compiling (a broken build), you can use make as a test script (git bisect run make).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset