git-rebase.shon commit rebase: error out for NO_PYTHON if they use recursive merge (693c15d)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Junio C Hamano.
   4#
   5
   6USAGE='[--onto <newbase>] <upstream> [<branch>]'
   7LONG_USAGE='git-rebase replaces <branch> with a new branch of the
   8same name.  When the --onto option is provided the new branch starts
   9out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
  10It then attempts to create a new commit for each commit from the original
  11<branch> that does not exist in the <upstream> branch.
  12
  13It is possible that a merge failure will prevent this process from being
  14completely automatic.  You will have to resolve any such merge failure
  15and run git rebase --continue.  Another option is to bypass the commit
  16that caused the merge failure with git rebase --skip.  To restore the
  17original <branch> and remove the .dotest working files, use the command
  18git rebase --abort instead.
  19
  20Note that if <branch> is not specified on the command line, the
  21currently checked out branch is used.  You must be in the top
  22directory of your project to start (or continue) a rebase.
  23
  24Example:       git-rebase master~1 topic
  25
  26        A---B---C topic                   A'\''--B'\''--C'\'' topic
  27       /                   -->           /
  28  D---E---F---G master          D---E---F---G master
  29'
  30. git-sh-setup
  31
  32RESOLVEMSG="
  33When you have resolved this problem run \"git rebase --continue\".
  34If you would prefer to skip this patch, instead run \"git rebase --skip\".
  35To restore the original branch and stop rebasing run \"git rebase --abort\".
  36"
  37
  38MRESOLVEMSG="
  39When you have resolved this problem run \"git rebase --continue\".
  40To restore the original branch and stop rebasing run \"git rebase --abort\".
  41"
  42unset newbase
  43strategy=recursive
  44do_merge=
  45dotest=$GIT_DIR/.dotest-merge
  46prec=4
  47
  48continue_merge () {
  49        test -n "$prev_head" || die "prev_head must be defined"
  50        test -d "$dotest" || die "$dotest directory does not exist"
  51
  52        unmerged=$(git-ls-files -u)
  53        if test -n "$unmerged"
  54        then
  55                echo "You still have unmerged paths in your index"
  56                echo "did you forget update-index?"
  57                die "$MRESOLVEMSG"
  58        fi
  59
  60        if test -n "`git-diff-index HEAD`"
  61        then
  62                git-commit -C "`cat $dotest/current`"
  63        else
  64                echo "Previous merge succeeded automatically"
  65        fi
  66
  67        prev_head=`git-rev-parse HEAD^0`
  68
  69        # save the resulting commit so we can read-tree on it later
  70        echo "$prev_head" > "$dotest/`printf %0${prec}d $msgnum`.result"
  71        echo "$prev_head" > "$dotest/prev_head"
  72
  73        # onto the next patch:
  74        msgnum=$(($msgnum + 1))
  75        printf "%0${prec}d" "$msgnum" > "$dotest/msgnum"
  76}
  77
  78call_merge () {
  79        cmt="$(cat $dotest/`printf %0${prec}d $1`)"
  80        echo "$cmt" > "$dotest/current"
  81        git-merge-$strategy "$cmt^" -- HEAD "$cmt"
  82        rv=$?
  83        case "$rv" in
  84        0)
  85                git-commit -C "$cmt" || die "commit failed: $MRESOLVEMSG"
  86                ;;
  87        1)
  88                test -d "$GIT_DIR/rr-cache" && git-rerere
  89                die "$MRESOLVEMSG"
  90                ;;
  91        2)
  92                echo "Strategy: $rv $strategy failed, try another" 1>&2
  93                die "$MRESOLVEMSG"
  94                ;;
  95        *)
  96                die "Unknown exit code ($rv) from command:" \
  97                        "git-merge-$strategy $cmt^ -- HEAD $cmt"
  98                ;;
  99        esac
 100}
 101
 102finish_rb_merge () {
 103        set -e
 104
 105        msgnum=1
 106        echo "Finalizing rebased commits..."
 107        git-reset --hard "`cat $dotest/onto`"
 108        end="`cat $dotest/end`"
 109        while test "$msgnum" -le "$end"
 110        do
 111                msgnum=`printf "%0${prec}d" "$msgnum"`
 112                printf "%0${prec}d" "$msgnum" > "$dotest/msgnum"
 113
 114                git-read-tree `cat "$dotest/$msgnum.result"`
 115                git-checkout-index -q -f -u -a
 116                git-commit -C "`cat $dotest/$msgnum`"
 117
 118                echo "Committed $msgnum"
 119                echo '    '`git-rev-list --pretty=oneline -1 HEAD | \
 120                                        sed 's/^[a-f0-9]\+ //'`
 121                msgnum=$(($msgnum + 1))
 122        done
 123        rm -r "$dotest"
 124        echo "All done."
 125}
 126
 127while case "$#" in 0) break ;; esac
 128do
 129        case "$1" in
 130        --continue)
 131                diff=$(git-diff-files)
 132                case "$diff" in
 133                ?*)     echo "You must edit all merge conflicts and then"
 134                        echo "mark them as resolved using git update-index"
 135                        exit 1
 136                        ;;
 137                esac
 138                if test -d "$dotest"
 139                then
 140                        prev_head="`cat $dotest/prev_head`"
 141                        end="`cat $dotest/end`"
 142                        msgnum="`cat $dotest/msgnum`"
 143                        onto="`cat $dotest/onto`"
 144                        continue_merge
 145                        while test "$msgnum" -le "$end"
 146                        do
 147                                call_merge "$msgnum"
 148                                continue_merge
 149                        done
 150                        finish_rb_merge
 151                        exit
 152                fi
 153                git am --resolved --3way --resolvemsg="$RESOLVEMSG"
 154                exit
 155                ;;
 156        --skip)
 157                if test -d "$dotest"
 158                then
 159                        die "--skip is not supported when using --merge"
 160                fi
 161                git am -3 --skip --resolvemsg="$RESOLVEMSG"
 162                exit
 163                ;;
 164        --abort)
 165                if test -d "$dotest"
 166                then
 167                        rm -r "$dotest"
 168                elif test -d .dotest
 169                then
 170                        rm -r .dotest
 171                else
 172                        die "No rebase in progress?"
 173                fi
 174                git reset --hard ORIG_HEAD
 175                exit
 176                ;;
 177        --onto)
 178                test 2 -le "$#" || usage
 179                newbase="$2"
 180                shift
 181                ;;
 182        -M|-m|--m|--me|--mer|--merg|--merge)
 183                do_merge=t
 184                ;;
 185        -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
 186                --strateg=*|--strategy=*|\
 187        -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
 188                case "$#,$1" in
 189                *,*=*)
 190                        strategy=`expr "$1" : '-[^=]*=\(.*\)'` ;;
 191                1,*)
 192                        usage ;;
 193                *)
 194                        strategy="$2"
 195                        shift ;;
 196                esac
 197                do_merge=t
 198                ;;
 199        -*)
 200                usage
 201                ;;
 202        *)
 203                break
 204                ;;
 205        esac
 206        shift
 207done
 208
 209# Make sure we do not have .dotest
 210if test -z "$do_merge"
 211then
 212        if mkdir .dotest
 213        then
 214                rmdir .dotest
 215        else
 216                echo >&2 '
 217It seems that I cannot create a .dotest directory, and I wonder if you
 218are in the middle of patch application or another rebase.  If that is not
 219the case, please rm -fr .dotest and run me again.  I am stopping in case
 220you still have something valuable there.'
 221                exit 1
 222        fi
 223else
 224        if test -d "$dotest"
 225        then
 226                die "previous dotest directory $dotest still exists." \
 227                        'try git-rebase < --continue | --abort >'
 228        fi
 229fi
 230
 231# The tree must be really really clean.
 232git-update-index --refresh || exit
 233diff=$(git-diff-index --cached --name-status -r HEAD)
 234case "$diff" in
 235?*)     echo "$diff"
 236        exit 1
 237        ;;
 238esac
 239
 240# The upstream head must be given.  Make sure it is valid.
 241upstream_name="$1"
 242upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 243    die "invalid upstream $upstream_name"
 244
 245# If a hook exists, give it a chance to interrupt
 246if test -x "$GIT_DIR/hooks/pre-rebase"
 247then
 248        "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
 249                echo >&2 "The pre-rebase hook refused to rebase."
 250                exit 1
 251        }
 252fi
 253
 254# If the branch to rebase is given, first switch to it.
 255case "$#" in
 2562)
 257        branch_name="$2"
 258        git-checkout "$2" || usage
 259        ;;
 260*)
 261        branch_name=`git symbolic-ref HEAD` || die "No current branch"
 262        branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
 263        ;;
 264esac
 265branch=$(git-rev-parse --verify "${branch_name}^0") || exit
 266
 267# Make sure the branch to rebase onto is valid.
 268onto_name=${newbase-"$upstream_name"}
 269onto=$(git-rev-parse --verify "${onto_name}^0") || exit
 270
 271# Now we are rebasing commits $upstream..$branch on top of $onto
 272
 273# Check if we are already based on $onto, but this should be
 274# done only when upstream and onto are the same.
 275if test "$upstream" = "$onto"
 276then
 277        mb=$(git-merge-base "$onto" "$branch")
 278        if test "$mb" = "$onto"
 279        then
 280                echo >&2 "Current branch $branch_name is up to date."
 281                exit 0
 282        fi
 283fi
 284
 285# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 286git-reset --hard "$onto"
 287
 288# If the $onto is a proper descendant of the tip of the branch, then
 289# we just fast forwarded.
 290if test "$mb" = "$onto"
 291then
 292        echo >&2 "Fast-forwarded $branch to $newbase."
 293        exit 0
 294fi
 295
 296if test -z "$do_merge"
 297then
 298        git-format-patch -k --stdout --full-index "$upstream"..ORIG_HEAD |
 299        git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
 300        exit $?
 301fi
 302
 303if test "@@NO_PYTHON@@" && test "$strategy" = "recursive"
 304then
 305        die 'The recursive merge strategy currently relies on Python,
 306which this installation of git was not configured with.  Please consider
 307a different merge strategy (e.g. octopus, resolve, stupid, ours)
 308or install Python and git with Python support.'
 309
 310fi
 311
 312# start doing a rebase with git-merge
 313# this is rename-aware if the recursive (default) strategy is used
 314
 315mkdir -p "$dotest"
 316echo "$onto" > "$dotest/onto"
 317prev_head=`git-rev-parse HEAD^0`
 318echo "$prev_head" > "$dotest/prev_head"
 319
 320msgnum=0
 321for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \
 322                        | perl -e 'print reverse <>'`
 323do
 324        msgnum=$(($msgnum + 1))
 325        echo "$cmt" > "$dotest/`printf "%0${prec}d" $msgnum`"
 326done
 327
 328printf "%0${prec}d" 1 > "$dotest/msgnum"
 329printf "%0${prec}d" "$msgnum" > "$dotest/end"
 330
 331end=$msgnum
 332msgnum=1
 333
 334while test "$msgnum" -le "$end"
 335do
 336        call_merge "$msgnum"
 337        continue_merge
 338done
 339
 340finish_rb_merge