summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-bisect.txt30
-rwxr-xr-xgit-bisect.sh54
-rwxr-xr-xt/t6030-bisect-run.sh57
3 files changed, 138 insertions, 3 deletions
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 16ec7269b2..b7cd715380 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -22,6 +22,7 @@ depending on the subcommand:
git bisect visualize
git bisect replay <logfile>
git bisect log
+ git bisect run <cmd>...
This command uses 'git-rev-list --bisect' option to help drive
the binary search process to find which change introduced a bug,
@@ -121,6 +122,35 @@ like this:
$ git bisect start arch/i386 include/asm-i386
------------
+If you have a script that can tell if the current
+source code is good or bad, you can automatically bisect using:
+
+------------
+$ git bisect run my_script
+------------
+
+Note that the "run" script (`my_script` in the above example)
+should exit with code 0 in
+case the current source code is good and with a code between 1 and 127
+(included) in case the current source code is bad.
+
+Any other exit code (a program that does "exit(-1)" leaves $? = 255,
+see exit(3) manual page, the value is chopped with "& 0377") will
+abort the automatic bisect process.
+
+You may often find that during bisect you want to have near-constant
+tweaks (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or
+"revision that does not have this commit needs this patch applied to
+work around other problem this bisection is not interested in")
+applied to the revision being tested.
+
+To cope with such a situation, after the inner git-bisect finds the
+next revision to test, with the "run" script, you can apply that tweak
+before compiling, run the real test, and after the test decides if the
+revision (possibly with the needed tweaks) passed the test, rewind the
+tree to the pristine state. Finally the "run" script can exit with
+the status of the real test to let "git bisect run" command loop to
+know the outcome.
Author
------
diff --git a/git-bisect.sh b/git-bisect.sh
index dbce0dfec9..3043f65514 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -1,14 +1,15 @@
#!/bin/sh
-USAGE='[start|bad|good|next|reset|visualize|replay|log]'
+USAGE='[start|bad|good|next|reset|visualize|replay|log|run]'
LONG_USAGE='git bisect start [<pathspec>] reset bisect state and start bisection.
git bisect bad [<rev>] mark <rev> a known-bad revision.
git bisect good [<rev>...] mark <rev>... known-good revisions.
git bisect next find next bisection to test and check it out.
git bisect reset [<branch>] finish bisection search and go back to branch.
git bisect visualize show bisect status in gitk.
-git bisect replay <logfile> replay bisection log
-git bisect log show bisect log.'
+git bisect replay <logfile> replay bisection log.
+git bisect log show bisect log.
+git bisect run <cmd>... use <cmd>... to automatically bisect.'
. git-sh-setup
require_work_tree
@@ -185,6 +186,7 @@ bisect_reset() {
rm -f "$GIT_DIR/refs/heads/bisect" "$GIT_DIR/head-name"
rm -f "$GIT_DIR/BISECT_LOG"
rm -f "$GIT_DIR/BISECT_NAMES"
+ rm -f "$GIT_DIR/BISECT_RUN"
fi
}
@@ -220,6 +222,50 @@ bisect_replay () {
bisect_auto_next
}
+bisect_run () {
+ while true
+ do
+ echo "running $@"
+ "$@"
+ res=$?
+
+ # Check for really bad run error.
+ if [ $res -lt 0 -o $res -ge 128 ]; then
+ echo >&2 "bisect run failed:"
+ echo >&2 "exit code $res from '$@' is < 0 or >= 128"
+ exit $res
+ fi
+
+ # Use "bisect_good" or "bisect_bad"
+ # depending on run success or failure.
+ if [ $res -gt 0 ]; then
+ next_bisect='bisect_bad'
+ else
+ next_bisect='bisect_good'
+ fi
+
+ # We have to use a subshell because bisect_good or
+ # bisect_bad functions can exit.
+ ( $next_bisect > "$GIT_DIR/BISECT_RUN" )
+ res=$?
+
+ cat "$GIT_DIR/BISECT_RUN"
+
+ if [ $res -ne 0 ]; then
+ echo >&2 "bisect run failed:"
+ echo >&2 "$next_bisect exited with error code $res"
+ exit $res
+ fi
+
+ if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
+ echo "bisect run success"
+ exit 0;
+ fi
+
+ done
+}
+
+
case "$#" in
0)
usage ;;
@@ -244,6 +290,8 @@ case "$#" in
bisect_replay "$@" ;;
log)
cat "$GIT_DIR/BISECT_LOG" ;;
+ run)
+ bisect_run "$@" ;;
*)
usage ;;
esac
diff --git a/t/t6030-bisect-run.sh b/t/t6030-bisect-run.sh
new file mode 100755
index 0000000000..39c72283b5
--- /dev/null
+++ b/t/t6030-bisect-run.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Christian Couder
+#
+test_description='Tests git-bisect run functionality'
+
+. ./test-lib.sh
+
+add_line_into_file()
+{
+ _line=$1
+ _file=$2
+
+ if [ -f "$_file" ]; then
+ echo "$_line" >> $_file || return $?
+ MSG="Add <$_line> into <$_file>."
+ else
+ echo "$_line" > $_file || return $?
+ git add $_file || return $?
+ MSG="Create file <$_file> with <$_line> inside."
+ fi
+
+ git-commit -m "$MSG" $_file
+}
+
+HASH1=
+HASH3=
+HASH4=
+
+test_expect_success \
+ 'set up basic repo with 1 file (hello) and 4 commits' \
+ 'add_line_into_file "1: Hello World" hello &&
+ add_line_into_file "2: A new day for git" hello &&
+ add_line_into_file "3: Another new day for git" hello &&
+ add_line_into_file "4: Ciao for now" hello &&
+ HASH1=$(git rev-list HEAD | tail -1) &&
+ HASH3=$(git rev-list HEAD | head -2 | tail -1) &&
+ HASH4=$(git rev-list HEAD | head -1)'
+
+# We want to automatically find the commit that
+# introduced "Another" into hello.
+test_expect_success \
+ 'git bisect run simple case' \
+ 'echo "#!/bin/sh" > test_script.sh &&
+ echo "grep Another hello > /dev/null" >> test_script.sh &&
+ echo "test \$? -ne 0" >> test_script.sh &&
+ chmod +x test_script.sh &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run ./test_script.sh > my_bisect_log.txt &&
+ grep "$HASH3 is first bad commit" my_bisect_log.txt'
+
+#
+#
+test_done
+