git manpage: note git-security@googlegroups.com
[gitweb.git] / git-bisect.sh
index fcbed2263b7500570891054ebe9af6cfe99f4abf..54cbfecc5ab0531513ff9e069be55d74339ad427 100755 (executable)
@@ -1,21 +1,26 @@
 #!/bin/sh
 
-USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
+USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
 LONG_USAGE='git bisect help
        print this long help message.
-git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
+git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
+                [--no-checkout] [<bad> [<good>...]] [--] [<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 (bad|new) [<rev>]
+       mark <rev> a known-bad revision/
+               a revision after change in a given property.
+git bisect (good|old) [<rev>...]
+       mark <rev>... known-good revisions/
+               revisions before change in a given property.
+git bisect terms [--term-good | --term-bad]
+       show the terms used for old and new commits (default: bad, good)
 git bisect skip [(<rev>|<range>)...]
        mark <rev>... untestable revisions.
 git bisect next
        find next bisection to test and check it out.
 git bisect reset [<commit>]
        finish bisection search and go back to commit.
-git bisect visualize
+git bisect (visualize|view)
        show bisect status in gitk.
 git bisect replay <logfile>
        replay bisection log.
@@ -28,7 +33,6 @@ Please use "git help bisect" to get the full man page.'
 
 OPTIONS_SPEC=
 . git-sh-setup
-. git-sh-i18n
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
@@ -77,6 +81,8 @@ bisect_start() {
        orig_args=$(git rev-parse --sq-quote "$@")
        bad_seen=0
        eval=''
+       must_write_terms=0
+       revs=''
        if test "z$(git rev-parse --is-bare-repository)" != zfalse
        then
                mode=--no-checkout
@@ -93,6 +99,24 @@ bisect_start() {
                --no-checkout)
                        mode=--no-checkout
                        shift ;;
+               --term-good|--term-old)
+                       shift
+                       must_write_terms=1
+                       TERM_GOOD=$1
+                       shift ;;
+               --term-good=*|--term-old=*)
+                       must_write_terms=1
+                       TERM_GOOD=${1#*=}
+                       shift ;;
+               --term-bad|--term-new)
+                       shift
+                       must_write_terms=1
+                       TERM_BAD=$1
+                       shift ;;
+               --term-bad=*|--term-new=*)
+                       must_write_terms=1
+                       TERM_BAD=${1#*=}
+                       shift ;;
                --*)
                        die "$(eval_gettext "unrecognised option: '\$arg'")" ;;
                *)
@@ -101,16 +125,27 @@ bisect_start() {
                                die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
                                break
                        }
-                       case $bad_seen in
-                       0) state=$TERM_BAD ; bad_seen=1 ;;
-                       *) state=$TERM_GOOD ;;
-                       esac
-                       eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
+                       revs="$revs $rev"
                        shift
                        ;;
                esac
        done
 
+       for rev in $revs
+       do
+               # The user ran "git bisect start <sha1>
+               # <sha1>", hence did not explicitly specify
+               # the terms, but we are already starting to
+               # set references named with the default terms,
+               # and won't be able to change afterwards.
+               must_write_terms=1
+
+               case $bad_seen in
+               0) state=$TERM_BAD ; bad_seen=1 ;;
+               *) state=$TERM_GOOD ;;
+               esac
+               eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
+       done
        #
        # Verify HEAD.
        #
@@ -151,7 +186,7 @@ bisect_start() {
        #
        # Get rid of any old bisect state.
        #
-       bisect_clean_state || exit
+       git bisect--helper --bisect-clean-state || exit
 
        #
        # Change state.
@@ -160,7 +195,7 @@ bisect_start() {
        # We have to trap this to be able to clean up using
        # "bisect_clean_state".
        #
-       trap 'bisect_clean_state' 0
+       trap 'git bisect--helper --bisect-clean-state' 0
        trap 'exit 255' 1 2 3 15
 
        #
@@ -172,6 +207,10 @@ bisect_start() {
        } &&
        git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
        eval "$eval true" &&
+       if test $must_write_terms -eq 1
+       then
+               git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit
+       fi &&
        echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
        #
        # Check if we can proceed to the next bisect state.
@@ -198,22 +237,6 @@ bisect_write() {
        test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
 }
 
-is_expected_rev() {
-       test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
-       test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
-}
-
-check_expected_revs() {
-       for _rev in "$@"; do
-               if ! is_expected_rev "$_rev"
-               then
-                       rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
-                       rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
-                       return
-               fi
-       done
-}
-
 bisect_skip() {
        all=''
        for arg in "$@"
@@ -232,14 +255,16 @@ bisect_skip() {
 bisect_state() {
        bisect_autostart
        state=$1
+       check_and_set_terms $state
        case "$#,$state" in
        0,*)
-               die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
+               die "Please call 'bisect_state' with at least one argument." ;;
        1,"$TERM_BAD"|1,"$TERM_GOOD"|1,skip)
-               rev=$(git rev-parse --verify $(bisect_head)) ||
-                       die "$(gettext "Bad rev input: $(bisect_head)")"
+               bisected_head=$(bisect_head)
+               rev=$(git rev-parse --verify "$bisected_head") ||
+                       die "$(eval_gettext "Bad rev input: \$bisected_head")"
                bisect_write "$state" "$rev"
-               check_expected_revs "$rev" ;;
+               git bisect--helper --check-expected-revs "$rev" ;;
        2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
                shift
                hash_list=''
@@ -253,7 +278,7 @@ bisect_state() {
                do
                        bisect_write "$state" "$rev"
                done
-               check_expected_revs $hash_list ;;
+               git bisect--helper --check-expected-revs $hash_list ;;
        *,"$TERM_BAD")
                die "$(eval_gettext "'git bisect \$TERM_BAD' can take only one argument.")" ;;
        *)
@@ -276,7 +301,7 @@ bisect_next_check() {
                false
                ;;
        t,,"$TERM_GOOD")
-               # have bad but not good.  we could bisect although
+               # have bad (or new) but not good (or old).  we could bisect although
                # this is less optimum.
                eval_gettextln "Warning: bisecting only with a \$TERM_BAD commit." >&2
                if test -t 0
@@ -291,15 +316,17 @@ bisect_next_check() {
                : bisect without $TERM_GOOD...
                ;;
        *)
-
+               bad_syn=$(bisect_voc bad)
+               good_syn=$(bisect_voc good)
                if test -s "$GIT_DIR/BISECT_START"
                then
-                       gettextln "You need to give me at least one good and one bad revision.
-(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
+
+                       eval_gettextln "You need to give me at least one \$bad_syn and one \$good_syn revision.
+(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
                else
-                       gettextln "You need to start by \"git bisect start\".
-You then need to give me at least one good and one bad revision.
-(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
+                       eval_gettextln "You need to start by \"git bisect start\".
+You then need to give me at least one \$good_syn and one \$bad_syn revision.
+(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
                fi
                exit 1 ;;
        esac
@@ -387,26 +414,7 @@ bisect_reset() {
                die "$(eval_gettext "Could not check out original HEAD '\$branch'.
 Try 'git bisect reset <commit>'.")"
        fi
-       bisect_clean_state
-}
-
-bisect_clean_state() {
-       # There may be some refs packed during bisection.
-       git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
-       while read ref hash
-       do
-               git update-ref -d $ref $hash || exit
-       done
-       rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
-       rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
-       rm -f "$GIT_DIR/BISECT_LOG" &&
-       rm -f "$GIT_DIR/BISECT_NAMES" &&
-       rm -f "$GIT_DIR/BISECT_RUN" &&
-       # Cleanup head-name if it got left by an old version of git-bisect
-       rm -f "$GIT_DIR/head-name" &&
-       git update-ref -d --no-deref BISECT_HEAD &&
-       # clean up BISECT_START last
-       rm -f "$GIT_DIR/BISECT_START"
+       git bisect--helper --bisect-clean-state || exit
 }
 
 bisect_replay () {
@@ -422,12 +430,16 @@ bisect_replay () {
                        rev="$command"
                        command="$bisect"
                fi
+               get_terms
+               check_and_set_terms "$command"
                case "$command" in
                start)
                        cmd="bisect_start $rev"
                        eval "$cmd" ;;
-               $TERM_GOOD|$TERM_BAD|skip)
+               "$TERM_GOOD"|"$TERM_BAD"|skip)
                        bisect_write "$command" "$rev" ;;
+               terms)
+                       bisect_terms $rev ;;
                *)
                        die "$(gettext "?? what are you talking about?")" ;;
                esac
@@ -438,6 +450,8 @@ bisect_replay () {
 bisect_run () {
        bisect_next_check fail
 
+       test -n "$*" || die "$(gettext "bisect run failed: no command provided.")"
+
        while true
        do
                command="$@"
@@ -499,18 +513,97 @@ bisect_log () {
        cat "$GIT_DIR/BISECT_LOG"
 }
 
+get_terms () {
+       if test -s "$GIT_DIR/BISECT_TERMS"
+       then
+               {
+               read TERM_BAD
+               read TERM_GOOD
+               } <"$GIT_DIR/BISECT_TERMS"
+       fi
+}
+
+check_and_set_terms () {
+       cmd="$1"
+       case "$cmd" in
+       skip|start|terms) ;;
+       *)
+               if test -s "$GIT_DIR/BISECT_TERMS" && test "$cmd" != "$TERM_BAD" && test "$cmd" != "$TERM_GOOD"
+               then
+                       die "$(eval_gettext "Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"
+               fi
+               case "$cmd" in
+               bad|good)
+                       if ! test -s "$GIT_DIR/BISECT_TERMS"
+                       then
+                               TERM_BAD=bad
+                               TERM_GOOD=good
+                               git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit
+                       fi
+                       ;;
+               new|old)
+                       if ! test -s "$GIT_DIR/BISECT_TERMS"
+                       then
+                               TERM_BAD=new
+                               TERM_GOOD=old
+                               git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit
+                       fi
+                       ;;
+               esac ;;
+       esac
+}
+
+bisect_voc () {
+       case "$1" in
+       bad) echo "bad|new" ;;
+       good) echo "good|old" ;;
+       esac
+}
+
+bisect_terms () {
+       get_terms
+       if ! test -s "$GIT_DIR/BISECT_TERMS"
+       then
+               die "$(gettext "no terms defined")"
+       fi
+       case "$#" in
+       0)
+               gettextln "Your current terms are $TERM_GOOD for the old state
+and $TERM_BAD for the new state."
+               ;;
+       1)
+               arg=$1
+               case "$arg" in
+                       --term-good|--term-old)
+                               printf '%s\n' "$TERM_GOOD"
+                               ;;
+                       --term-bad|--term-new)
+                               printf '%s\n' "$TERM_BAD"
+                               ;;
+                       *)
+                               die "$(eval_gettext "invalid argument \$arg for 'git bisect terms'.
+Supported options are: --term-good|--term-old and --term-bad|--term-new.")"
+                               ;;
+               esac
+               ;;
+       *)
+               usage ;;
+       esac
+}
+
 case "$#" in
 0)
        usage ;;
 *)
        cmd="$1"
+       get_terms
        shift
        case "$cmd" in
        help)
                git bisect -h ;;
        start)
                bisect_start "$@" ;;
-       bad|good)
+       bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
                bisect_state "$cmd" "$@" ;;
        skip)
                bisect_skip "$@" ;;
@@ -527,6 +620,8 @@ case "$#" in
                bisect_log ;;
        run)
                bisect_run "$@" ;;
+       terms)
+               bisect_terms "$@" ;;
        *)
                usage ;;
        esac