git-rebase.shon commit add replay and log to the usage string of git-bisect (4ef40cd)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Junio C Hamano.
   4#
   5
   6USAGE='[-v] [--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
  31SUBDIRECTORY_OK=Yes
  32. git-sh-setup
  33set_reflog_action rebase
  34require_work_tree
  35cd_to_toplevel
  36
  37RESOLVEMSG="
  38When you have resolved this problem run \"git rebase --continue\".
  39If you would prefer to skip this patch, instead run \"git rebase --skip\".
  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
  47verbose=
  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        hd=$(git-rev-parse --verify HEAD)
  89        cmt_name=$(git-symbolic-ref HEAD)
  90        msgnum=$(cat $dotest/msgnum)
  91        end=$(cat $dotest/end)
  92        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
  93        eval GITHEAD_$hd='"$(cat $dotest/onto_name)"'
  94        export GITHEAD_$cmt GITHEAD_$hd
  95        git-merge-$strategy "$cmt^" -- "$hd" "$cmt"
  96        rv=$?
  97        case "$rv" in
  98        0)
  99                unset GITHEAD_$cmt GITHEAD_$hd
 100                return
 101                ;;
 102        1)
 103                test -d "$GIT_DIR/rr-cache" && git-rerere
 104                die "$RESOLVEMSG"
 105                ;;
 106        2)
 107                echo "Strategy: $rv $strategy failed, try another" 1>&2
 108                die "$RESOLVEMSG"
 109                ;;
 110        *)
 111                die "Unknown exit code ($rv) from command:" \
 112                        "git-merge-$strategy $cmt^ -- HEAD $cmt"
 113                ;;
 114        esac
 115}
 116
 117finish_rb_merge () {
 118        rm -r "$dotest"
 119        echo "All done."
 120}
 121
 122while case "$#" in 0) break ;; esac
 123do
 124        case "$1" in
 125        --continue)
 126                diff=$(git-diff-files)
 127                case "$diff" in
 128                ?*)     echo "You must edit all merge conflicts and then"
 129                        echo "mark them as resolved using git update-index"
 130                        exit 1
 131                        ;;
 132                esac
 133                if test -d "$dotest"
 134                then
 135                        prev_head="`cat $dotest/prev_head`"
 136                        end="`cat $dotest/end`"
 137                        msgnum="`cat $dotest/msgnum`"
 138                        onto="`cat $dotest/onto`"
 139                        continue_merge
 140                        while test "$msgnum" -le "$end"
 141                        do
 142                                call_merge "$msgnum"
 143                                continue_merge
 144                        done
 145                        finish_rb_merge
 146                        exit
 147                fi
 148                git am --resolved --3way --resolvemsg="$RESOLVEMSG"
 149                exit
 150                ;;
 151        --skip)
 152                if test -d "$dotest"
 153                then
 154                        if test -d "$GIT_DIR/rr-cache"
 155                        then
 156                                git-rerere clear
 157                        fi
 158                        prev_head="`cat $dotest/prev_head`"
 159                        end="`cat $dotest/end`"
 160                        msgnum="`cat $dotest/msgnum`"
 161                        msgnum=$(($msgnum + 1))
 162                        onto="`cat $dotest/onto`"
 163                        while test "$msgnum" -le "$end"
 164                        do
 165                                call_merge "$msgnum"
 166                                continue_merge
 167                        done
 168                        finish_rb_merge
 169                        exit
 170                fi
 171                git am -3 --skip --resolvemsg="$RESOLVEMSG"
 172                exit
 173                ;;
 174        --abort)
 175                if test -d "$GIT_DIR/rr-cache"
 176                then
 177                        git-rerere clear
 178                fi
 179                if test -d "$dotest"
 180                then
 181                        rm -r "$dotest"
 182                elif test -d .dotest
 183                then
 184                        rm -r .dotest
 185                else
 186                        die "No rebase in progress?"
 187                fi
 188                git reset --hard ORIG_HEAD
 189                exit
 190                ;;
 191        --onto)
 192                test 2 -le "$#" || usage
 193                newbase="$2"
 194                shift
 195                ;;
 196        -M|-m|--m|--me|--mer|--merg|--merge)
 197                do_merge=t
 198                ;;
 199        -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
 200                --strateg=*|--strategy=*|\
 201        -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
 202                case "$#,$1" in
 203                *,*=*)
 204                        strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
 205                1,*)
 206                        usage ;;
 207                *)
 208                        strategy="$2"
 209                        shift ;;
 210                esac
 211                do_merge=t
 212                ;;
 213        -v|--verbose)
 214                verbose=t
 215                ;;
 216        -*)
 217                usage
 218                ;;
 219        *)
 220                break
 221                ;;
 222        esac
 223        shift
 224done
 225
 226# Make sure we do not have .dotest
 227if test -z "$do_merge"
 228then
 229        if mkdir .dotest
 230        then
 231                rmdir .dotest
 232        else
 233                echo >&2 '
 234It seems that I cannot create a .dotest directory, and I wonder if you
 235are in the middle of patch application or another rebase.  If that is not
 236the case, please rm -fr .dotest and run me again.  I am stopping in case
 237you still have something valuable there.'
 238                exit 1
 239        fi
 240else
 241        if test -d "$dotest"
 242        then
 243                die "previous dotest directory $dotest still exists." \
 244                        'try git-rebase < --continue | --abort >'
 245        fi
 246fi
 247
 248# The tree must be really really clean.
 249git-update-index --refresh || exit
 250diff=$(git-diff-index --cached --name-status -r HEAD)
 251case "$diff" in
 252?*)     echo "cannot rebase: your index is not up-to-date"
 253        echo "$diff"
 254        exit 1
 255        ;;
 256esac
 257
 258# The upstream head must be given.  Make sure it is valid.
 259upstream_name="$1"
 260upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 261    die "invalid upstream $upstream_name"
 262
 263# If a hook exists, give it a chance to interrupt
 264if test -x "$GIT_DIR/hooks/pre-rebase"
 265then
 266        "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
 267                echo >&2 "The pre-rebase hook refused to rebase."
 268                exit 1
 269        }
 270fi
 271
 272# If the branch to rebase is given, first switch to it.
 273case "$#" in
 2742)
 275        branch_name="$2"
 276        git-checkout "$2" || usage
 277        ;;
 278*)
 279        if branch_name=`git symbolic-ref -q HEAD`
 280        then
 281                branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
 282        else
 283                branch_name=HEAD ;# detached
 284        fi
 285        ;;
 286esac
 287branch=$(git-rev-parse --verify "${branch_name}^0") || exit
 288
 289# Make sure the branch to rebase onto is valid.
 290onto_name=${newbase-"$upstream_name"}
 291onto=$(git-rev-parse --verify "${onto_name}^0") || exit
 292
 293# Now we are rebasing commits $upstream..$branch on top of $onto
 294
 295# Check if we are already based on $onto, but this should be
 296# done only when upstream and onto are the same.
 297mb=$(git-merge-base "$onto" "$branch")
 298if test "$upstream" = "$onto" && test "$mb" = "$onto"
 299then
 300        echo >&2 "Current branch $branch_name is up to date."
 301        exit 0
 302fi
 303
 304if test -n "$verbose"
 305then
 306        echo "Changes from $mb to $onto:"
 307        git-diff-tree --stat --summary "$mb" "$onto"
 308fi
 309
 310# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 311echo "First, rewinding head to replay your work on top of it..."
 312git-reset --hard "$onto"
 313
 314# If the $onto is a proper descendant of the tip of the branch, then
 315# we just fast forwarded.
 316if test "$mb" = "$branch"
 317then
 318        echo >&2 "Fast-forwarded $branch_name to $onto_name."
 319        exit 0
 320fi
 321
 322if test -z "$do_merge"
 323then
 324        git-format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
 325        git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
 326        exit $?
 327fi
 328
 329# start doing a rebase with git-merge
 330# this is rename-aware if the recursive (default) strategy is used
 331
 332mkdir -p "$dotest"
 333echo "$onto" > "$dotest/onto"
 334echo "$onto_name" > "$dotest/onto_name"
 335prev_head=`git-rev-parse HEAD^0`
 336echo "$prev_head" > "$dotest/prev_head"
 337
 338msgnum=0
 339for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \
 340                        | @@PERL@@ -e 'print reverse <>'`
 341do
 342        msgnum=$(($msgnum + 1))
 343        echo "$cmt" > "$dotest/cmt.$msgnum"
 344done
 345
 346echo 1 >"$dotest/msgnum"
 347echo $msgnum >"$dotest/end"
 348
 349end=$msgnum
 350msgnum=1
 351
 352while test "$msgnum" -le "$end"
 353do
 354        call_merge "$msgnum"
 355        continue_merge
 356done
 357
 358finish_rb_merge