git-bisect-scripton commit [PATCH] Fix bisection terminating condition (670f5fe)
   1#!/bin/sh
   2. git-sh-setup-script || dir "Not a git archive"
   3
   4usage() {
   5    echo >&2 'usage: git bisect [start | bad | good | next | reset]
   6git bisect start                reset bisect state and start bisection.
   7git bisect bad [<rev>]          mark <rev> a known-bad revision.
   8git bisect good [<rev>...]      mark <rev>... known-good revisions.
   9git bisect next                 find next bisection to test and check it out.
  10git bisect reset [<branch>]     finish bisection search and go back to branch.'
  11    exit 1
  12}
  13
  14bisect_autostart() {
  15        test -d "$GIT_DIR/refs/bisect" || {
  16                echo >&2 'You need to start by "git bisect start"'
  17                if test -t 0
  18                then
  19                        echo >&2 -n 'Do you want me to do it for you [Y/n]? '
  20                        read yesno
  21                        case "$yesno" in
  22                        [Nn]*)
  23                                exit ;;
  24                        esac
  25                        bisect_start
  26                else
  27                        exit 1
  28                fi
  29        }
  30}
  31
  32bisect_start() {
  33        case "$#" in 0) ;; *) usage ;; esac
  34        #
  35        # Verify HEAD. If we were bisecting before this, reset to the
  36        # top-of-line master first!
  37        #
  38        head=$(readlink $GIT_DIR/HEAD) || die "Bad HEAD - I need a symlink"
  39        case "$head" in
  40        refs/heads/bisect*)
  41                git checkout master || exit
  42                ;;
  43        refs/heads/*)
  44                ;;
  45        *)
  46                die "Bad HEAD - strange symlink"
  47                ;;
  48        esac
  49
  50        #
  51        # Get rid of any old bisect state
  52        #
  53        rm -f "$GIT_DIR/refs/heads/bisect"
  54        rm -rf "$GIT_DIR/refs/bisect/"
  55        mkdir "$GIT_DIR/refs/bisect"
  56}
  57
  58bisect_bad() {
  59        bisect_autostart
  60        case "$#" in 0 | 1) ;; *) usage ;; esac
  61        rev=$(git-rev-parse --verify --default HEAD "$@") || exit
  62        echo "$rev" > "$GIT_DIR/refs/bisect/bad"
  63        bisect_auto_next
  64}
  65
  66bisect_good() {
  67        bisect_autostart
  68        case "$#" in
  69        0)    revs=$(git-rev-parse --verify HEAD) || exit ;;
  70        *)    revs=$(git-rev-parse --revs-only --no-flags "$@") || exit ;;
  71        esac
  72        for rev in $revs
  73        do
  74            echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
  75        done
  76        bisect_auto_next
  77}
  78
  79bisect_next_check() {
  80        next_ok=no
  81        test -f "$GIT_DIR/refs/bisect/bad" &&
  82        case "$(cd "$GIT_DIR" && echo refs/bisect/good-*)" in
  83        refs/bisect/good-\*) ;;
  84        *) next_ok=yes ;;
  85        esac
  86        case "$next_ok,$1" in
  87        no,) false ;;
  88        no,fail)
  89            echo >&2 'You need to give me at least one good and one bad revisions.'
  90            exit 1 ;;
  91        *)
  92            true ;;
  93        esac
  94}
  95
  96bisect_auto_next() {
  97        bisect_next_check && bisect_next
  98}
  99
 100bisect_next() {
 101        case "$#" in 0) ;; *) usage ;; esac
 102        bisect_autostart
 103        bisect_next_check fail
 104        bad=$(git-rev-parse --verify refs/bisect/bad) &&
 105        good=$(git-rev-parse --sq --revs-only --not \
 106                $(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
 107        rev=$(eval "git-rev-list --bisect $good $bad") || exit
 108        if [ -z "$rev" ]; then
 109            echo "$bad was both good and bad"
 110            exit 1
 111        fi
 112        if [ "$rev" = "$bad" ]; then
 113            echo "$rev is first bad commit"
 114            git-diff-tree --pretty $rev
 115            exit 0
 116        fi
 117        nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
 118        echo "Bisecting: $nr revisions left to test after this"
 119        echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
 120        git checkout new-bisect || exit
 121        mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
 122        ln -sf refs/heads/bisect "$GIT_DIR/HEAD"
 123}
 124
 125bisect_reset() {
 126        case "$#" in
 127        0) branch=master ;;
 128        1) test -f "$GIT_DIR/refs/heads/$1" || {
 129               echo >&2 "$1 does not seem to be a valid branch"
 130               exit 1
 131           }
 132           branch="$1" ;;
 133        *)
 134            usage ;;
 135        esac
 136        git checkout "$branch" &&
 137        rm -fr "$GIT_DIR/refs/bisect"
 138        rm -f "$GIT_DIR/refs/reads/bisect"
 139}
 140
 141case "$#" in
 1420)
 143    usage ;;
 144*)
 145    cmd="$1"
 146    shift
 147    case "$cmd" in
 148    start)
 149        bisect_start "$@" ;;
 150    bad)
 151        bisect_bad "$@" ;;
 152    good)
 153        bisect_good "$@" ;;
 154    next)
 155        # Not sure we want "next" at the UI level anymore.
 156        bisect_next "$@" ;;
 157    reset)
 158        bisect_reset "$@" ;;
 159    *)
 160        usage ;;
 161    esac
 162esac