git-rebase.shon commit merge-recur: do not call git-write-tree (5b982f8)
   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"
  37unset newbase
  38case "${GIT_USE_RECUR_FOR_RECURSIVE}" in
  39'')
  40        strategy=recursive ;;
  41?*)
  42        strategy=recur ;;
  43esac
  44
  45do_merge=
  46dotest=$GIT_DIR/.dotest-merge
  47prec=4
  48
  49continue_merge () {
  50        test -n "$prev_head" || die "prev_head must be defined"
  51        test -d "$dotest" || die "$dotest directory does not exist"
  52
  53        unmerged=$(git-ls-files -u)
  54        if test -n "$unmerged"
  55        then
  56                echo "You still have unmerged paths in your index"
  57                echo "did you forget update-index?"
  58                die "$RESOLVEMSG"
  59        fi
  60
  61        if test -n "`git-diff-index HEAD`"
  62        then
  63                if ! git-commit -C "`cat $dotest/current`"
  64                then
  65                        echo "Commit failed, please do not call \"git commit\""
  66                        echo "directly, but instead do one of the following: "
  67                        die "$RESOLVEMSG"
  68                fi
  69                printf "Committed: %0${prec}d" $msgnum
  70        else
  71                printf "Already applied: %0${prec}d" $msgnum
  72        fi
  73        echo ' '`git-rev-list --pretty=oneline -1 HEAD | \
  74                                sed 's/^[a-f0-9]\+ //'`
  75
  76        prev_head=`git-rev-parse HEAD^0`
  77        # save the resulting commit so we can read-tree on it later
  78        echo "$prev_head" > "$dotest/prev_head"
  79
  80        # onto the next patch:
  81        msgnum=$(($msgnum + 1))
  82        echo "$msgnum" >"$dotest/msgnum"
  83}
  84
  85call_merge () {
  86        cmt="$(cat $dotest/cmt.$1)"
  87        echo "$cmt" > "$dotest/current"
  88        git-merge-$strategy "$cmt^" -- HEAD "$cmt"
  89        rv=$?
  90        case "$rv" in
  91        0)
  92                return
  93                ;;
  94        1)
  95                test -d "$GIT_DIR/rr-cache" && git-rerere
  96                die "$RESOLVEMSG"
  97                ;;
  98        2)
  99                echo "Strategy: $rv $strategy failed, try another" 1>&2
 100                die "$RESOLVEMSG"
 101                ;;
 102        *)
 103                die "Unknown exit code ($rv) from command:" \
 104                        "git-merge-$strategy $cmt^ -- HEAD $cmt"
 105                ;;
 106        esac
 107}
 108
 109finish_rb_merge () {
 110        rm -r "$dotest"
 111        echo "All done."
 112}
 113
 114while case "$#" in 0) break ;; esac
 115do
 116        case "$1" in
 117        --continue)
 118                diff=$(git-diff-files)
 119                case "$diff" in
 120                ?*)     echo "You must edit all merge conflicts and then"
 121                        echo "mark them as resolved using git update-index"
 122                        exit 1
 123                        ;;
 124                esac
 125                if test -d "$dotest"
 126                then
 127                        prev_head="`cat $dotest/prev_head`"
 128                        end="`cat $dotest/end`"
 129                        msgnum="`cat $dotest/msgnum`"
 130                        onto="`cat $dotest/onto`"
 131                        continue_merge
 132                        while test "$msgnum" -le "$end"
 133                        do
 134                                call_merge "$msgnum"
 135                                continue_merge
 136                        done
 137                        finish_rb_merge
 138                        exit
 139                fi
 140                git am --resolved --3way --resolvemsg="$RESOLVEMSG" \
 141                        --reflog-action=rebase
 142                exit
 143                ;;
 144        --skip)
 145                if test -d "$dotest"
 146                then
 147                        prev_head="`cat $dotest/prev_head`"
 148                        end="`cat $dotest/end`"
 149                        msgnum="`cat $dotest/msgnum`"
 150                        msgnum=$(($msgnum + 1))
 151                        onto="`cat $dotest/onto`"
 152                        while test "$msgnum" -le "$end"
 153                        do
 154                                call_merge "$msgnum"
 155                                continue_merge
 156                        done
 157                        finish_rb_merge
 158                        exit
 159                fi
 160                git am -3 --skip --resolvemsg="$RESOLVEMSG" \
 161                        --reflog-action=rebase
 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 "z$1" : 'z-[^=]*=\(.*\)'` ;;
 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
 209case "$strategy,${GIT_USE_RECUR_FOR_RECURSIVE}" in
 210recursive,?*)
 211        strategy=recur ;;
 212esac
 213
 214# Make sure we do not have .dotest
 215if test -z "$do_merge"
 216then
 217        if mkdir .dotest
 218        then
 219                rmdir .dotest
 220        else
 221                echo >&2 '
 222It seems that I cannot create a .dotest directory, and I wonder if you
 223are in the middle of patch application or another rebase.  If that is not
 224the case, please rm -fr .dotest and run me again.  I am stopping in case
 225you still have something valuable there.'
 226                exit 1
 227        fi
 228else
 229        if test -d "$dotest"
 230        then
 231                die "previous dotest directory $dotest still exists." \
 232                        'try git-rebase < --continue | --abort >'
 233        fi
 234fi
 235
 236# The tree must be really really clean.
 237git-update-index --refresh || exit
 238diff=$(git-diff-index --cached --name-status -r HEAD)
 239case "$diff" in
 240?*)     echo "$diff"
 241        exit 1
 242        ;;
 243esac
 244
 245# The upstream head must be given.  Make sure it is valid.
 246upstream_name="$1"
 247upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 248    die "invalid upstream $upstream_name"
 249
 250# If a hook exists, give it a chance to interrupt
 251if test -x "$GIT_DIR/hooks/pre-rebase"
 252then
 253        "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
 254                echo >&2 "The pre-rebase hook refused to rebase."
 255                exit 1
 256        }
 257fi
 258
 259# If the branch to rebase is given, first switch to it.
 260case "$#" in
 2612)
 262        branch_name="$2"
 263        git-checkout "$2" || usage
 264        ;;
 265*)
 266        branch_name=`git symbolic-ref HEAD` || die "No current branch"
 267        branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
 268        ;;
 269esac
 270branch=$(git-rev-parse --verify "${branch_name}^0") || exit
 271
 272# Make sure the branch to rebase onto is valid.
 273onto_name=${newbase-"$upstream_name"}
 274onto=$(git-rev-parse --verify "${onto_name}^0") || exit
 275
 276# Now we are rebasing commits $upstream..$branch on top of $onto
 277
 278# Check if we are already based on $onto, but this should be
 279# done only when upstream and onto are the same.
 280if test "$upstream" = "$onto"
 281then
 282        mb=$(git-merge-base "$onto" "$branch")
 283        if test "$mb" = "$onto"
 284        then
 285                echo >&2 "Current branch $branch_name is up to date."
 286                exit 0
 287        fi
 288fi
 289
 290# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 291git-reset --hard "$onto"
 292
 293# If the $onto is a proper descendant of the tip of the branch, then
 294# we just fast forwarded.
 295if test "$mb" = "$onto"
 296then
 297        echo >&2 "Fast-forwarded $branch to $newbase."
 298        exit 0
 299fi
 300
 301if test -z "$do_merge"
 302then
 303        git-format-patch -k --stdout --full-index "$upstream"..ORIG_HEAD |
 304        git am --binary -3 -k --resolvemsg="$RESOLVEMSG" \
 305                --reflog-action=rebase
 306        exit $?
 307fi
 308
 309if test "@@NO_PYTHON@@" && test "$strategy" = "recursive"
 310then
 311        die 'The recursive merge strategy currently relies on Python,
 312which this installation of git was not configured with.  Please consider
 313a different merge strategy (e.g. octopus, resolve, stupid, ours)
 314or install Python and git with Python support.'
 315
 316fi
 317
 318# start doing a rebase with git-merge
 319# this is rename-aware if the recursive (default) strategy is used
 320
 321mkdir -p "$dotest"
 322echo "$onto" > "$dotest/onto"
 323prev_head=`git-rev-parse HEAD^0`
 324echo "$prev_head" > "$dotest/prev_head"
 325
 326msgnum=0
 327for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \
 328                        | @@PERL@@ -e 'print reverse <>'`
 329do
 330        msgnum=$(($msgnum + 1))
 331        echo "$cmt" > "$dotest/cmt.$msgnum"
 332done
 333
 334echo 1 >"$dotest/msgnum"
 335echo $msgnum >"$dotest/end"
 336
 337end=$msgnum
 338msgnum=1
 339
 340while test "$msgnum" -le "$end"
 341do
 342        call_merge "$msgnum"
 343        continue_merge
 344done
 345
 346finish_rb_merge