This is an old revision of the document!


Both intro and advanced content on how to use git bisect.

Some links:

git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
                 [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>...]
git bisect terms [--term-good | --term-bad]
git bisect skip [(<rev>|<range>)...]
git bisect reset [<commit>]
git bisect (visualize|view)
git bisect replay <logfile>
git bisect log
git bisect run <cmd>...
git bisect help

Any of the following (bad, followed by good):

$ git bisect start v4.20 v4.19

or

$ git bisect start
$ git bisect good v4.19
$ git bisect bad v4.20

after which you should see:

Bisecting: 7499 revisions left to test after this (roughly 13 steps)
[ec9c166434595382be3babf266febf876327774d] Merge tag 'mips_fixes_4.20_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux

At any time, examine the current commit with:

$ git show
commit ec9c166434595382be3babf266febf876327774d (HEAD)
Merge: 685f7e4f1614 c61c7def1fa0
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Fri Oct 26 14:39:22 2018 -0700

    Merge tag 'mips_fixes_4.20_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
    
    Pull MIPS fixes from Paul Burton:
     "A couple of MIPS fixes that should have ideally made it for v4.19, but
      hey-ho here they are now:
    
       - A fix for potential poor stack placement introduced in v4.19-rc8.
    
       - A fix for a warning introduced in use of TURBOchannel devices by
         DMA changes in v4.16"
    
    * tag 'mips_fixes_4.20_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux:
      MIPS: VDSO: Reduce VDSO_RANDOMIZE_SIZE to 64MB for 64bit
      TC: Set DMA masks for devices

After testing the current checkout for the error, do one of:

$ git bisect good
$ git bisect bad

to refine the interval containing the error.

After binary search, you will end up with something like:

$ git bisect good
130d6f946f6f2a972ee3ec8540b7243ab99abe97 is the first bad commit
commit 130d6f946f6f2a972ee3ec8540b7243ab99abe97
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Sun Nov 25 19:33:40 2018 +0100

    x86/l1tf: Show actual SMT state
    ... snip ...

Once you're done:

$ git bisect reset

Description:

git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
	  [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>...]
git bisect terms [--term-good | --term-bad]
... snip ...

Pre-defined (you can't mix them):

  • good/bad
  • old/new

To see the current terms:

$ git bisect terms

Or just make up your own (to see where performance suddenly tanked):

$ git bisect start --term-old fast --term-new slow
$ git bisect good/bad         # previous round was good or bad.
Bisecting: 337 revisions left to test after this (roughly 9 steps)
$ git show                    # oops, that is uninteresting.
$ git reset --hard HEAD~3     # try 3 revisions before what
                              # was suggested

Skip the current commit:

$ git bisect skip

Skip entire ranges:

$ git bisect skip v2.5..v2.6           # (v2.5,v2.6]
$ git bisect skip v2.5 v2.5..v2.6      # [v2.5,v2.6]

If you're having trouble with a USB-serial converter:

$ git bisect start -- drivers/usb/ drivers/serial/
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
                   # v2.6.20-rc6 is bad
                   # v2.6.20-rc4 and v2.6.20-rc1 are good
$

If you have a command or program (say, ~/bin/check_test_case.sh) that returns 0 (success) or 1 (failure) based on testing the checked out repo, use that to automatically bisect:

$ git bisect run ~/bin/check_test_case.sh

For example, you can find the first unbuildable commit with:

$ git bisect run make

since make returns 0 on success and 2 on failure.

Any exit code from 1 to 127 represents failure, except for the special exit code of 125, which should be used when the current source code cannot be tested. If the script exits with this code, the current revision will be skipped (see git bisect skip).

$ cat ~/bin/test.sh
#!/bin/sh
make || exit 125                  # this skips broken builds
~/check_test_case.sh              # does the test case pass?
$

How to use it:

$ git bisect start <bad> <good>
$ git bisect run ~/test.sh
$ git bisect reset

Do not checkout the new working tree at each iteration of the bisection process. Instead just update a special reference named BISECT_HEAD to make it point to the commit that should be tested.

This option may be useful when the test you would perform in each step does not require a checked out tree.

Rather than bisecting completely on lengthy feature branches, restrict the search to just those commits where feature branches were merged into master, so the ultimate goal is to say, “That merged feature branch is the one that caused the problem,” possibly inspiring another round of more focused bisection.

First, list all revisions in the range of interest (Linux kernel source used here):

$ git rev-list v4.14..v4.15
d8a5b80568a9cb66810e75b182018e9edb68e8ff
24b1cccf922914f3d6eeb84036dde8338bc03abb
32c6cdf75c9270848d2d0ed7c814eba05b47081f
07b0137c0268b8d0694a5f09284449353a1a6fed
624441927ff6af871d793dfa49fa347c8450e250
39e383626caffd2b5f4407710157b32172898869
... massive snip ...

Just count the commits available to bisection with either of:

$ git rev-list v4.14..v4.15 | wc -l
16223
$ git rev-list ^v4.14 v4.15 | wc -l
16223
$

Next, restrict yourself to just merge commits (which could include merges on feature branches, but we will deal with those shortly):

$ git rev-list v4.14..v4.15 --merges | wc -l
1357
$

Further, follow only the first parent commit upon seeing a merge commit (to exclude any commits on feature branches, including those pesky merge commits):

$ git rev-list v4.14..v4.15 --merges --first-parent | wc -l
435
$

The above set of commits represents the merge commits on master we would like to bisect, but we need to use them as the basis to identify the commits on each feature branch we want to skip so let's wrap that command in a loop in preparation:

$ for rev in $(git rev-list v4.14..v4.15 --merges --first-parent) ; do
> echo ${rev}
> done | wc -l
435
$

Now, for each merge commit on master being represented by rev above, we need to use git rev-list to generate the list of commits we want to skip from the bisection, and those would be the commits exclusively on the feature branch being merged, which are those commits reachable in each case from the second parent of rev (the feature branch), but not the first parent:

git rev-list ${rev}^2 ^${rev}^
  • git_bisect.1550688860.txt.gz
  • Last modified: 2019/02/20 18:54
  • by rpjday