Merge branch 'rr/rebase-autostash-fix' into maint
[gitweb.git] / git-rebase.sh
index 9eb276ba203ae552d1b64fe49814b7e8d8f91e1b..47ca3b990ba38cf45de793d5c3186b36fa728e33 100755 (executable)
@@ -5,6 +5,7 @@
 
 SUBDIRECTORY_OK=Yes
 OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=t
 OPTIONS_SPEC="\
 git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
 git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
@@ -14,6 +15,7 @@ git-rebase --continue | --abort | --skip | --edit-todo
 v,verbose!         display a diffstat of what changed upstream
 q,quiet!           be quiet. implies --no-stat
 autostash!         automatically stash/stash pop before and after
+fork-point         use 'merge-base --fork-point' to refine upstream
 onto=!             rebase onto given branch instead of upstream
 p,preserve-merges! try to recreate merges instead of ignoring them
 s,strategy=!       use the given merge strategy
@@ -35,6 +37,7 @@ ignore-date!       passed to 'git am'
 whitespace=!       passed to 'git apply'
 ignore-whitespace! passed to 'git apply'
 C=!                passed to 'git apply'
+S,gpg-sign?        GPG-sign commits
  Actions:
 continue!          continue
 abort!             abort and check out the original branch
@@ -66,6 +69,7 @@ verbose=
 diffstat=
 test "$(git config --bool rebase.stat)" = true && diffstat=t
 autostash="$(git config --bool rebase.autostash || echo false)"
+fork_point=auto
 git_am_opt=
 rebase_root=
 force_rebase=
@@ -82,6 +86,7 @@ preserve_merges=
 autosquash=
 keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
+gpg_sign_opt=
 
 read_basic_state () {
        test -f "$state_dir/head-name" &&
@@ -104,6 +109,8 @@ read_basic_state () {
                strategy_opts="$(cat "$state_dir"/strategy_opts)"
        test -f "$state_dir"/allow_rerere_autoupdate &&
                allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
+       test -f "$state_dir"/gpg_sign_opt &&
+               gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
 }
 
 write_basic_state () {
@@ -117,6 +124,7 @@ write_basic_state () {
                "$state_dir"/strategy_opts
        test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
                "$state_dir"/allow_rerere_autoupdate
+       test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt
 }
 
 output () {
@@ -155,11 +163,8 @@ apply_autostash () {
                then
                        echo "$(gettext 'Applied autostash.')"
                else
-                       ref_stash=refs/stash &&
-                       >>"$GIT_DIR/logs/$ref_stash" &&
-                       git update-ref -m "autostash" $ref_stash $stash_sha1 ||
-                       die "$(eval_gettext 'Cannot store $stash_sha1')"
-
+                       git stash store -m "autostash" -q $stash_sha1 ||
+                       die "$(eval_gettext "Cannot store \$stash_sha1")"
                        gettext 'Applying autostash resulted in conflicts.
 Your changes are safe in the stash.
 You can run "git stash pop" or "git stash drop" at any time.
@@ -237,23 +242,19 @@ do
                test $total_argc -eq 2 || usage
                action=${1##--}
                ;;
-       --onto)
-               test 2 -le "$#" || usage
-               onto="$2"
-               shift
+       --onto=*)
+               onto="${1#--onto=}"
                ;;
-       -x)
-               test 2 -le "$#" || usage
-               cmd="${cmd}exec $2${LF}"
-               shift
+       --exec=*)
+               cmd="${cmd}exec ${1#--exec=}${LF}"
                ;;
-       -i)
+       --interactive)
                interactive_rebase=explicit
                ;;
-       -k)
+       --keep-empty)
                keep_empty=yes
                ;;
-       -p)
+       --preserve-merges)
                preserve_merges=t
                test -z "$interactive_rebase" && interactive_rebase=implied
                ;;
@@ -263,21 +264,25 @@ do
        --no-autosquash)
                autosquash=
                ;;
-       -M|-m)
+       --fork-point)
+               fork_point=t
+               ;;
+       --no-fork-point)
+               fork_point=
+               ;;
+       --merge)
                do_merge=t
                ;;
-       -X)
-               shift
-               strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")"
+       --strategy-option=*)
+               strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}")"
                do_merge=t
                test -z "$strategy" && strategy=recursive
                ;;
-       -s)
-               shift
-               strategy="$1"
+       --strategy=*)
+               strategy="${1#--strategy=}"
                do_merge=t
                ;;
-       -n)
+       --no-stat)
                diffstat=
                ;;
        --stat)
@@ -286,21 +291,20 @@ do
        --autostash)
                autostash=true
                ;;
-       -v)
+       --verbose)
                verbose=t
                diffstat=t
                GIT_QUIET=
                ;;
-       -q)
+       --quiet)
                GIT_QUIET=t
                git_am_opt="$git_am_opt -q"
                verbose=
                diffstat=
                ;;
-       --whitespace)
-               shift
-               git_am_opt="$git_am_opt --whitespace=$1"
-               case "$1" in
+       --whitespace=*)
+               git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
+               case "${1#--whitespace=}" in
                fix|strip)
                        force_rebase=t
                        ;;
@@ -313,19 +317,24 @@ do
                git_am_opt="$git_am_opt $1"
                force_rebase=t
                ;;
-       -C)
-               shift
-               git_am_opt="$git_am_opt -C$1"
+       -C*)
+               git_am_opt="$git_am_opt $1"
                ;;
        --root)
                rebase_root=t
                ;;
-       -f|--no-ff)
+       --force-rebase|--no-ff)
                force_rebase=t
                ;;
        --rerere-autoupdate|--no-rerere-autoupdate)
                allow_rerere_autoupdate="$1"
                ;;
+       --gpg-sign)
+               gpg_sign_opt=-S
+               ;;
+       --gpg-sign=*)
+               gpg_sign_opt="-S${1#--gpg-sign=}"
+               ;;
        --)
                shift
                break
@@ -440,12 +449,18 @@ then
                        error_on_missing_default_upstream "rebase" "rebase" \
                                "against" "git rebase <branch>"
                fi
+
+               test "$fork_point" = auto && fork_point=t
                ;;
        *)      upstream_name="$1"
+               if test "$upstream_name" = "-"
+               then
+                       upstream_name="@{-1}"
+               fi
                shift
                ;;
        esac
-       upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+       upstream=$(peel_committish "${upstream_name}") ||
        die "$(eval_gettext "invalid upstream \$upstream_name")"
        upstream_arg="$upstream_name"
 else
@@ -481,7 +496,7 @@ case "$onto_name" in
        fi
        ;;
 *)
-       onto=$(git rev-parse --verify "${onto_name}^0") ||
+       onto=$(peel_committish "$onto_name") ||
        die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
        ;;
 esac
@@ -525,6 +540,16 @@ case "$#" in
        ;;
 esac
 
+if test "$fork_point" = t
+then
+       new_upstream=$(git merge-base --fork-point "$upstream_name" \
+                       "${switch_to:-HEAD}")
+       if test -n "$new_upstream"
+       then
+               upstream=$new_upstream
+       fi
+fi
+
 if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
 then
        stash_sha1=$(git stash create "autostash") ||
@@ -554,7 +579,9 @@ then
        if test -z "$force_rebase"
        then
                # Lazily switch to the target branch if needed...
-               test -z "$switch_to" || git checkout "$switch_to" --
+               test -z "$switch_to" ||
+               GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
+                       git checkout "$switch_to" --
                say "$(eval_gettext "Current branch \$branch_name is up to date.")"
                finish_rebase
                exit 0
@@ -580,7 +607,9 @@ test "$type" = interactive && run_specific_rebase
 
 # Detach HEAD and reset the tree
 say "$(gettext "First, rewinding head to replay your work on top of it...")"
-git checkout -q "$onto^0" || die "could not detach HEAD"
+
+GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
+       git checkout -q "$onto^0" || die "could not detach HEAD"
 git update-ref ORIG_HEAD $orig_head
 
 # If the $onto is a proper descendant of the tip of the branch, then