# The original idea comes from Eric W. Biederman, in
# http://article.gmane.org/gmane.comp.version-control.git/22407
-OPTIONS_KEEPDASHDASH=
-OPTIONS_SPEC="\
-git-rebase [-i] [options] [--] <upstream> [<branch>]
-git-rebase [-i] (--continue | --abort | --skip)
---
- Available options are
-v,verbose display a diffstat of what changed 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
-no-ff cherry-pick all commits, even if unchanged
-m,merge always used (no-op)
-i,interactive always used (no-op)
- Actions:
-continue continue rebasing process
-abort abort rebasing process and restore original branch
-skip skip current patch and continue rebasing process
-no-verify override pre-rebase hook from stopping the operation
-verify allow pre-rebase hook to run
-root rebase all reachable commmits up to the root(s)
-autosquash move commits that begin with squash!/fixup! under -i
-"
-
. git-sh-setup
-require_work_tree
dotest="$GIT_DIR/rebase-merge"
rewritten_list="$dotest"/rewritten-list
rewritten_pending="$dotest"/rewritten-pending
-preserve_merges=
-strategy=
-onto=
-verbose=
-ok_to_skip_pre_rebase=
-rebase_root=
-autosquash=
-test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
-force_rebase=
-
-GIT_CHERRY_PICK_HELP="\
-hint: after resolving the conflicts, mark the corrected paths
-hint: with 'git add <paths>' and run 'git rebase --continue'"
+GIT_CHERRY_PICK_HELP="$resolvemsg"
export GIT_CHERRY_PICK_HELP
warn () {
git cat-file commit "$1" | sed "1,/^$/d"
}
-run_pre_rebase_hook () {
- if test -z "$ok_to_skip_pre_rebase" &&
- test -x "$GIT_DIR/hooks/pre-rebase"
- then
- "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
- echo >&2 "The pre-rebase hook refused to rebase."
- exit 1
- }
- fi
-}
-
-
orig_reflog_action="$GIT_REFLOG_ACTION"
comment_for_reflog () {
# No point in merging the first parent, that's HEAD
new_parents=${new_parents# $first_parent}
if ! do_with_author output \
- git merge $strategy -m "$msg_content" $new_parents
+ git merge ${strategy:+-s $strategy} -m \
+ "$msg_content" $new_parents
then
printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
die_with_patch $sha1 "Error redoing merge $sha1"
die "Could not skip unnecessary pick commands"
}
-# check if no other options are set
-is_standalone () {
- test $# -eq 2 -a "$2" = '--' &&
- test -z "$onto" &&
- test -z "$preserve_merges" &&
- test -z "$strategy" &&
- test -z "$verbose"
-}
-
get_saved_options () {
test -d "$rewritten" && preserve_merges=t
test -f "$dotest"/strategy && strategy="$(cat "$dotest"/strategy)"
rm -f "$1.sq" "$1.rearranged"
}
-LF='
-'
-parse_onto () {
- case "$1" in
- *...*)
- if left=${1%...*} right=${1#*...} &&
- onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
- then
- case "$onto" in
- ?*"$LF"?* | '')
- exit 1 ;;
- esac
- echo "$onto"
- exit 0
- fi
- esac
- git rev-parse --verify "$1^0"
-}
+case "$action" in
+continue)
+ get_saved_options
+ comment_for_reflog continue
-while test $# != 0
-do
- case "$1" in
- --no-verify)
- ok_to_skip_pre_rebase=yes
- ;;
- --verify)
- ok_to_skip_pre_rebase=
- ;;
- --continue)
- is_standalone "$@" || usage
- get_saved_options
- comment_for_reflog continue
-
- test -d "$dotest" || die "No interactive rebase running"
-
- # Sanity check
- git rev-parse --verify HEAD >/dev/null ||
- die "Cannot read HEAD"
- git update-index --ignore-submodules --refresh &&
- git diff-files --quiet --ignore-submodules ||
- die "Working tree is dirty"
-
- # do we have anything to commit?
- if git diff-index --cached --quiet --ignore-submodules HEAD --
+ # Sanity check
+ git rev-parse --verify HEAD >/dev/null ||
+ die "Cannot read HEAD"
+ git update-index --ignore-submodules --refresh &&
+ git diff-files --quiet --ignore-submodules ||
+ die "Working tree is dirty"
+
+ # do we have anything to commit?
+ if git diff-index --cached --quiet --ignore-submodules HEAD --
+ then
+ : Nothing to commit -- skip this
+ else
+ . "$author_script" ||
+ die "Cannot find the author identity"
+ current_head=
+ if test -f "$amend"
then
- : Nothing to commit -- skip this
- else
- . "$author_script" ||
- die "Cannot find the author identity"
- current_head=
- if test -f "$amend"
- then
- current_head=$(git rev-parse --verify HEAD)
- test "$current_head" = $(cat "$amend") ||
- die "\
+ current_head=$(git rev-parse --verify HEAD)
+ test "$current_head" = $(cat "$amend") ||
+ die "\
You have uncommitted changes in your working tree. Please, commit them
first and then run 'git rebase --continue' again."
- git reset --soft HEAD^ ||
- die "Cannot rewind the HEAD"
- fi
- do_with_author git commit --no-verify -F "$msg" -e || {
- test -n "$current_head" && git reset --soft $current_head
- die "Could not commit staged changes."
- }
+ git reset --soft HEAD^ ||
+ die "Cannot rewind the HEAD"
fi
+ do_with_author git commit --no-verify -F "$msg" -e || {
+ test -n "$current_head" && git reset --soft $current_head
+ die "Could not commit staged changes."
+ }
+ fi
- record_in_rewritten "$(cat "$dotest"/stopped-sha)"
+ record_in_rewritten "$(cat "$dotest"/stopped-sha)"
- require_clean_work_tree "rebase"
- do_rest
- ;;
- --abort)
- is_standalone "$@" || usage
- get_saved_options
- comment_for_reflog abort
-
- git rerere clear
- test -d "$dotest" || die "No interactive rebase running"
-
- headname=$(cat "$dotest"/head-name)
- head=$(cat "$dotest"/head)
- case $headname in
- refs/*)
- git symbolic-ref HEAD $headname
- ;;
- esac &&
- output git reset --hard $head &&
- rm -rf "$dotest"
- exit
- ;;
- --skip)
- is_standalone "$@" || usage
- get_saved_options
- comment_for_reflog skip
+ require_clean_work_tree "rebase"
+ do_rest
+ ;;
+abort)
+ get_saved_options
+ comment_for_reflog abort
- git rerere clear
- test -d "$dotest" || die "No interactive rebase running"
+ git rerere clear
- output git reset --hard && do_rest
- ;;
- -s)
- case "$#,$1" in
- *,*=*)
- strategy="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
- 1,*)
- usage ;;
- *)
- strategy="-s $2"
- shift ;;
- esac
- ;;
- -m)
- # we use merge anyway
- ;;
- -v)
- verbose=t
- ;;
- -p)
- preserve_merges=t
- ;;
- -i)
- # yeah, we know
- ;;
- --no-ff)
- force_rebase=t
- ;;
- --root)
- rebase_root=t
- ;;
- --autosquash)
- autosquash=t
- ;;
- --no-autosquash)
- autosquash=
- ;;
- --onto)
- shift
- onto=$(parse_onto "$1") ||
- die "Does not point to a valid commit: $1"
- ;;
- --)
- shift
- break
+ headname=$(cat "$dotest"/head-name)
+ head=$(cat "$dotest"/head)
+ case $headname in
+ refs/*)
+ git symbolic-ref HEAD $headname
;;
- esac
- shift
-done
+ esac &&
+ output git reset --hard $head &&
+ rm -rf "$dotest"
+ exit
+ ;;
+skip)
+ get_saved_options
+ comment_for_reflog skip
+
+ git rerere clear
-test -z "$rebase_root" -a $# -ge 1 -a $# -le 2 ||
-test ! -z "$rebase_root" -a $# -le 1 || usage
-test -d "$dotest" &&
- die "Interactive rebase already started"
+ output git reset --hard && do_rest
+ ;;
+esac
git var GIT_COMMITTER_IDENT >/dev/null ||
die "You need to set your committer info first"
-if test -z "$rebase_root"
-then
- upstream_arg="$1"
- upstream=$(git rev-parse --verify "$1") || die "Invalid base"
- test -z "$onto" && onto=$upstream
- shift
-else
- upstream=
- upstream_arg=--root
- test -z "$onto" &&
- die "You must specify --onto when using --root"
-fi
-run_pre_rebase_hook "$upstream_arg" "$@"
-
comment_for_reflog start
-require_clean_work_tree "rebase" "Please commit or stash them."
-
-if test ! -z "$1"
+if test ! -z "$switch_to"
then
- output git checkout "$1" -- ||
- die "Could not checkout $1"
+ output git checkout "$switch_to" -- ||
+ die "Could not checkout $switch_to"
fi
head=$(git rev-parse --verify HEAD) || die "No HEAD?"
mkdir "$dotest" || die "Could not create temporary $dotest"
: > "$dotest"/interactive || die "Could not mark as interactive"
-git symbolic-ref HEAD > "$dotest"/head-name 2> /dev/null ||
- echo "detached HEAD" > "$dotest"/head-name
+echo "$head_name" > "$dotest"/head-name
echo $head > "$dotest"/head
case "$rebase_root" in