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