git-p4: Support usage of perforce client spec
[gitweb.git] / git-rebase.sh
index e342974dc0c2d99a0ad4e93743e94f23cb9de63f..bdcea0ed703057e08fd4204245f4f0c8a308f8d0 100755 (executable)
@@ -29,6 +29,7 @@ Example:       git-rebase master~1 topic
 '
 
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 set_reflog_action rebase
 require_work_tree
@@ -59,8 +60,8 @@ continue_merge () {
                die "$RESOLVEMSG"
        fi
 
-       cmt=`cat $dotest/current`
-       if ! git diff-index --quiet HEAD
+       cmt=`cat "$dotest/current"`
+       if ! git diff-index --quiet HEAD --
        then
                if ! git-commit -C "$cmt"
                then
@@ -84,14 +85,14 @@ continue_merge () {
 }
 
 call_merge () {
-       cmt="$(cat $dotest/cmt.$1)"
+       cmt="$(cat "$dotest/cmt.$1")"
        echo "$cmt" > "$dotest/current"
        hd=$(git rev-parse --verify HEAD)
-       cmt_name=$(git symbolic-ref HEAD)
-       msgnum=$(cat $dotest/msgnum)
-       end=$(cat $dotest/end)
+       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
+       msgnum=$(cat "$dotest/msgnum")
+       end=$(cat "$dotest/end")
        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
-       eval GITHEAD_$hd='"$(cat $dotest/onto_name)"'
+       eval GITHEAD_$hd='$(cat "$dotest/onto_name")'
        export GITHEAD_$cmt GITHEAD_$hd
        git-merge-$strategy "$cmt^" -- "$hd" "$cmt"
        rv=$?
@@ -115,42 +116,38 @@ call_merge () {
        esac
 }
 
+move_to_original_branch () {
+       test -z "$head_name" &&
+               head_name="$(cat "$dotest"/head-name)" &&
+               onto="$(cat "$dotest"/onto)" &&
+               orig_head="$(cat "$dotest"/orig-head)"
+       case "$head_name" in
+       refs/*)
+               message="rebase finished: $head_name onto $onto"
+               git update-ref -m "$message" \
+                       $head_name $(git rev-parse HEAD) $orig_head &&
+               git symbolic-ref HEAD $head_name ||
+               die "Could not move back to $head_name"
+               ;;
+       esac
+}
+
 finish_rb_merge () {
-       if test -f "$dotest/stash"
-       then
-               stash=$(cat "$dotest/stash")
-               git stash apply --index "$stash"
-       fi
+       move_to_original_branch
        rm -r "$dotest"
        echo "All done."
 }
 
-read_stash () {
-       if test -f "$1"
-       then
-               cat "$1"
-       fi
-}
-unstash_and_exit () {
-       err=$?
-       if test -f "$1" && test $err = 0
-       then
-               git stash apply --index "$1"
-       fi
-       exit $err
-}
-
 is_interactive () {
        test -f "$dotest"/interactive ||
-       while case $#,"$1" in 0,|*,-i|*,--interactive) break ;; esac
-       do
+       while :; do case $#,"$1" in 0,|*,-i|*,--interactive) break ;; esac
                shift
        done && test -n "$1"
 }
 
 is_interactive "$@" && exec git-rebase--interactive "$@"
 
-while case "$#" in 0) break ;; esac
+while test $# != 0
 do
        case "$1" in
        --continue)
@@ -161,10 +158,10 @@ do
                }
                if test -d "$dotest"
                then
-                       prev_head="`cat $dotest/prev_head`"
-                       end="`cat $dotest/end`"
-                       msgnum="`cat $dotest/msgnum`"
-                       onto="`cat $dotest/onto`"
+                       prev_head=$(cat "$dotest/prev_head")
+                       end=$(cat "$dotest/end")
+                       msgnum=$(cat "$dotest/msgnum")
+                       onto=$(cat "$dotest/onto")
                        continue_merge
                        while test "$msgnum" -le "$end"
                        do
@@ -174,19 +171,23 @@ do
                        finish_rb_merge
                        exit
                fi
-               stash=$(read_stash ".dotest/stash")
-               git am --resolved --3way --resolvemsg="$RESOLVEMSG"
-               unstash_and_exit "$stash"
+               head_name=$(cat .dotest/head-name) &&
+               onto=$(cat .dotest/onto) &&
+               orig_head=$(cat .dotest/orig-head) &&
+               git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
+               move_to_original_branch
+               exit
                ;;
        --skip)
+               git reset --hard HEAD || exit $?
                if test -d "$dotest"
                then
                        git rerere clear
-                       prev_head="`cat $dotest/prev_head`"
-                       end="`cat $dotest/end`"
-                       msgnum="`cat $dotest/msgnum`"
+                       prev_head=$(cat "$dotest/prev_head")
+                       end=$(cat "$dotest/end")
+                       msgnum=$(cat "$dotest/msgnum")
                        msgnum=$(($msgnum + 1))
-                       onto="`cat $dotest/onto`"
+                       onto=$(cat "$dotest/onto")
                        while test "$msgnum" -le "$end"
                        do
                                call_merge "$msgnum"
@@ -195,31 +196,28 @@ do
                        finish_rb_merge
                        exit
                fi
-               stash=$(read_stash ".dotest/stash")
-               git am -3 --skip --resolvemsg="$RESOLVEMSG"
-               unstash_and_exit "$stash"
+               head_name=$(cat .dotest/head-name) &&
+               onto=$(cat .dotest/onto) &&
+               orig_head=$(cat .dotest/orig-head) &&
+               git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
+               move_to_original_branch
+               exit
                ;;
        --abort)
                git rerere clear
                if test -d "$dotest"
                then
-                       if test -f "$dotest/stash"
-                       then
-                               stash=$(cat "$dotest/stash")
-                       fi
+                       move_to_original_branch
                        rm -r "$dotest"
                elif test -d .dotest
                then
-                       if test -f ".dotest/stash"
-                       then
-                               stash=$(cat ".dotest/stash")
-                       fi
+                       dotest=.dotest
+                       move_to_original_branch
                        rm -r .dotest
                else
                        die "No rebase in progress?"
                fi
                git reset --hard ORIG_HEAD
-               test -z "$stash" || git stash apply --index "$stash"
                exit
                ;;
        --onto)
@@ -285,6 +283,16 @@ else
        fi
 fi
 
+# The tree must be really really clean.
+git update-index --refresh || exit
+diff=$(git diff-index --cached --name-status -r HEAD --)
+case "$diff" in
+?*)    echo "cannot rebase: your index is not up-to-date"
+       echo "$diff"
+       exit 1
+       ;;
+esac
+
 # The upstream head must be given.  Make sure it is valid.
 upstream_name="$1"
 upstream=`git rev-parse --verify "${upstream_name}^0"` ||
@@ -294,19 +302,11 @@ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 onto_name=${newbase-"$upstream_name"}
 onto=$(git rev-parse --verify "${onto_name}^0") || exit
 
-# The tree must be clean enough for us to create a stash
-stash=$(git stash create) || exit
-if test -n "$stash"
-then
-       echo >&2 "Stashed away your working tree changes"
-fi
-
 # If a hook exists, give it a chance to interrupt
 if test -x "$GIT_DIR/hooks/pre-rebase"
 then
        "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
                echo >&2 "The pre-rebase hook refused to rebase."
-               test -z "$stash" || git stash apply --index "$stash"
                exit 1
        }
 fi
@@ -315,10 +315,7 @@ fi
 case "$#" in
 2)
        branch_name="$2"
-       git-checkout "$2" || {
-               test -z "$stash" || git stash apply --index "$stash"
-               usage
-       }
+       git-checkout "$2" || usage
        ;;
 *)
        if branch_name=`git symbolic-ref -q HEAD`
@@ -341,7 +338,6 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
        ! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
 then
        echo >&2 "Current branch $branch_name is up to date."
-       test -z "$stash" || git stash apply --index "$stash"
        exit 0
 fi
 
@@ -352,6 +348,19 @@ then
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
+# move to a detached HEAD
+orig_head=$(git rev-parse HEAD^0)
+head_name=$(git symbolic-ref HEAD 2> /dev/null)
+case "$head_name" in
+'')
+       head_name="detached HEAD"
+       ;;
+*)
+       git checkout "$orig_head" > /dev/null 2>&1 ||
+               die "could not detach HEAD"
+       ;;
+esac
+
 # Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 echo "First, rewinding head to replay your work on top of it..."
 git-reset --hard "$onto"
@@ -361,24 +370,21 @@ git-reset --hard "$onto"
 if test "$mb" = "$branch"
 then
        echo >&2 "Fast-forwarded $branch_name to $onto_name."
-       test -z "$stash" || git stash apply --index "$stash"
+       move_to_original_branch
        exit 0
 fi
 
 if test -z "$do_merge"
 then
        git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
-       git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG"
-       err=$?
-
-       if test $err = 0
-       then
-               test -z "$stash" || git stash apply --index "$stash"
-               exit
-       else
-               test -z "$stash" || echo "$stash" >.dotest/stash
-               exit $err
-       fi
+       git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG" &&
+       move_to_original_branch
+       ret=$?
+       test 0 != $ret -a -d .dotest &&
+               echo $head_name > .dotest/head-name &&
+               echo $onto > .dotest/onto &&
+               echo $orig_head > .dotest/orig-head
+       exit $ret
 fi
 
 # start doing a rebase with git-merge
@@ -387,9 +393,10 @@ fi
 mkdir -p "$dotest"
 echo "$onto" > "$dotest/onto"
 echo "$onto_name" > "$dotest/onto_name"
-prev_head=`git rev-parse HEAD^0`
+prev_head=$orig_head
 echo "$prev_head" > "$dotest/prev_head"
-test -z "$stash" || echo "$stash" >"$dotest/stash"
+echo "$orig_head" > "$dotest/orig-head"
+echo "$head_name" > "$dotest/head-name"
 
 msgnum=0
 for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`