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