===== Overview ===== Both intro and advanced content on how to use ''git bisect''. Some links: * [[https://blog.smart.ly/2015/02/03/git-bisect-debugging-with-feature-branches/|Git Bisect Debugging with Feature Branches]] * [[https://git-scm.com/docs/git-bisect-lk2009.html|git-bisect-lk2009]] ===== SYNOPSIS ===== git bisect start [--term-{old,good}= --term-{new,bad}=] [--no-checkout] [ [...]] [--] [...] git bisect (bad|new|) [] git bisect (good|old|) [...] git bisect terms [--term-good | --term-bad] git bisect skip [(|)...] git bisect reset [] git bisect (visualize|view) git bisect replay git bisect log git bisect run ... 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 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 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-{new,bad}=] [--no-checkout] [ [...]] [--] [...] git bisect (bad|new|) [] git bisect (good|old|) [...] 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 $ 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 [[https://blog.smart.ly/2015/02/03/git-bisect-debugging-with-feature-branches/|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 $