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