git-bisect: make "start", "good" and "skip" succeed or fail atomically

Before this patch, when "git bisect start", "git bisect good" or
"git bisect skip" were called with many revisions, they could fail
after having already marked some revisions as "good", "bad" or
"skip".

This could be especilally bad for "git bisect start" because as
the file ".git/BISECT_NAMES" would not have been written, there
would have been no attempt to clear the marked revisions on a
"git bisect reset". That's because if there is no
".git/BISECT_NAMES" file, nothing is done to clean things up, as
the bisect session is not supposed to have started.

While at it, let's also create the ".git/BISECT_START" file, only
after ".git/BISECT_NAMES" as been created.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Christian Couder
2008-04-14 05:41:45 +02:00
committed by Junio C Hamano
parent 2e6e3e829f
commit d3e54c8829
2 changed files with 16 additions and 5 deletions

View File

@ -65,6 +65,7 @@ bisect_start() {
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) || head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) || head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
die "Bad HEAD - I need a HEAD" die "Bad HEAD - I need a HEAD"
start_head=''
case "$head" in case "$head" in
refs/heads/bisect) refs/heads/bisect)
if [ -s "$GIT_DIR/BISECT_START" ]; then if [ -s "$GIT_DIR/BISECT_START" ]; then
@ -78,7 +79,7 @@ bisect_start() {
# This error message should only be triggered by cogito usage, # This error message should only be triggered by cogito usage,
# and cogito users should understand it relates to cg-seek. # and cogito users should understand it relates to cg-seek.
[ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree" [ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
echo "${head#refs/heads/}" >"$GIT_DIR/BISECT_START" start_head="${head#refs/heads/}"
;; ;;
*) *)
die "Bad HEAD - strange symbolic ref" die "Bad HEAD - strange symbolic ref"
@ -99,6 +100,7 @@ bisect_start() {
done done
orig_args=$(sq "$@") orig_args=$(sq "$@")
bad_seen=0 bad_seen=0
eval=''
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
arg="$1" arg="$1"
case "$arg" in case "$arg" in
@ -116,13 +118,15 @@ bisect_start() {
0) state='bad' ; bad_seen=1 ;; 0) state='bad' ; bad_seen=1 ;;
*) state='good' ;; *) state='good' ;;
esac esac
bisect_write "$state" "$rev" 'nolog' eval="$eval bisect_write '$state' '$rev' 'nolog'; "
shift shift
;; ;;
esac esac
done done
sq "$@" >"$GIT_DIR/BISECT_NAMES" sq "$@" >"$GIT_DIR/BISECT_NAMES"
test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START"
eval "$eval"
echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
bisect_auto_next bisect_auto_next
} }
@ -153,12 +157,14 @@ bisect_state() {
bisect_write "$state" "$rev" ;; bisect_write "$state" "$rev" ;;
2,bad|*,good|*,skip) 2,bad|*,good|*,skip)
shift shift
eval=''
for rev in "$@" for rev in "$@"
do do
sha=$(git rev-parse --verify "$rev^{commit}") || sha=$(git rev-parse --verify "$rev^{commit}") ||
die "Bad rev input: $rev" die "Bad rev input: $rev"
bisect_write "$state" "$sha" eval="$eval bisect_write '$state' '$sha'; "
done ;; done
eval "$eval" ;;
*,bad) *,bad)
die "'git bisect bad' can take only one argument." ;; die "'git bisect bad' can take only one argument." ;;
*) *)

View File

@ -71,8 +71,12 @@ test_expect_success 'bisect start with one bad and good' '
git bisect next git bisect next
' '
test_expect_success 'bisect good and bad fails if not given only revs' ' test_expect_success 'bisect fails if given any junk instead of revs' '
git bisect reset && git bisect reset &&
test_must_fail git bisect start foo $HASH1 -- &&
test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
test -z "$(git for-each-ref "refs/bisect/*")" &&
test_must_fail ls .git/BISECT_* &&
git bisect start && git bisect start &&
test_must_fail git bisect good foo $HASH1 && test_must_fail git bisect good foo $HASH1 &&
test_must_fail git bisect good $HASH1 bar && test_must_fail git bisect good $HASH1 bar &&
@ -80,6 +84,7 @@ test_expect_success 'bisect good and bad fails if not given only revs' '
test_must_fail git bisect bad $HASH3 $HASH4 && test_must_fail git bisect bad $HASH3 $HASH4 &&
test_must_fail git bisect skip bar $HASH3 && test_must_fail git bisect skip bar $HASH3 &&
test_must_fail git bisect skip $HASH1 foo && test_must_fail git bisect skip $HASH1 foo &&
test -z "$(git for-each-ref "refs/bisect/*")" &&
git bisect good $HASH1 && git bisect good $HASH1 &&
git bisect bad $HASH4 git bisect bad $HASH4
' '