Merge branch 'mz/rebase'
* mz/rebase: (34 commits) rebase: define options in OPTIONS_SPEC Makefile: do not install sourced rebase scripts rebase: use @{upstream} if no upstream specified rebase -i: remove unnecessary state rebase-root rebase -i: don't read unused variable preserve_merges git-rebase--am: remove unnecessary --3way option rebase -m: don't print exit code 2 when merge fails rebase -m: remember allow_rerere_autoupdate option rebase: remember strategy and strategy options rebase: remember verbose option rebase: extract code for writing basic state rebase: factor out sub command handling rebase: make -v a tiny bit more verbose rebase -i: align variable names rebase: show consistent conflict resolution hint rebase: extract am code to new source file rebase: extract merge code to new source file rebase: remove $branch as synonym for $orig_head rebase -i: support --stat rebase: factor out call to pre-rebase hook ...
This commit is contained in:
commit
78c6e0f3fa
2
.gitignore
vendored
2
.gitignore
vendored
@ -101,7 +101,9 @@
|
|||||||
/git-quiltimport
|
/git-quiltimport
|
||||||
/git-read-tree
|
/git-read-tree
|
||||||
/git-rebase
|
/git-rebase
|
||||||
|
/git-rebase--am
|
||||||
/git-rebase--interactive
|
/git-rebase--interactive
|
||||||
|
/git-rebase--merge
|
||||||
/git-receive-pack
|
/git-receive-pack
|
||||||
/git-reflog
|
/git-reflog
|
||||||
/git-relink
|
/git-relink
|
||||||
|
@ -641,7 +641,7 @@ branch.<name>.remote::
|
|||||||
|
|
||||||
branch.<name>.merge::
|
branch.<name>.merge::
|
||||||
Defines, together with branch.<name>.remote, the upstream branch
|
Defines, together with branch.<name>.remote, the upstream branch
|
||||||
for the given branch. It tells 'git fetch'/'git pull' which
|
for the given branch. It tells 'git fetch'/'git pull'/'git rebase' which
|
||||||
branch to merge and can also affect 'git push' (see push.default).
|
branch to merge and can also affect 'git push' (see push.default).
|
||||||
When in branch <name>, it tells 'git fetch' the default
|
When in branch <name>, it tells 'git fetch' the default
|
||||||
refspec to be marked for merging in FETCH_HEAD. The value is
|
refspec to be marked for merging in FETCH_HEAD. The value is
|
||||||
|
@ -9,7 +9,7 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git rebase' [-i | --interactive] [options] [--onto <newbase>]
|
'git rebase' [-i | --interactive] [options] [--onto <newbase>]
|
||||||
<upstream> [<branch>]
|
[<upstream>] [<branch>]
|
||||||
'git rebase' [-i | --interactive] [options] --onto <newbase>
|
'git rebase' [-i | --interactive] [options] --onto <newbase>
|
||||||
--root [<branch>]
|
--root [<branch>]
|
||||||
|
|
||||||
@ -21,6 +21,12 @@ If <branch> is specified, 'git rebase' will perform an automatic
|
|||||||
`git checkout <branch>` before doing anything else. Otherwise
|
`git checkout <branch>` before doing anything else. Otherwise
|
||||||
it remains on the current branch.
|
it remains on the current branch.
|
||||||
|
|
||||||
|
If <upstream> is not specified, the upstream configured in
|
||||||
|
branch.<name>.remote and branch.<name>.merge options will be used; see
|
||||||
|
linkgit:git-config[1] for details. If you are currently not on any
|
||||||
|
branch or if the current branch does not have a configured upstream,
|
||||||
|
the rebase will abort.
|
||||||
|
|
||||||
All changes made by commits in the current branch but that are not
|
All changes made by commits in the current branch but that are not
|
||||||
in <upstream> are saved to a temporary area. This is the same set
|
in <upstream> are saved to a temporary area. This is the same set
|
||||||
of commits that would be shown by `git log <upstream>..HEAD` (or
|
of commits that would be shown by `git log <upstream>..HEAD` (or
|
||||||
@ -217,7 +223,8 @@ leave out at most one of A and B, in which case it defaults to HEAD.
|
|||||||
|
|
||||||
<upstream>::
|
<upstream>::
|
||||||
Upstream branch to compare against. May be any valid commit,
|
Upstream branch to compare against. May be any valid commit,
|
||||||
not just an existing branch name.
|
not just an existing branch name. Defaults to the configured
|
||||||
|
upstream for the current branch.
|
||||||
|
|
||||||
<branch>::
|
<branch>::
|
||||||
Working branch; defaults to HEAD.
|
Working branch; defaults to HEAD.
|
||||||
|
4
Makefile
4
Makefile
@ -368,7 +368,6 @@ SCRIPT_SH += git-merge-resolve.sh
|
|||||||
SCRIPT_SH += git-mergetool.sh
|
SCRIPT_SH += git-mergetool.sh
|
||||||
SCRIPT_SH += git-pull.sh
|
SCRIPT_SH += git-pull.sh
|
||||||
SCRIPT_SH += git-quiltimport.sh
|
SCRIPT_SH += git-quiltimport.sh
|
||||||
SCRIPT_SH += git-rebase--interactive.sh
|
|
||||||
SCRIPT_SH += git-rebase.sh
|
SCRIPT_SH += git-rebase.sh
|
||||||
SCRIPT_SH += git-repack.sh
|
SCRIPT_SH += git-repack.sh
|
||||||
SCRIPT_SH += git-request-pull.sh
|
SCRIPT_SH += git-request-pull.sh
|
||||||
@ -378,6 +377,9 @@ SCRIPT_SH += git-web--browse.sh
|
|||||||
|
|
||||||
SCRIPT_LIB += git-mergetool--lib
|
SCRIPT_LIB += git-mergetool--lib
|
||||||
SCRIPT_LIB += git-parse-remote
|
SCRIPT_LIB += git-parse-remote
|
||||||
|
SCRIPT_LIB += git-rebase--am
|
||||||
|
SCRIPT_LIB += git-rebase--interactive
|
||||||
|
SCRIPT_LIB += git-rebase--merge
|
||||||
SCRIPT_LIB += git-sh-setup
|
SCRIPT_LIB += git-sh-setup
|
||||||
|
|
||||||
SCRIPT_PERL += git-add--interactive.perl
|
SCRIPT_PERL += git-add--interactive.perl
|
||||||
|
@ -50,3 +50,41 @@ get_remote_merge_branch () {
|
|||||||
esac
|
esac
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_on_missing_default_upstream () {
|
||||||
|
cmd="$1"
|
||||||
|
op_type="$2"
|
||||||
|
op_prep="$3"
|
||||||
|
example="$4"
|
||||||
|
branch_name=$(git symbolic-ref -q HEAD)
|
||||||
|
if test -z "$branch_name"
|
||||||
|
then
|
||||||
|
echo "You are not currently on a branch, so I cannot use any
|
||||||
|
'branch.<branchname>.merge' in your configuration file.
|
||||||
|
Please specify which branch you want to $op_type $op_prep on the command
|
||||||
|
line and try again (e.g. '$example').
|
||||||
|
See git-${cmd}(1) for details."
|
||||||
|
else
|
||||||
|
echo "You asked me to $cmd without telling me which branch you
|
||||||
|
want to $op_type $op_prep, and 'branch.${branch_name#refs/heads/}.merge' in
|
||||||
|
your configuration file does not tell me, either. Please
|
||||||
|
specify which branch you want to use on the command line and
|
||||||
|
try again (e.g. '$example').
|
||||||
|
See git-${cmd}(1) for details.
|
||||||
|
|
||||||
|
If you often $op_type $op_prep the same branch, you may want to
|
||||||
|
use something like the following in your configuration file:
|
||||||
|
[branch \"${branch_name#refs/heads/}\"]
|
||||||
|
remote = <nickname>
|
||||||
|
merge = <remote-ref>"
|
||||||
|
test rebase = "$op_type" &&
|
||||||
|
echo " rebase = true"
|
||||||
|
echo "
|
||||||
|
[remote \"<nickname>\"]
|
||||||
|
url = <url>
|
||||||
|
fetch = <refspec>
|
||||||
|
|
||||||
|
See git-config(1) for details."
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
32
git-pull.sh
32
git-pull.sh
@ -168,34 +168,10 @@ error_on_no_merge_candidates () {
|
|||||||
echo "You asked to pull from the remote '$1', but did not specify"
|
echo "You asked to pull from the remote '$1', but did not specify"
|
||||||
echo "a branch. Because this is not the default configured remote"
|
echo "a branch. Because this is not the default configured remote"
|
||||||
echo "for your current branch, you must specify a branch on the command line."
|
echo "for your current branch, you must specify a branch on the command line."
|
||||||
elif [ -z "$curr_branch" ]; then
|
elif [ -z "$curr_branch" -o -z "$upstream" ]; then
|
||||||
echo "You are not currently on a branch, so I cannot use any"
|
. git-parse-remote
|
||||||
echo "'branch.<branchname>.merge' in your configuration file."
|
error_on_missing_default_upstream "pull" $op_type $op_prep \
|
||||||
echo "Please specify which remote branch you want to use on the command"
|
"git pull <repository> <refspec>"
|
||||||
echo "line and try again (e.g. 'git pull <repository> <refspec>')."
|
|
||||||
echo "See git-pull(1) for details."
|
|
||||||
elif [ -z "$upstream" ]; then
|
|
||||||
echo "You asked me to pull without telling me which branch you"
|
|
||||||
echo "want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in"
|
|
||||||
echo "your configuration file does not tell me, either. Please"
|
|
||||||
echo "specify which branch you want to use on the command line and"
|
|
||||||
echo "try again (e.g. 'git pull <repository> <refspec>')."
|
|
||||||
echo "See git-pull(1) for details."
|
|
||||||
echo
|
|
||||||
echo "If you often $op_type $op_prep the same branch, you may want to"
|
|
||||||
echo "use something like the following in your configuration file:"
|
|
||||||
echo
|
|
||||||
echo " [branch \"${curr_branch}\"]"
|
|
||||||
echo " remote = <nickname>"
|
|
||||||
echo " merge = <remote-ref>"
|
|
||||||
test rebase = "$op_type" &&
|
|
||||||
echo " rebase = true"
|
|
||||||
echo
|
|
||||||
echo " [remote \"<nickname>\"]"
|
|
||||||
echo " url = <url>"
|
|
||||||
echo " fetch = <refspec>"
|
|
||||||
echo
|
|
||||||
echo "See git-config(1) for details."
|
|
||||||
else
|
else
|
||||||
echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'"
|
echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'"
|
||||||
echo "from the remote, but no such ref was fetched."
|
echo "from the remote, but no such ref was fetched."
|
||||||
|
30
git-rebase--am.sh
Normal file
30
git-rebase--am.sh
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2010 Junio C Hamano.
|
||||||
|
#
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
continue)
|
||||||
|
git am --resolved --resolvemsg="$resolvemsg" &&
|
||||||
|
move_to_original_branch
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
skip)
|
||||||
|
git am --skip --resolvemsg="$resolvemsg" &&
|
||||||
|
move_to_original_branch
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
test -n "$rebase_root" && root_flag=--root
|
||||||
|
|
||||||
|
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
|
||||||
|
--src-prefix=a/ --dst-prefix=b/ \
|
||||||
|
--no-renames $root_flag "$revisions" |
|
||||||
|
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
|
||||||
|
move_to_original_branch
|
||||||
|
ret=$?
|
||||||
|
test 0 != $ret -a -d "$state_dir" && write_basic_state
|
||||||
|
exit $ret
|
753
git-rebase--interactive.sh
Executable file → Normal file
753
git-rebase--interactive.sh
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
151
git-rebase--merge.sh
Normal file
151
git-rebase--merge.sh
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2010 Junio C Hamano.
|
||||||
|
#
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
|
||||||
|
prec=4
|
||||||
|
|
||||||
|
read_state () {
|
||||||
|
onto_name=$(cat "$state_dir"/onto_name) &&
|
||||||
|
end=$(cat "$state_dir"/end) &&
|
||||||
|
msgnum=$(cat "$state_dir"/msgnum)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue_merge () {
|
||||||
|
test -d "$state_dir" || die "$state_dir directory does not exist"
|
||||||
|
|
||||||
|
unmerged=$(git ls-files -u)
|
||||||
|
if test -n "$unmerged"
|
||||||
|
then
|
||||||
|
echo "You still have unmerged paths in your index"
|
||||||
|
echo "did you forget to use git add?"
|
||||||
|
die "$resolvemsg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmt=`cat "$state_dir/current"`
|
||||||
|
if ! git diff-index --quiet --ignore-submodules HEAD --
|
||||||
|
then
|
||||||
|
if ! git commit --no-verify -C "$cmt"
|
||||||
|
then
|
||||||
|
echo "Commit failed, please do not call \"git commit\""
|
||||||
|
echo "directly, but instead do one of the following: "
|
||||||
|
die "$resolvemsg"
|
||||||
|
fi
|
||||||
|
if test -z "$GIT_QUIET"
|
||||||
|
then
|
||||||
|
printf "Committed: %0${prec}d " $msgnum
|
||||||
|
fi
|
||||||
|
echo "$cmt $(git rev-parse HEAD^0)" >> "$state_dir/rewritten"
|
||||||
|
else
|
||||||
|
if test -z "$GIT_QUIET"
|
||||||
|
then
|
||||||
|
printf "Already applied: %0${prec}d " $msgnum
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
test -z "$GIT_QUIET" &&
|
||||||
|
GIT_PAGER='' git log --format=%s -1 "$cmt"
|
||||||
|
|
||||||
|
# onto the next patch:
|
||||||
|
msgnum=$(($msgnum + 1))
|
||||||
|
echo "$msgnum" >"$state_dir/msgnum"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_merge () {
|
||||||
|
cmt="$(cat "$state_dir/cmt.$1")"
|
||||||
|
echo "$cmt" > "$state_dir/current"
|
||||||
|
hd=$(git rev-parse --verify HEAD)
|
||||||
|
cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
|
||||||
|
msgnum=$(cat "$state_dir/msgnum")
|
||||||
|
eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
|
||||||
|
eval GITHEAD_$hd='$onto_name'
|
||||||
|
export GITHEAD_$cmt GITHEAD_$hd
|
||||||
|
if test -n "$GIT_QUIET"
|
||||||
|
then
|
||||||
|
GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
|
||||||
|
fi
|
||||||
|
test -z "$strategy" && strategy=recursive
|
||||||
|
eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
|
||||||
|
rv=$?
|
||||||
|
case "$rv" in
|
||||||
|
0)
|
||||||
|
unset GITHEAD_$cmt GITHEAD_$hd
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
git rerere $allow_rerere_autoupdate
|
||||||
|
die "$resolvemsg"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo "Strategy: $strategy failed, try another" 1>&2
|
||||||
|
die "$resolvemsg"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unknown exit code ($rv) from command:" \
|
||||||
|
"git-merge-$strategy $cmt^ -- HEAD $cmt"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_rb_merge () {
|
||||||
|
move_to_original_branch
|
||||||
|
git notes copy --for-rewrite=rebase < "$state_dir"/rewritten
|
||||||
|
if test -x "$GIT_DIR"/hooks/post-rewrite &&
|
||||||
|
test -s "$state_dir"/rewritten; then
|
||||||
|
"$GIT_DIR"/hooks/post-rewrite rebase < "$state_dir"/rewritten
|
||||||
|
fi
|
||||||
|
rm -r "$state_dir"
|
||||||
|
say All done.
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
continue)
|
||||||
|
read_state
|
||||||
|
continue_merge
|
||||||
|
while test "$msgnum" -le "$end"
|
||||||
|
do
|
||||||
|
call_merge "$msgnum"
|
||||||
|
continue_merge
|
||||||
|
done
|
||||||
|
finish_rb_merge
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
skip)
|
||||||
|
read_state
|
||||||
|
git rerere clear
|
||||||
|
msgnum=$(($msgnum + 1))
|
||||||
|
while test "$msgnum" -le "$end"
|
||||||
|
do
|
||||||
|
call_merge "$msgnum"
|
||||||
|
continue_merge
|
||||||
|
done
|
||||||
|
finish_rb_merge
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "$state_dir"
|
||||||
|
echo "$onto_name" > "$state_dir/onto_name"
|
||||||
|
write_basic_state
|
||||||
|
|
||||||
|
msgnum=0
|
||||||
|
for cmt in `git rev-list --reverse --no-merges "$revisions"`
|
||||||
|
do
|
||||||
|
msgnum=$(($msgnum + 1))
|
||||||
|
echo "$cmt" > "$state_dir/cmt.$msgnum"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo 1 >"$state_dir/msgnum"
|
||||||
|
echo $msgnum >"$state_dir/end"
|
||||||
|
|
||||||
|
end=$msgnum
|
||||||
|
msgnum=1
|
||||||
|
|
||||||
|
while test "$msgnum" -le "$end"
|
||||||
|
do
|
||||||
|
call_merge "$msgnum"
|
||||||
|
continue_merge
|
||||||
|
done
|
||||||
|
|
||||||
|
finish_rb_merge
|
598
git-rebase.sh
598
git-rebase.sh
@ -3,7 +3,7 @@
|
|||||||
# Copyright (c) 2005 Junio C Hamano.
|
# Copyright (c) 2005 Junio C Hamano.
|
||||||
#
|
#
|
||||||
|
|
||||||
USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] (<upstream>|--root) [<branch>] [--quiet | -q]'
|
USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
|
||||||
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
|
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
|
||||||
same name. When the --onto option is provided the new branch starts
|
same name. When the --onto option is provided the new branch starts
|
||||||
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
|
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
|
||||||
@ -28,7 +28,39 @@ Example: git-rebase master~1 topic
|
|||||||
'
|
'
|
||||||
|
|
||||||
SUBDIRECTORY_OK=Yes
|
SUBDIRECTORY_OK=Yes
|
||||||
OPTIONS_SPEC=
|
OPTIONS_KEEPDASHDASH=
|
||||||
|
OPTIONS_SPEC="\
|
||||||
|
git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]
|
||||||
|
git rebase [-i] [options] --onto <newbase> --root [<branch>]
|
||||||
|
git-rebase [-i] --continue | --abort | --skip
|
||||||
|
--
|
||||||
|
Available options are
|
||||||
|
v,verbose! display a diffstat of what changed upstream
|
||||||
|
q,quiet! be quiet. implies --no-stat
|
||||||
|
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! use merging strategies to rebase
|
||||||
|
i,interactive! let the user edit the list of commits to rebase
|
||||||
|
f,force-rebase! force rebase even if branch is up to date
|
||||||
|
X,strategy-option=! pass the argument through to the merge strategy
|
||||||
|
stat! display a diffstat of what changed upstream
|
||||||
|
n,no-stat! do not show diffstat of what changed upstream
|
||||||
|
verify allow pre-rebase hook to run
|
||||||
|
rerere-autoupdate allow rerere to update index with resolved conflicts
|
||||||
|
root! rebase all reachable commits up to the root(s)
|
||||||
|
autosquash move commits that begin with squash!/fixup! under -i
|
||||||
|
committer-date-is-author-date! passed to 'git am'
|
||||||
|
ignore-date! passed to 'git am'
|
||||||
|
whitespace=! passed to 'git apply'
|
||||||
|
ignore-whitespace! passed to 'git apply'
|
||||||
|
C=! passed to 'git apply'
|
||||||
|
Actions:
|
||||||
|
continue! continue rebasing process
|
||||||
|
abort! abort rebasing process and restore original branch
|
||||||
|
skip! skip current patch and continue rebasing process
|
||||||
|
"
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
set_reflog_action rebase
|
set_reflog_action rebase
|
||||||
require_work_tree
|
require_work_tree
|
||||||
@ -36,18 +68,18 @@ cd_to_toplevel
|
|||||||
|
|
||||||
LF='
|
LF='
|
||||||
'
|
'
|
||||||
OK_TO_SKIP_PRE_REBASE=
|
ok_to_skip_pre_rebase=
|
||||||
RESOLVEMSG="
|
resolvemsg="
|
||||||
When you have resolved this problem run \"git rebase --continue\".
|
When you have resolved this problem run \"git rebase --continue\".
|
||||||
If you would prefer to skip this patch, instead run \"git rebase --skip\".
|
If you would prefer to skip this patch, instead run \"git rebase --skip\".
|
||||||
To restore the original branch and stop rebasing run \"git rebase --abort\".
|
To restore the original branch and stop rebasing run \"git rebase --abort\".
|
||||||
"
|
"
|
||||||
unset newbase
|
unset onto
|
||||||
strategy=recursive
|
strategy=
|
||||||
strategy_opts=
|
strategy_opts=
|
||||||
do_merge=
|
do_merge=
|
||||||
dotest="$GIT_DIR"/rebase-merge
|
merge_dir="$GIT_DIR"/rebase-merge
|
||||||
prec=4
|
apply_dir="$GIT_DIR"/rebase-apply
|
||||||
verbose=
|
verbose=
|
||||||
diffstat=
|
diffstat=
|
||||||
test "$(git config --bool rebase.stat)" = true && diffstat=t
|
test "$(git config --bool rebase.stat)" = true && diffstat=t
|
||||||
@ -55,92 +87,67 @@ git_am_opt=
|
|||||||
rebase_root=
|
rebase_root=
|
||||||
force_rebase=
|
force_rebase=
|
||||||
allow_rerere_autoupdate=
|
allow_rerere_autoupdate=
|
||||||
|
# Non-empty if a rebase was in progress when 'git rebase' was invoked
|
||||||
|
in_progress=
|
||||||
|
# One of {am, merge, interactive}
|
||||||
|
type=
|
||||||
|
# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
|
||||||
|
state_dir=
|
||||||
|
# One of {'', continue, skip, abort}, as parsed from command line
|
||||||
|
action=
|
||||||
|
preserve_merges=
|
||||||
|
autosquash=
|
||||||
|
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
|
||||||
|
|
||||||
continue_merge () {
|
read_basic_state () {
|
||||||
test -n "$prev_head" || die "prev_head must be defined"
|
head_name=$(cat "$state_dir"/head-name) &&
|
||||||
test -d "$dotest" || die "$dotest directory does not exist"
|
onto=$(cat "$state_dir"/onto) &&
|
||||||
|
# We always write to orig-head, but interactive rebase used to write to
|
||||||
unmerged=$(git ls-files -u)
|
# head. Fall back to reading from head to cover for the case that the
|
||||||
if test -n "$unmerged"
|
# user upgraded git with an ongoing interactive rebase.
|
||||||
|
if test -f "$state_dir"/orig-head
|
||||||
then
|
then
|
||||||
echo "You still have unmerged paths in your index"
|
orig_head=$(cat "$state_dir"/orig-head)
|
||||||
echo "did you forget to use git add?"
|
|
||||||
die "$RESOLVEMSG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmt=`cat "$dotest/current"`
|
|
||||||
if ! git diff-index --quiet --ignore-submodules HEAD --
|
|
||||||
then
|
|
||||||
if ! git commit --no-verify -C "$cmt"
|
|
||||||
then
|
|
||||||
echo "Commit failed, please do not call \"git commit\""
|
|
||||||
echo "directly, but instead do one of the following: "
|
|
||||||
die "$RESOLVEMSG"
|
|
||||||
fi
|
|
||||||
if test -z "$GIT_QUIET"
|
|
||||||
then
|
|
||||||
printf "Committed: %0${prec}d " $msgnum
|
|
||||||
fi
|
|
||||||
echo "$cmt $(git rev-parse HEAD^0)" >> "$dotest/rewritten"
|
|
||||||
else
|
else
|
||||||
if test -z "$GIT_QUIET"
|
orig_head=$(cat "$state_dir"/head)
|
||||||
then
|
fi &&
|
||||||
printf "Already applied: %0${prec}d " $msgnum
|
GIT_QUIET=$(cat "$state_dir"/quiet) &&
|
||||||
fi
|
test -f "$state_dir"/verbose && verbose=t
|
||||||
fi
|
test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
|
||||||
test -z "$GIT_QUIET" &&
|
test -f "$state_dir"/strategy_opts &&
|
||||||
GIT_PAGER='' git log --format=%s -1 "$cmt"
|
strategy_opts="$(cat "$state_dir"/strategy_opts)"
|
||||||
|
test -f "$state_dir"/allow_rerere_autoupdate &&
|
||||||
prev_head=`git rev-parse HEAD^0`
|
allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
|
||||||
# save the resulting commit so we can read-tree on it later
|
|
||||||
echo "$prev_head" > "$dotest/prev_head"
|
|
||||||
|
|
||||||
# onto the next patch:
|
|
||||||
msgnum=$(($msgnum + 1))
|
|
||||||
echo "$msgnum" >"$dotest/msgnum"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
call_merge () {
|
write_basic_state () {
|
||||||
cmt="$(cat "$dotest/cmt.$1")"
|
echo "$head_name" > "$state_dir"/head-name &&
|
||||||
echo "$cmt" > "$dotest/current"
|
echo "$onto" > "$state_dir"/onto &&
|
||||||
hd=$(git rev-parse --verify HEAD)
|
echo "$orig_head" > "$state_dir"/orig-head &&
|
||||||
cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
|
echo "$GIT_QUIET" > "$state_dir"/quiet &&
|
||||||
msgnum=$(cat "$dotest/msgnum")
|
test t = "$verbose" && : > "$state_dir"/verbose
|
||||||
end=$(cat "$dotest/end")
|
test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy
|
||||||
eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
|
test -n "$strategy_opts" && echo "$strategy_opts" > \
|
||||||
eval GITHEAD_$hd='$(cat "$dotest/onto_name")'
|
"$state_dir"/strategy_opts
|
||||||
export GITHEAD_$cmt GITHEAD_$hd
|
test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
|
||||||
if test -n "$GIT_QUIET"
|
"$state_dir"/allow_rerere_autoupdate
|
||||||
then
|
}
|
||||||
GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
|
|
||||||
fi
|
output () {
|
||||||
eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
|
case "$verbose" in
|
||||||
rv=$?
|
'')
|
||||||
case "$rv" in
|
output=$("$@" 2>&1 )
|
||||||
0)
|
status=$?
|
||||||
unset GITHEAD_$cmt GITHEAD_$hd
|
test $status != 0 && printf "%s\n" "$output"
|
||||||
return
|
return $status
|
||||||
;;
|
|
||||||
1)
|
|
||||||
git rerere $allow_rerere_autoupdate
|
|
||||||
die "$RESOLVEMSG"
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
echo "Strategy: $rv $strategy failed, try another" 1>&2
|
|
||||||
die "$RESOLVEMSG"
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
die "Unknown exit code ($rv) from command:" \
|
"$@"
|
||||||
"git-merge-$strategy $cmt^ -- HEAD $cmt"
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
move_to_original_branch () {
|
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
|
case "$head_name" in
|
||||||
refs/*)
|
refs/*)
|
||||||
message="rebase finished: $head_name onto $onto"
|
message="rebase finished: $head_name onto $onto"
|
||||||
@ -152,42 +159,16 @@ move_to_original_branch () {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_rb_merge () {
|
run_specific_rebase () {
|
||||||
move_to_original_branch
|
|
||||||
git notes copy --for-rewrite=rebase < "$dotest"/rewritten
|
|
||||||
if test -x "$GIT_DIR"/hooks/post-rewrite &&
|
|
||||||
test -s "$dotest"/rewritten; then
|
|
||||||
"$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten
|
|
||||||
fi
|
|
||||||
rm -r "$dotest"
|
|
||||||
say All done.
|
|
||||||
}
|
|
||||||
|
|
||||||
is_interactive () {
|
|
||||||
while test $# != 0
|
|
||||||
do
|
|
||||||
case "$1" in
|
|
||||||
-i|--interactive)
|
|
||||||
interactive_rebase=explicit
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
-p|--preserve-merges)
|
|
||||||
interactive_rebase=implied
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$interactive_rebase" = implied ]; then
|
if [ "$interactive_rebase" = implied ]; then
|
||||||
GIT_EDITOR=:
|
GIT_EDITOR=:
|
||||||
export GIT_EDITOR
|
export GIT_EDITOR
|
||||||
fi
|
fi
|
||||||
|
. git-rebase--$type
|
||||||
test -n "$interactive_rebase" || test -f "$dotest"/interactive
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run_pre_rebase_hook () {
|
run_pre_rebase_hook () {
|
||||||
if test -z "$OK_TO_SKIP_PRE_REBASE" &&
|
if test -z "$ok_to_skip_pre_rebase" &&
|
||||||
test -x "$GIT_DIR/hooks/pre-rebase"
|
test -x "$GIT_DIR/hooks/pre-rebase"
|
||||||
then
|
then
|
||||||
"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
|
"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
|
||||||
@ -195,163 +176,94 @@ run_pre_rebase_hook () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
test -f "$GIT_DIR"/rebase-apply/applying &&
|
test -f "$apply_dir"/applying &&
|
||||||
die 'It looks like git-am is in progress. Cannot rebase.'
|
die 'It looks like git-am is in progress. Cannot rebase.'
|
||||||
|
|
||||||
is_interactive "$@" && exec git-rebase--interactive "$@"
|
if test -d "$apply_dir"
|
||||||
|
then
|
||||||
|
type=am
|
||||||
|
state_dir="$apply_dir"
|
||||||
|
elif test -d "$merge_dir"
|
||||||
|
then
|
||||||
|
if test -f "$merge_dir"/interactive
|
||||||
|
then
|
||||||
|
type=interactive
|
||||||
|
interactive_rebase=explicit
|
||||||
|
else
|
||||||
|
type=merge
|
||||||
|
fi
|
||||||
|
state_dir="$merge_dir"
|
||||||
|
fi
|
||||||
|
test -n "$type" && in_progress=t
|
||||||
|
|
||||||
|
total_argc=$#
|
||||||
while test $# != 0
|
while test $# != 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--no-verify)
|
--no-verify)
|
||||||
OK_TO_SKIP_PRE_REBASE=yes
|
ok_to_skip_pre_rebase=yes
|
||||||
;;
|
;;
|
||||||
--verify)
|
--verify)
|
||||||
OK_TO_SKIP_PRE_REBASE=
|
ok_to_skip_pre_rebase=
|
||||||
;;
|
;;
|
||||||
--continue)
|
--continue|--skip|--abort)
|
||||||
test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
|
test $total_argc -eq 2 || usage
|
||||||
die "No rebase in progress?"
|
action=${1##--}
|
||||||
|
|
||||||
git update-index --ignore-submodules --refresh &&
|
|
||||||
git diff-files --quiet --ignore-submodules || {
|
|
||||||
echo "You must edit all merge conflicts and then"
|
|
||||||
echo "mark them as resolved using git add"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
if test -d "$dotest"
|
|
||||||
then
|
|
||||||
prev_head=$(cat "$dotest/prev_head")
|
|
||||||
end=$(cat "$dotest/end")
|
|
||||||
msgnum=$(cat "$dotest/msgnum")
|
|
||||||
onto=$(cat "$dotest/onto")
|
|
||||||
GIT_QUIET=$(cat "$dotest/quiet")
|
|
||||||
continue_merge
|
|
||||||
while test "$msgnum" -le "$end"
|
|
||||||
do
|
|
||||||
call_merge "$msgnum"
|
|
||||||
continue_merge
|
|
||||||
done
|
|
||||||
finish_rb_merge
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
|
|
||||||
onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
|
|
||||||
orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
|
|
||||||
GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
|
|
||||||
git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
|
|
||||||
move_to_original_branch
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
--skip)
|
|
||||||
test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
|
|
||||||
die "No rebase in progress?"
|
|
||||||
|
|
||||||
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")
|
|
||||||
msgnum=$(($msgnum + 1))
|
|
||||||
onto=$(cat "$dotest/onto")
|
|
||||||
GIT_QUIET=$(cat "$dotest/quiet")
|
|
||||||
while test "$msgnum" -le "$end"
|
|
||||||
do
|
|
||||||
call_merge "$msgnum"
|
|
||||||
continue_merge
|
|
||||||
done
|
|
||||||
finish_rb_merge
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
|
|
||||||
onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
|
|
||||||
orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
|
|
||||||
GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
|
|
||||||
git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
|
|
||||||
move_to_original_branch
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
--abort)
|
|
||||||
test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
|
|
||||||
die "No rebase in progress?"
|
|
||||||
|
|
||||||
git rerere clear
|
|
||||||
|
|
||||||
test -d "$dotest" || dotest="$GIT_DIR"/rebase-apply
|
|
||||||
|
|
||||||
head_name="$(cat "$dotest"/head-name)" &&
|
|
||||||
case "$head_name" in
|
|
||||||
refs/*)
|
|
||||||
git symbolic-ref HEAD $head_name ||
|
|
||||||
die "Could not move back to $head_name"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
git reset --hard $(cat "$dotest/orig-head")
|
|
||||||
rm -r "$dotest"
|
|
||||||
exit
|
|
||||||
;;
|
;;
|
||||||
--onto)
|
--onto)
|
||||||
test 2 -le "$#" || usage
|
test 2 -le "$#" || usage
|
||||||
newbase="$2"
|
onto="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-M|-m|--m|--me|--mer|--merg|--merge)
|
-i)
|
||||||
|
interactive_rebase=explicit
|
||||||
|
;;
|
||||||
|
-p)
|
||||||
|
preserve_merges=t
|
||||||
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
||||||
|
;;
|
||||||
|
--autosquash)
|
||||||
|
autosquash=t
|
||||||
|
;;
|
||||||
|
--no-autosquash)
|
||||||
|
autosquash=
|
||||||
|
;;
|
||||||
|
-M|-m)
|
||||||
do_merge=t
|
do_merge=t
|
||||||
;;
|
;;
|
||||||
-X*|--strategy-option*)
|
-X)
|
||||||
case "$#,$1" in
|
shift
|
||||||
1,-X|1,--strategy-option)
|
strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")"
|
||||||
usage ;;
|
do_merge=t
|
||||||
*,-X|*,--strategy-option)
|
test -z "$strategy" && strategy=recursive
|
||||||
newopt="$2"
|
;;
|
||||||
shift ;;
|
-s)
|
||||||
*,--strategy-option=*)
|
shift
|
||||||
newopt="$(expr " $1" : ' --strategy-option=\(.*\)')" ;;
|
strategy="$1"
|
||||||
*,-X*)
|
|
||||||
newopt="$(expr " $1" : ' -X\(.*\)')" ;;
|
|
||||||
1,*)
|
|
||||||
usage ;;
|
|
||||||
esac
|
|
||||||
strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")"
|
|
||||||
do_merge=t
|
do_merge=t
|
||||||
;;
|
;;
|
||||||
-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
|
-n)
|
||||||
--strateg=*|--strategy=*|\
|
|
||||||
-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
|
|
||||||
case "$#,$1" in
|
|
||||||
*,*=*)
|
|
||||||
strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
|
|
||||||
1,*)
|
|
||||||
usage ;;
|
|
||||||
*)
|
|
||||||
strategy="$2"
|
|
||||||
shift ;;
|
|
||||||
esac
|
|
||||||
do_merge=t
|
|
||||||
;;
|
|
||||||
-n|--no-stat)
|
|
||||||
diffstat=
|
diffstat=
|
||||||
;;
|
;;
|
||||||
--stat)
|
--stat)
|
||||||
diffstat=t
|
diffstat=t
|
||||||
;;
|
;;
|
||||||
-v|--verbose)
|
-v)
|
||||||
verbose=t
|
verbose=t
|
||||||
diffstat=t
|
diffstat=t
|
||||||
GIT_QUIET=
|
GIT_QUIET=
|
||||||
;;
|
;;
|
||||||
-q|--quiet)
|
-q)
|
||||||
GIT_QUIET=t
|
GIT_QUIET=t
|
||||||
git_am_opt="$git_am_opt -q"
|
git_am_opt="$git_am_opt -q"
|
||||||
verbose=
|
verbose=
|
||||||
diffstat=
|
diffstat=
|
||||||
;;
|
;;
|
||||||
--whitespace=*)
|
--whitespace)
|
||||||
git_am_opt="$git_am_opt $1"
|
shift
|
||||||
|
git_am_opt="$git_am_opt --whitespace=$1"
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--whitespace=fix|--whitespace=strip)
|
fix|strip)
|
||||||
force_rebase=t
|
force_rebase=t
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -363,22 +275,21 @@ do
|
|||||||
git_am_opt="$git_am_opt $1"
|
git_am_opt="$git_am_opt $1"
|
||||||
force_rebase=t
|
force_rebase=t
|
||||||
;;
|
;;
|
||||||
-C*)
|
-C)
|
||||||
git_am_opt="$git_am_opt $1"
|
shift
|
||||||
|
git_am_opt="$git_am_opt -C$1"
|
||||||
;;
|
;;
|
||||||
--root)
|
--root)
|
||||||
rebase_root=t
|
rebase_root=t
|
||||||
;;
|
;;
|
||||||
-f|--f|--fo|--for|--forc|--force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff)
|
-f|--no-ff)
|
||||||
force_rebase=t
|
force_rebase=t
|
||||||
;;
|
;;
|
||||||
--rerere-autoupdate|--no-rerere-autoupdate)
|
--rerere-autoupdate|--no-rerere-autoupdate)
|
||||||
allow_rerere_autoupdate="$1"
|
allow_rerere_autoupdate="$1"
|
||||||
;;
|
;;
|
||||||
-*)
|
--)
|
||||||
usage
|
shift
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -386,58 +297,106 @@ do
|
|||||||
done
|
done
|
||||||
test $# -gt 2 && usage
|
test $# -gt 2 && usage
|
||||||
|
|
||||||
if test $# -eq 0 && test -z "$rebase_root"
|
if test -n "$action"
|
||||||
then
|
then
|
||||||
test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage
|
test -z "$in_progress" && die "No rebase in progress?"
|
||||||
test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing &&
|
# Only interactive rebase uses detailed reflog messages
|
||||||
die 'A rebase is in progress, try --continue, --skip or --abort.'
|
if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
|
||||||
|
then
|
||||||
|
GIT_REFLOG_ACTION="rebase -i ($action)"
|
||||||
|
export GIT_REFLOG_ACTION
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure we do not have $GIT_DIR/rebase-apply
|
case "$action" in
|
||||||
if test -z "$do_merge"
|
continue)
|
||||||
|
# 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 || {
|
||||||
|
echo "You must edit all merge conflicts and then"
|
||||||
|
echo "mark them as resolved using git add"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
read_basic_state
|
||||||
|
run_specific_rebase
|
||||||
|
;;
|
||||||
|
skip)
|
||||||
|
output git reset --hard HEAD || exit $?
|
||||||
|
read_basic_state
|
||||||
|
run_specific_rebase
|
||||||
|
;;
|
||||||
|
abort)
|
||||||
|
git rerere clear
|
||||||
|
read_basic_state
|
||||||
|
case "$head_name" in
|
||||||
|
refs/*)
|
||||||
|
git symbolic-ref HEAD $head_name ||
|
||||||
|
die "Could not move back to $head_name"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
output git reset --hard $orig_head
|
||||||
|
rm -r "$state_dir"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Make sure no rebase is in progress
|
||||||
|
if test -n "$in_progress"
|
||||||
then
|
then
|
||||||
if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null
|
die '
|
||||||
then
|
It seems that there is already a '"${state_dir##*/}"' directory, and
|
||||||
rmdir "$GIT_DIR"/rebase-apply
|
I wonder if you are in the middle of another rebase. If that is the
|
||||||
else
|
case, please try
|
||||||
echo >&2 '
|
git rebase (--continue | --abort | --skip)
|
||||||
It seems that I cannot create a rebase-apply directory, and
|
If that is not the case, please
|
||||||
I wonder if you are in the middle of patch application or another
|
rm -fr '"$state_dir"'
|
||||||
rebase. If that is not the case, please
|
|
||||||
rm -fr '"$GIT_DIR"'/rebase-apply
|
|
||||||
and run me again. I am stopping in case you still have something
|
and run me again. I am stopping in case you still have something
|
||||||
valuable there.'
|
valuable there.'
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if test -d "$dotest"
|
|
||||||
then
|
|
||||||
die "previous rebase directory $dotest still exists." \
|
|
||||||
'Try git rebase (--continue | --abort | --skip)'
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
require_clean_work_tree "rebase" "Please commit or stash them."
|
if test -n "$interactive_rebase"
|
||||||
|
then
|
||||||
|
type=interactive
|
||||||
|
state_dir="$merge_dir"
|
||||||
|
elif test -n "$do_merge"
|
||||||
|
then
|
||||||
|
type=merge
|
||||||
|
state_dir="$merge_dir"
|
||||||
|
else
|
||||||
|
type=am
|
||||||
|
state_dir="$apply_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
if test -z "$rebase_root"
|
if test -z "$rebase_root"
|
||||||
then
|
then
|
||||||
# The upstream head must be given. Make sure it is valid.
|
case "$#" in
|
||||||
upstream_name="$1"
|
0)
|
||||||
shift
|
if ! upstream_name=$(git rev-parse --symbolic-full-name \
|
||||||
|
--verify -q @{upstream} 2>/dev/null)
|
||||||
|
then
|
||||||
|
. git-parse-remote
|
||||||
|
error_on_missing_default_upstream "rebase" "rebase" \
|
||||||
|
"against" "git rebase <upstream branch>"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*) upstream_name="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
upstream=`git rev-parse --verify "${upstream_name}^0"` ||
|
upstream=`git rev-parse --verify "${upstream_name}^0"` ||
|
||||||
die "invalid upstream $upstream_name"
|
die "invalid upstream $upstream_name"
|
||||||
unset root_flag
|
|
||||||
upstream_arg="$upstream_name"
|
upstream_arg="$upstream_name"
|
||||||
else
|
else
|
||||||
test -z "$newbase" && die "--root must be used with --onto"
|
test -z "$onto" && die "You must specify --onto when using --root"
|
||||||
unset upstream_name
|
unset upstream_name
|
||||||
unset upstream
|
unset upstream
|
||||||
root_flag="--root"
|
upstream_arg=--root
|
||||||
upstream_arg="$root_flag"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure the branch to rebase onto is valid.
|
# Make sure the branch to rebase onto is valid.
|
||||||
onto_name=${newbase-"$upstream_name"}
|
onto_name=${onto-"$upstream_name"}
|
||||||
case "$onto_name" in
|
case "$onto_name" in
|
||||||
*...*)
|
*...*)
|
||||||
if left=${onto_name%...*} right=${onto_name#*...} &&
|
if left=${onto_name%...*} right=${onto_name#*...} &&
|
||||||
@ -456,13 +415,11 @@ case "$onto_name" in
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
onto=$(git rev-parse --verify "${onto_name}^0") || exit
|
onto=$(git rev-parse --verify "${onto_name}^0") ||
|
||||||
|
die "Does not point to a valid commit: $1"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# If a hook exists, give it a chance to interrupt
|
|
||||||
run_pre_rebase_hook "$upstream_arg" "$@"
|
|
||||||
|
|
||||||
# If the branch to rebase is given, that is the branch we will rebase
|
# If the branch to rebase is given, that is the branch we will rebase
|
||||||
# $branch_name -- branch being rebased, or HEAD (already detached)
|
# $branch_name -- branch being rebased, or HEAD (already detached)
|
||||||
# $orig_head -- commit object name of tip of the branch before rebasing
|
# $orig_head -- commit object name of tip of the branch before rebasing
|
||||||
@ -475,10 +432,10 @@ case "$#" in
|
|||||||
switch_to="$1"
|
switch_to="$1"
|
||||||
|
|
||||||
if git show-ref --verify --quiet -- "refs/heads/$1" &&
|
if git show-ref --verify --quiet -- "refs/heads/$1" &&
|
||||||
branch=$(git rev-parse -q --verify "refs/heads/$1")
|
orig_head=$(git rev-parse -q --verify "refs/heads/$1")
|
||||||
then
|
then
|
||||||
head_name="refs/heads/$1"
|
head_name="refs/heads/$1"
|
||||||
elif branch=$(git rev-parse -q --verify "$1")
|
elif orig_head=$(git rev-parse -q --verify "$1")
|
||||||
then
|
then
|
||||||
head_name="detached HEAD"
|
head_name="detached HEAD"
|
||||||
else
|
else
|
||||||
@ -496,20 +453,23 @@ case "$#" in
|
|||||||
head_name="detached HEAD"
|
head_name="detached HEAD"
|
||||||
branch_name=HEAD ;# detached
|
branch_name=HEAD ;# detached
|
||||||
fi
|
fi
|
||||||
branch=$(git rev-parse --verify "${branch_name}^0") || exit
|
orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
orig_head=$branch
|
|
||||||
|
|
||||||
# Now we are rebasing commits $upstream..$branch (or with --root,
|
require_clean_work_tree "rebase" "Please commit or stash them."
|
||||||
# everything leading up to $branch) on top of $onto
|
|
||||||
|
# Now we are rebasing commits $upstream..$orig_head (or with --root,
|
||||||
|
# everything leading up to $orig_head) on top of $onto
|
||||||
|
|
||||||
# Check if we are already based on $onto with linear history,
|
# Check if we are already based on $onto with linear history,
|
||||||
# but this should be done only when upstream and onto are the same.
|
# but this should be done only when upstream and onto are the same
|
||||||
mb=$(git merge-base "$onto" "$branch")
|
# and if this is not an interactive rebase.
|
||||||
if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
|
mb=$(git merge-base "$onto" "$orig_head")
|
||||||
|
if test "$type" != interactive && test "$upstream" = "$onto" &&
|
||||||
|
test "$mb" = "$onto" &&
|
||||||
# linear history?
|
# linear history?
|
||||||
! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null
|
! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
|
||||||
then
|
then
|
||||||
if test -z "$force_rebase"
|
if test -z "$force_rebase"
|
||||||
then
|
then
|
||||||
@ -522,10 +482,8 @@ then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Detach HEAD and reset the tree
|
# If a hook exists, give it a chance to interrupt
|
||||||
say "First, rewinding head to replay your work on top of it..."
|
run_pre_rebase_hook "$upstream_arg" "$@"
|
||||||
git checkout -q "$onto^0" || die "could not detach HEAD"
|
|
||||||
git update-ref ORIG_HEAD $branch
|
|
||||||
|
|
||||||
if test -n "$diffstat"
|
if test -n "$diffstat"
|
||||||
then
|
then
|
||||||
@ -537,9 +495,16 @@ then
|
|||||||
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
|
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
test "$type" = interactive && run_specific_rebase
|
||||||
|
|
||||||
|
# Detach HEAD and reset the tree
|
||||||
|
say "First, rewinding head to replay your work on top of it..."
|
||||||
|
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
|
# If the $onto is a proper descendant of the tip of the branch, then
|
||||||
# we just fast-forwarded.
|
# we just fast-forwarded.
|
||||||
if test "$mb" = "$branch"
|
if test "$mb" = "$orig_head"
|
||||||
then
|
then
|
||||||
say "Fast-forwarded $branch_name to $onto_name."
|
say "Fast-forwarded $branch_name to $onto_name."
|
||||||
move_to_original_branch
|
move_to_original_branch
|
||||||
@ -553,51 +518,4 @@ else
|
|||||||
revisions="$upstream..$orig_head"
|
revisions="$upstream..$orig_head"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -z "$do_merge"
|
run_specific_rebase
|
||||||
then
|
|
||||||
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
|
|
||||||
--src-prefix=a/ --dst-prefix=b/ \
|
|
||||||
--no-renames $root_flag "$revisions" |
|
|
||||||
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
|
|
||||||
move_to_original_branch
|
|
||||||
ret=$?
|
|
||||||
test 0 != $ret -a -d "$GIT_DIR"/rebase-apply &&
|
|
||||||
echo $head_name > "$GIT_DIR"/rebase-apply/head-name &&
|
|
||||||
echo $onto > "$GIT_DIR"/rebase-apply/onto &&
|
|
||||||
echo $orig_head > "$GIT_DIR"/rebase-apply/orig-head &&
|
|
||||||
echo "$GIT_QUIET" > "$GIT_DIR"/rebase-apply/quiet
|
|
||||||
exit $ret
|
|
||||||
fi
|
|
||||||
|
|
||||||
# start doing a rebase with git-merge
|
|
||||||
# this is rename-aware if the recursive (default) strategy is used
|
|
||||||
|
|
||||||
mkdir -p "$dotest"
|
|
||||||
echo "$onto" > "$dotest/onto"
|
|
||||||
echo "$onto_name" > "$dotest/onto_name"
|
|
||||||
prev_head=$orig_head
|
|
||||||
echo "$prev_head" > "$dotest/prev_head"
|
|
||||||
echo "$orig_head" > "$dotest/orig-head"
|
|
||||||
echo "$head_name" > "$dotest/head-name"
|
|
||||||
echo "$GIT_QUIET" > "$dotest/quiet"
|
|
||||||
|
|
||||||
msgnum=0
|
|
||||||
for cmt in `git rev-list --reverse --no-merges "$revisions"`
|
|
||||||
do
|
|
||||||
msgnum=$(($msgnum + 1))
|
|
||||||
echo "$cmt" > "$dotest/cmt.$msgnum"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo 1 >"$dotest/msgnum"
|
|
||||||
echo $msgnum >"$dotest/end"
|
|
||||||
|
|
||||||
end=$msgnum
|
|
||||||
msgnum=1
|
|
||||||
|
|
||||||
while test "$msgnum" -le "$end"
|
|
||||||
do
|
|
||||||
call_merge "$msgnum"
|
|
||||||
continue_merge
|
|
||||||
done
|
|
||||||
|
|
||||||
finish_rb_merge
|
|
||||||
|
@ -158,15 +158,24 @@ test_expect_success 'Show verbose error when HEAD could not be detached' '
|
|||||||
'
|
'
|
||||||
rm -f B
|
rm -f B
|
||||||
|
|
||||||
test_expect_success 'dump usage when upstream arg is missing' '
|
test_expect_success 'fail when upstream arg is missing and not on branch' '
|
||||||
git checkout -b usage topic &&
|
git checkout topic &&
|
||||||
test_must_fail git rebase 2>error1 &&
|
test_must_fail git rebase >output.out &&
|
||||||
grep "[Uu]sage" error1 &&
|
grep "You are not currently on a branch" output.out
|
||||||
test_must_fail git rebase --abort 2>error2 &&
|
'
|
||||||
grep "No rebase in progress" error2 &&
|
|
||||||
test_must_fail git rebase --onto master 2>error3 &&
|
test_expect_success 'fail when upstream arg is missing and not configured' '
|
||||||
grep "[Uu]sage" error3 &&
|
git checkout -b no-config topic &&
|
||||||
! grep "can.t shift" error3
|
test_must_fail git rebase >output.out &&
|
||||||
|
grep "branch.no-config.merge" output.out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'default to @{upstream} when upstream arg is missing' '
|
||||||
|
git checkout -b default topic &&
|
||||||
|
git config branch.default.remote .
|
||||||
|
git config branch.default.merge refs/heads/master
|
||||||
|
git rebase &&
|
||||||
|
test "$(git rev-parse default~1)" = "$(git rev-parse master)"
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase -q is quiet' '
|
test_expect_success 'rebase -q is quiet' '
|
||||||
|
@ -35,6 +35,11 @@ test_expect_success 'rebase with git am -3 (default)' '
|
|||||||
test_must_fail git rebase master
|
test_must_fail git rebase master
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rebase --skip can not be used with other options' '
|
||||||
|
test_must_fail git rebase -v --skip &&
|
||||||
|
test_must_fail git rebase --skip -v
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase --skip with am -3' '
|
test_expect_success 'rebase --skip with am -3' '
|
||||||
git rebase --skip
|
git rebase --skip
|
||||||
'
|
'
|
||||||
|
@ -84,6 +84,16 @@ testrebase() {
|
|||||||
test_cmp reflog_before reflog_after &&
|
test_cmp reflog_before reflog_after &&
|
||||||
rm reflog_before reflog_after
|
rm reflog_before reflog_after
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rebase --abort can not be used with other options' '
|
||||||
|
cd "$work_dir" &&
|
||||||
|
# Clean up the state from the previous one
|
||||||
|
git reset --hard pre-rebase &&
|
||||||
|
test_must_fail git rebase$type master &&
|
||||||
|
test_must_fail git rebase -v --abort &&
|
||||||
|
test_must_fail git rebase --abort -v &&
|
||||||
|
git rebase --abort
|
||||||
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
testrebase "" .git/rebase-apply
|
testrebase "" .git/rebase-apply
|
||||||
|
@ -40,4 +40,59 @@ test_expect_success 'non-interactive rebase --continue works with touched file'
|
|||||||
git rebase --continue
|
git rebase --continue
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rebase --continue can not be used with other options' '
|
||||||
|
test_must_fail git rebase -v --continue &&
|
||||||
|
test_must_fail git rebase --continue -v
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rebase --continue remembers merge strategy and options' '
|
||||||
|
rm -fr .git/rebase-* &&
|
||||||
|
git reset --hard commit-new-file-F2-on-topic-branch &&
|
||||||
|
test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
|
||||||
|
test_when_finished "rm -fr test-bin funny.was.run" &&
|
||||||
|
mkdir test-bin &&
|
||||||
|
cat >test-bin/git-merge-funny <<-EOF
|
||||||
|
#!$SHELL_PATH
|
||||||
|
case "\$1" in --opt) ;; *) exit 2 ;; esac
|
||||||
|
shift &&
|
||||||
|
>funny.was.run &&
|
||||||
|
exec git merge-recursive "\$@"
|
||||||
|
EOF
|
||||||
|
chmod +x test-bin/git-merge-funny &&
|
||||||
|
(
|
||||||
|
PATH=./test-bin:$PATH
|
||||||
|
test_must_fail git rebase -s funny -Xopt master topic
|
||||||
|
) &&
|
||||||
|
test -f funny.was.run &&
|
||||||
|
rm funny.was.run &&
|
||||||
|
echo "Resolved" >F2 &&
|
||||||
|
git add F2 &&
|
||||||
|
(
|
||||||
|
PATH=./test-bin:$PATH
|
||||||
|
git rebase --continue
|
||||||
|
) &&
|
||||||
|
test -f funny.was.run
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rebase --continue remembers --rerere-autoupdate' '
|
||||||
|
rm -fr .git/rebase-* &&
|
||||||
|
git reset --hard commit-new-file-F3-on-topic-branch &&
|
||||||
|
git checkout master
|
||||||
|
test_commit "commit-new-file-F3" F3 3 &&
|
||||||
|
git config rerere.enabled true &&
|
||||||
|
test_must_fail git rebase -m master topic &&
|
||||||
|
echo "Resolved" >F2 &&
|
||||||
|
git add F2 &&
|
||||||
|
test_must_fail git rebase --continue &&
|
||||||
|
echo "Resolved" >F3 &&
|
||||||
|
git add F3 &&
|
||||||
|
git rebase --continue &&
|
||||||
|
git reset --hard topic@{1} &&
|
||||||
|
test_must_fail git rebase -m --rerere-autoupdate master &&
|
||||||
|
test "$(cat F2)" = "Resolved" &&
|
||||||
|
test_must_fail git rebase --continue &&
|
||||||
|
test "$(cat F3)" = "Resolved" &&
|
||||||
|
git rebase --continue
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user