“What? I already fixed this bug! Why is it still happening?” If you don’t have a good test suite or you don’t run it regularly, finding these sorts of regressions can be difficult. Because git makes it really easy to jump to other commits (branches or history), it is very easy to narrow down what commit(s) caused the regression.
git bisect helps you do that.
I’m going to go through an example of
git bisect to show the basics.
Let’s say we have history that looks something like this (from the official git repo):
8419d2e... git-format-patch --in-reply-to: accept with angle brackets 767c98a... git-add -u: do not barf on type changes f5de799... Remove duplicate note about removing commits with git-filter-branch f28dd47... git-clone: improve error message if curl program is missing or not executable 568d2cd... git.el: Allow the add and remove commands to be applied to ignored files. 98acc3f... git.el: Allow selecting whether to display uptodate/unknown/ignored files. 1b65504... git.el: Keep the status buffer sorted by filename. c32da69... hooks--update: Explicitly check for all zeros for a deleted ref. 80bffaf... git-commit: Allow partial commit of file removal.
All we know is that 8419d2e has the bug and 80bffaf works, so we run
git bisect start 8419d2e 80bffaf. Git’s output looks like this:
$ git bisect start 8419d2e 80bffaf Bisecting: 2 revisions left to test after this [f28dd4774d4723e8251817e910dbdc5507282113] git-clone: improve error message if curl program is missing or not executable
Now we’re right in the middle of these commits. We find that the bug existed at this point too, so we run
git bisect bad:
$ git bisect bad Bisecting: 0 revisions left to test after this [c32da692de332d3c9a0b283066e3786af00f4931] hooks--update: Explicitly check for all zeros for a deleted ref.
This commit doesn’t have the bug, so we run
git bisect good:
$ git bisect good f28dd4774d4723e8251817e910dbdc5507282113 is first bad commit commit f28dd4774d4723e8251817e910dbdc5507282113 Author: Gerrit Pape Date: Thu Sep 13 11:36:22 2007 +0000 git-clone: improve error message if curl program is missing or not executable
Signed-off-by: Gerrit Pape Signed-off-by: Junio C Hamano :100755 100755 18003ab4b39ad0a7848cc20db2f6ad55e1291264 5e582fe247892fa7dffc44556c939863c36edc35 M git-clone.sh
Now we know the exact commit that caused the regression.
Sure, you could have done that with a temporary branch and
git reset --hard, but things get a lot more complicated when merges are involved.
git bisect doesn’t have problems walking down branches and keeping track of which sections are good and which sections are bad.
There are a few other options that git bisect has that can help a lot:
git bisect visualize
git bisect log
git bisect replay
git bisect run
git bisect skip
git bisect visualize opens up the range you’re analyzing in gitk which lets you see which sections you’ve discounted as good or bad.
git bisect log shows you history that can be replayed by
git bisect replay. Our example’s log looks like this:
# bad: [8419d2ee9ba8b375186a5c1019df8dfbce610aba] git-format-patch --in-reply-to: accept with angle brackets # good: [80bffaf7fbe09ef62ecb9a6ffea70ac0171b456c] git-commit: Allow partial commit of file removal. git-bisect start '8419d2e' '80bffaf' # bad: [f28dd4774d4723e8251817e910dbdc5507282113] git-clone: improve error message if curl program is missing or not executable git-bisect bad f28dd4774d4723e8251817e910dbdc5507282113 # good: [c32da692de332d3c9a0b283066e3786af00f4931] hooks--update: Explicitly check for all zeros for a deleted ref. git-bisect good c32da692de332d3c9a0b283066e3786af00f4931
If you screw up bisecting, you can use
git bisect log,
git bisect reset, and
git bisect replay to go back and fix your mistakes.
If you can write a script to automatically test your regression, you can use
git bisect run. Your script has to do its test and exit with a status code. If the status code is 0, the revision is good; if the status is between 1 and 127 (but not 125), the revision is bad; if the status is anything else (exit -1 is common), the automatic bisect process will stop; if the status is 125, it means skip that revision.
git bisect skip is used to tell git that you can’t test this revision. There can be cases where git won’t know which commit caused the problem if a skipped commit makes the bisect ambiguous.
Most newer version control systems (especially distributed ones) support bisect features. Subversion is the notable exception.