This project demos how to use git-bisect. The project contains a simple calculator that does not add correctly.
Your task is to find the commit that introduced the bug.
Bisecting is the process of finding a commit that introduced a bug using in binary search algorithm. The process is roughly as follows:
- Define the range from the "last-known-good" to a broken commit.
- Select a commit between the "last-known-good" and the earliest bad commit (usually by splitting the range in half).
- Check if the commit contains the bug and report back to git.
- Rinse and repeat step 2 and 3 until the bug-introducing commit is found.
The awkward part is to check whether the commit to check already introduced the a bug. Luckily, this can be automated using a script you have in place ... which you do, right?
The repository contains two branches, master and retrofit. Both branches
have a broken calculator implemented as a simple shell script.
-
The
masterbranch includes a test for the calculator'saddmethod,adds-operands-test. The test has been committed together with theaddfunction (think TDD). -
The
retrofitbranch initially did not add a test for the broken calculator. This usually the case when developers don't subscribe to TDD or when the bug was not covered by the tests that were written by the time theaddfunction was implemented. What you would usually do is to write a reproduction for the bug in the form of a test. For your convenience I've added the reproducing test in the most recent commit inretrofit,adds-operands-reproduction-test.
Each branch contains:
- A buggy calculator.
- A build script,
build, that is used to build and test the calculator. - A tag denoting the working revision:
good.
After cloning the repository start bisecting the good..master revision range.
$ git bisect start master goodYou can test each commit manually while you are in bisect mode:
# You are in detached HEAD state at a commit between master and good.
$ ./build
# Check build results, if the build succeeded:
$ git bisect good
# otherwise:
$ git bisect bad
# Repeat until you found the breaking commit...
# When you are done, stop bisecting.
$ git bisect resetYou can also script the check by running build for every commit to be tested:
$ git bisect run ./buildNow watch git finding the commit that introduced the bug in the addition logic.
Bisecting without a proper reproduction that is already part of the commits to be tested is a bit harder, but not impossible. You will have to apply the bug's reproduction to each of the commits being tested.
In this example, we use cherry-pick
to apply the reproduction to every commit in the good..retrofit revision
range. A little helper script, start-bisect, does the cherry-picking, build
script invocation and clean-up for us.
Switch to the retrofit branch and start bisecting the bad..retrofit revision
range.
# Create the retrofit branch from the remote retrofit branch.
$ git checkout -b retrofit origin/retrofit
# Start bisecting.
$ ./start-bisect