Git Bisect

Working as a software engineer, a lot of time is spent fixing bugs. Some of these bugs are regressions which means that something which used to work doesn't anymore. When working with a large code base it's often difficult to pinpoint what exactly triggered the regression. It sometimes can be something that at first glance is completely unrelated. When this happens, a technique to determine which commit triggered the regression is to try out every commit until you hit the one that caused the regression. This can be optimized by using dichotomy to ⌊log2(n)⌋ where n is the number of commits between the version where it worked (good) and where it doesn't (bad).

When using git; dichotomy can be done for you. The command is git bisect. But when using plain git bisect you still have to manually tell git if the current version is good or bad. That is unless you have a scripted way to telling if the current version is good or bad. In our case this will be a Maven test. I used this when working on CAMEL-12613.

First of you have to write a script (bash in our case) that outputs 0 if the code is good (doesn't contain the bug) and any number between 1 and 127 if the code is bad (contains the bug). A special return value of 125 can be used to tell git that the current version isn't testable. This can be VERY useful as some commits may have broken the build thus preventing you from running your test. This is the script used in our case:

#!/bin/sh
mvn clean install -Dtest=FileConsumerPreMoveLastModifiedTest -f camel-core/pom.xml
test_exit_code=$?
git checkout -- .
exit "$test_exit_code"
view raw git-run.sh hosted with ❤ by GitHub
All this script does is execute a Maven test called FileConsumerPreMoveLastModifiedTest and does some cleaning due to generated files. Once you have this script, you're ready to go! Here's the sample work flow I used:

[jpoth@localhost ~/dev/git/apache/camel]$git bisect start HEAD camel-2.17.0
Bisecting: a merge base must be tested
[95a7910f00bb42398acd1fbedc1bd88e0f53d475] Add setContentLengthLong() method defined in ServletResponse
[jpoth@localhost ~/dev/git/apache/camel]$git bisect run ./git-run.sh
running ./git-run.sh
..... COFFEE BREAK ~ 20 minutes later
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 58.522 s
[INFO] Finished at: 2018-07-02T17:16:32+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.19.1:test (default-test) on project camel-core: There are test failures.
[ERROR]
[ERROR] Please refer to /home/jpoth/dev/git/apache/camel/camel-core/target/surefire-reports for the individual test results.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
5c47d946e1f469f515203b594b720b9f5a297ddc is the first bad commit
commit 5c47d946e1f469f515203b594b720b9f5a297ddc
Date: Fri May 20 08:57:27 2016 +0200
CAMEL-9970: CamelFileLength header is wrong for long write file. Implemented a generic solution. Thanks to Sergey Monichev for the test patch we are using.
:040000 040000 d0fcb7635b4e3e9501acec252a62855cb2437e90 2b1794e6db5ebb4fdb9801c406b493e0d27d0b25 M camel-core
:040000 040000 ebb2895aff38cf3a42e3af2200a2095e7cb2fc28 91993384594df7007ce624c4524f7d4bdedec8cd M components
bisect run success
view raw git-bisect-run hosted with ❤ by GitHub


There are two commands used here: git bisect start HEAD camel-2.17.0, which starts git bisect by telling the HEAD revision is bad and camel-2.17.0 is good; and git bisect run ./git-run.sh which tells git to use a script called git-run.sh (see above) to know if a revision is good or bad. And voilà! Enjoy the free coffee break ;)

Comments

Popular Posts