git-rebase.shon commit Makefile: git-merge-recur depends on xdiff libraries. (a060b80)
   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                exit
 142                ;;
 143        --skip)
 144                if test -d "$dotest"
 145                then
 146                        prev_head="`cat $dotest/prev_head`"
 147                        end="`cat $dotest/end`"
 148                        msgnum="`cat $dotest/msgnum`"
 149                        msgnum=$(($msgnum + 1))
 150                        onto="`cat $dotest/onto`"
 151                        while test "$msgnum" -le "$end"
 152                        do
 153                                call_merge "$msgnum"
 154                                continue_merge
 155                        done
 156                        finish_rb_merge
 157                        exit
 158                fi
 159                git am -3 --skip --resolvemsg="$RESOLVEMSG"
 160                exit
 161                ;;
 162        --abort)
 163                if test -d "$dotest"
 164                then
 165                        rm -r "$dotest"
 166                elif test -d .dotest
 167                then
 168                        rm -r .dotest
 169                else
 170                        die "No rebase in progress?"
 171                fi
 172                git reset --hard ORIG_HEAD
 173                exit
 174                ;;
 175        --onto)
 176                test 2 -le "$#" || usage
 177                newbase="$2"
 178                shift
 179                ;;
 180        -M|-m|--m|--me|--mer|--merg|--merge)
 181                do_merge=t
 182                ;;
 183        -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
 184                --strateg=*|--strategy=*|\
 185        -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
 186                case "$#,$1" in
 187                *,*=*)
 188                        strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
 189                1,*)
 190                        usage ;;
 191                *)
 192                        strategy="$2"
 193                        shift ;;
 194                esac
 195                do_merge=t
 196                ;;
 197        -*)
 198                usage
 199                ;;
 200        *)
 201                break
 202                ;;
 203        esac
 204        shift
 205done
 206
 207case "$strategy,${GIT_USE_RECUR_FOR_RECURSIVE}" in
 208recursive,?*)
 209        strategy=recur ;;
 210esac
 211
 212# Make sure we do not have .dotest
 213if test -z "$do_merge"
 214then
 215        if mkdir .dotest
 216        then
 217                rmdir .dotest
 218        else
 219                echo >&2 '
 220It seems that I cannot create a .dotest directory, and I wonder if you
 221are in the middle of patch application or another rebase.  If that is not
 222the case, please rm -fr .dotest and run me again.  I am stopping in case
 223you still have something valuable there.'
 224                exit 1
 225        fi
 226else
 227        if test -d "$dotest"
 228        then
 229                die "previous dotest directory $dotest still exists." \
 230                        'try git-rebase < --continue | --abort >'
 231        fi
 232fi
 233
 234# The tree must be really really clean.
 235git-update-index --refresh || exit
 236diff=$(git-diff-index --cached --name-status -r HEAD)
 237case "$diff" in
 238?*)     echo "$diff"
 239        exit 1
 240        ;;
 241esac
 242
 243# The upstream head must be given.  Make sure it is valid.
 244upstream_name="$1"
 245upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 246    die "invalid upstream $upstream_name"
 247
 248# If a hook exists, give it a chance to interrupt
 249if test -x "$GIT_DIR/hooks/pre-rebase"
 250then
 251        "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
 252                echo >&2 "The pre-rebase hook refused to rebase."
 253                exit 1
 254        }
 255fi
 256
 257# If the branch to rebase is given, first switch to it.
 258case "$#" in
 2592)
 260        branch_name="$2"
 261        git-checkout "$2" || usage
 262        ;;
 263*)
 264        branch_name=`git symbolic-ref HEAD` || die "No current branch"
 265        branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
 266        ;;
 267esac
 268branch=$(git-rev-parse --verify "${branch_name}^0") || exit
 269
 270# Make sure the branch to rebase onto is valid.
 271onto_name=${newbase-"$upstream_name"}
 272onto=$(git-rev-parse --verify "${onto_name}^0") || exit
 273
 274# Now we are rebasing commits $upstream..$branch on top of $onto
 275
 276# Check if we are already based on $onto, but this should be
 277# done only when upstream and onto are the same.
 278if test "$upstream" = "$onto"
 279then
 280        mb=$(git-merge-base "$onto" "$branch")
 281        if test "$mb" = "$onto"
 282        then
 283                echo >&2 "Current branch $branch_name is up to date."
 284                exit 0
 285        fi
 286fi
 287
 288# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 289git-reset --hard "$onto"
 290
 291# If the $onto is a proper descendant of the tip of the branch, then
 292# we just fast forwarded.
 293if test "$mb" = "$onto"
 294then
 295        echo >&2 "Fast-forwarded $branch to $newbase."
 296        exit 0
 297fi
 298
 299if test -z "$do_merge"
 300then
 301        git-format-patch -k --stdout --full-index "$upstream"..ORIG_HEAD |
 302        git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
 303        exit $?
 304fi
 305
 306if test "@@NO_PYTHON@@" && test "$strategy" = "recursive"
 307then
 308        die 'The recursive merge strategy currently relies on Python,
 309which this installation of git was not configured with.  Please consider
 310a different merge strategy (e.g. octopus, resolve, stupid, ours)
 311or install Python and git with Python support.'
 312
 313fi
 314
 315# start doing a rebase with git-merge
 316# this is rename-aware if the recursive (default) strategy is used
 317
 318mkdir -p "$dotest"
 319echo "$onto" > "$dotest/onto"
 320prev_head=`git-rev-parse HEAD^0`
 321echo "$prev_head" > "$dotest/prev_head"
 322
 323msgnum=0
 324for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \
 325                        | @@PERL@@ -e 'print reverse <>'`
 326do
 327        msgnum=$(($msgnum + 1))
 328        echo "$cmt" > "$dotest/cmt.$msgnum"
 329done
 330
 331echo 1 >"$dotest/msgnum"
 332echo $msgnum >"$dotest/end"
 333
 334end=$msgnum
 335msgnum=1
 336
 337while test "$msgnum" -le "$end"
 338do
 339        call_merge "$msgnum"
 340        continue_merge
 341done
 342
 343finish_rb_merge