User Tools

Site Tools


git_bisect

Overview

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

Some links:

SYNOPSIS

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

Basic bisection

Defining the endpoints

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

Displaying the current commit

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

The bisection step

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

$ git bisect good
$ git bisect bad

to refine the interval containing the error.

The end result

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

Advanced bisection

Alternate terms

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

Avoid testing a clearly bad commit

$ 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

Skipping commits

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]

Path limiting bisection

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

$ git bisect start -- drivers/usb/ drivers/serial/

More than one good commit

$ 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
$

git bisect run

Overview

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.

Special exit code 125

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

The "--no-checkout" option

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.

Bisection while ignoring feature branches

NOTE: This explanation is based on the writeup here.

If we have two commits directly on the master branch, and we try to bisect using those two commits as good and bad endpoints, it's entirely possible that we could end up processing many, many, many commits based on the number of (potentially lengthy) feature branches that were merged into master between the two commits.

Rather than bisecting completely on those lengthy feature branches, we can 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. (This also considers the possibility of a stand-alone commit directly on the master branch as well.) Let's demonstrate this using the Linux kernel source repository, defining v4.18 as the good commit, and v4.19 as the bad commit.

First, let's count the number of commits we would normally need to process if we used basic bisection based on those two endpoints:

$ git rev-list v4.18..v4.19 | wc -l
15204
$

That's a lot of commits so let's see if we can reduce that number. The basis for ignoring all of the commits on feature branches is to generate a list of commits to ignore, and feed that list to git bisect skip to cut down on the work. The first step is to generate a list of merge commits between the two endpoints

$ git rev-list v4.18..v4.19 --merges | wc -l
1161
$

So there are 1161 merge commits in the testable range, but we need to further disqualify merge commits exclusively on feature branches, so let's restrict ourselves to just the first parents of those merge commits, which guarantees that all of those merge commits are on the master branch:

$ git rev-list v4.18..v4.19 --merges --first-parent | wc -l
426
$

What the above set of merge commits represents are those merge commits for which we want to totally ignore all commits on the feature branch that contributed to each of those commits. For each merge commit above (call it rev), we list all commits reachable from the second parent (the one on the feature branch, rev^2), but not reachable from the parent on the master branch (rev^), and pass all such commits to git bisect skip.

for rev in $(git rev-list v4.18..v4.19 --merges --first-parent); do
  git rev-list $rev^2 --not $rev^
done | xargs git bisect skip

Given that our basic search would have processed 15204 commits, we can count how many commits will now be pruned from the bisection:

for rev in $(git rev-list v4.18..v4.19 --merges --first-parent); do
  git rev-list $rev^2 --not $rev^
done | sort | uniq | wc -l
14714
$
git_bisect.txt · Last modified: 2019/02/26 21:54 by rpjday