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