git-bisect-scripton commit Document "git cherry-pick" and "git revert" (de2b82c)
   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        nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
 109        if [ "$nr" -le "1" ]; then
 110            echo "$rev is first bad commit"
 111            git-diff-tree --pretty $rev
 112            exit 0
 113        fi
 114        echo "Bisecting: $nr revisions left to test after this"
 115        echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
 116        git checkout new-bisect || exit
 117        mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
 118        ln -sf refs/heads/bisect "$GIT_DIR/HEAD"
 119}
 120
 121bisect_reset() {
 122        case "$#" in
 123        0) branch=master ;;
 124        1) test -f "$GIT_DIR/refs/heads/$1" || {
 125               echo >&2 "$1 does not seem to be a valid branch"
 126               exit 1
 127           }
 128           branch="$1" ;;
 129        *)
 130            usage ;;
 131        esac
 132        git checkout "$branch" &&
 133        rm -fr "$GIT_DIR/refs/bisect"
 134        rm -f "$GIT_DIR/refs/reads/bisect"
 135}
 136
 137case "$#" in
 1380)
 139    usage ;;
 140*)
 141    cmd="$1"
 142    shift
 143    case "$cmd" in
 144    start)
 145        bisect_start "$@" ;;
 146    bad)
 147        bisect_bad "$@" ;;
 148    good)
 149        bisect_good "$@" ;;
 150    next)
 151        # Not sure we want "next" at the UI level anymore.
 152        bisect_next "$@" ;;
 153    reset)
 154        bisect_reset "$@" ;;
 155    *)
 156        usage ;;
 157    esac
 158esac