This is an old revision of the document!
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:
$ git bisect start v4.20 v4.19
or
$ git bisect start $ git bisect good v4.19 $ git bisect bad v4.20
Cute features of 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/badold/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 with feature branches (WARNING: INCOMPLETE!)
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}^