diff options
Diffstat (limited to 'git-rebase.sh')
-rwxr-xr-x | git-rebase.sh | 156 |
1 files changed, 120 insertions, 36 deletions
diff --git a/git-rebase.sh b/git-rebase.sh index b2f1c76dc3..5f6732bf3d 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -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>] @@ -13,6 +14,8 @@ git-rebase --continue | --abort | --skip | --edit-todo Available options are 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 @@ -34,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 @@ -64,6 +68,8 @@ apply_dir="$GIT_DIR"/rebase-apply 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= @@ -80,8 +86,11 @@ 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" && + test -f "$state_dir/onto" && head_name=$(cat "$state_dir"/head-name) && onto=$(cat "$state_dir"/onto) && # We always write to orig-head, but interactive rebase used to write to @@ -100,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 () { @@ -113,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 () { @@ -143,15 +155,50 @@ move_to_original_branch () { esac } -run_specific_rebase () { +finish_rebase () { + if test -f "$state_dir/autostash" + then + stash_sha1=$(cat "$state_dir/autostash") + if git stash apply $stash_sha1 2>&1 >/dev/null + then + echo "$(gettext 'Applied autostash.')" + else + 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. +' + fi + fi + git gc --auto && + rm -rf "$state_dir" +} + +run_specific_rebase_internal () { if [ "$interactive_rebase" = implied ]; then GIT_EDITOR=: export GIT_EDITOR autosquash= fi + # On FreeBSD, the shell's "return" returns from the current + # function, not from the current file inclusion. + # run_specific_rebase_internal has the file inclusion as a + # last statement, so POSIX and FreeBSD's return will do the + # same thing. . git-rebase--$type } +run_specific_rebase () { + run_specific_rebase_internal + ret=$? + if test $ret -eq 0 + then + finish_rebase + fi + exit $ret +} + run_pre_rebase_hook () { if test -z "$ok_to_skip_pre_rebase" && test -x "$GIT_DIR/hooks/pre-rebase" @@ -195,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 ;; @@ -221,41 +264,47 @@ 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) diffstat=t ;; - -v) + --autostash) + autostash=true + ;; + --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 ;; @@ -268,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 @@ -341,7 +395,7 @@ abort) ;; esac output git reset --hard $orig_head - rm -r "$state_dir" + finish_rebase exit ;; edit-todo) @@ -395,12 +449,14 @@ then error_on_missing_default_upstream "rebase" "rebase" \ "against" "git rebase <branch>" fi + + test "$fork_point" = auto && fork_point=t ;; *) upstream_name="$1" 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 @@ -436,7 +492,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 @@ -473,13 +529,35 @@ case "$#" in head_name="detached HEAD" branch_name=HEAD ;# detached fi - orig_head=$(git rev-parse --verify "${branch_name}^0") || exit + orig_head=$(git rev-parse --verify HEAD) || exit ;; *) die "BUG: unexpected number of arguments left to parse" ;; 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") || + die "$(gettext 'Cannot autostash')" + + mkdir -p "$state_dir" && + echo $stash_sha1 >"$state_dir/autostash" && + stash_abbrev=$(git rev-parse --short $stash_sha1) && + echo "$(eval_gettext 'Created autostash: $stash_abbrev')" && + git reset --hard +fi + require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")" # Now we are rebasing commits $upstream..$orig_head (or with --root, @@ -497,8 +575,11 @@ 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 else say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")" @@ -522,7 +603,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 @@ -531,6 +614,7 @@ if test "$mb" = "$orig_head" then say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")" move_to_original_branch + finish_rebase exit 0 fi |