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