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