提交 34262322 编写于 作者: M Martin von Zweigbergk 提交者: Junio C Hamano

rebase: act on command line outside parsing loop

To later be able to use the command line processing in git-rebase.sh
for both interactive and non-interactive rebases, move anything that
is specific to non-interactive rebase outside of the parsing
loop. Keep only parsing and validation of command line options in the
loop.
Signed-off-by: NMartin von Zweigbergk <martin.von.zweigbergk@gmail.com>
Signed-off-by: NJunio C Hamano <gitster@pobox.com>
上级 99de0640
...@@ -866,152 +866,158 @@ first and then run 'git rebase --continue' again." ...@@ -866,152 +866,158 @@ first and then run 'git rebase --continue' again."
;; ;;
--) --)
shift shift
test -z "$REBASE_ROOT" -a $# -ge 1 -a $# -le 2 || break
test ! -z "$REBASE_ROOT" -a $# -le 1 || usage ;;
test -d "$DOTEST" && esac
die "Interactive rebase already started" shift
done
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"
then
output git checkout "$1" -- ||
die "Could not checkout $1"
fi
HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?" test -z "$REBASE_ROOT" -a $# -ge 1 -a $# -le 2 ||
mkdir "$DOTEST" || die "Could not create temporary $DOTEST" test ! -z "$REBASE_ROOT" -a $# -le 1 || usage
test -d "$DOTEST" &&
die "Interactive rebase already started"
: > "$DOTEST"/interactive || die "Could not mark as interactive" git var GIT_COMMITTER_IDENT >/dev/null ||
git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null || die "You need to set your committer info first"
echo "detached HEAD" > "$DOTEST"/head-name
echo $HEAD > "$DOTEST"/head if test -z "$REBASE_ROOT"
case "$REBASE_ROOT" in then
'') UPSTREAM_ARG="$1"
rm -f "$DOTEST"/rebase-root ;; UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
*) test -z "$ONTO" && ONTO=$UPSTREAM
: >"$DOTEST"/rebase-root ;; shift
esac else
echo $ONTO > "$DOTEST"/onto UPSTREAM=
test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy UPSTREAM_ARG=--root
test t = "$VERBOSE" && : > "$DOTEST"/verbose test -z "$ONTO" &&
if test t = "$PRESERVE_MERGES" die "You must specify --onto when using --root"
then fi
if test -z "$REBASE_ROOT" run_pre_rebase_hook "$UPSTREAM_ARG" "$@"
then
mkdir "$REWRITTEN" && comment_for_reflog start
for c in $(git merge-base --all $HEAD $UPSTREAM)
do require_clean_work_tree "rebase" "Please commit or stash them."
echo $ONTO > "$REWRITTEN"/$c ||
die "Could not init rewritten commits" if test ! -z "$1"
done then
else output git checkout "$1" -- ||
mkdir "$REWRITTEN" && die "Could not checkout $1"
echo $ONTO > "$REWRITTEN"/root || fi
die "Could not init rewritten commits"
fi HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
# No cherry-pick because our first pass is to determine mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
# parents to rewrite and skipping dropped commits would
# prematurely end our probe : > "$DOTEST"/interactive || die "Could not mark as interactive"
MERGES_OPTION= git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)" echo "detached HEAD" > "$DOTEST"/head-name
else
MERGES_OPTION="--no-merges --cherry-pick" echo $HEAD > "$DOTEST"/head
fi case "$REBASE_ROOT" in
'')
SHORTHEAD=$(git rev-parse --short $HEAD) rm -f "$DOTEST"/rebase-root ;;
SHORTONTO=$(git rev-parse --short $ONTO) *)
if test -z "$REBASE_ROOT" : >"$DOTEST"/rebase-root ;;
# this is now equivalent to ! -z "$UPSTREAM" esac
then echo $ONTO > "$DOTEST"/onto
SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM) test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy
REVISIONS=$UPSTREAM...$HEAD test t = "$VERBOSE" && : > "$DOTEST"/verbose
SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD if test t = "$PRESERVE_MERGES"
else then
REVISIONS=$ONTO...$HEAD if test -z "$REBASE_ROOT"
SHORTREVISIONS=$SHORTHEAD then
fi mkdir "$REWRITTEN" &&
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \ for c in $(git merge-base --all $HEAD $UPSTREAM)
--abbrev=7 --reverse --left-right --topo-order \
$REVISIONS | \
sed -n "s/^>//p" |
while read -r shortsha1 rest
do do
if test t != "$PRESERVE_MERGES" echo $ONTO > "$REWRITTEN"/$c ||
then die "Could not init rewritten commits"
printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
else
sha1=$(git rev-parse $shortsha1)
if test -z "$REBASE_ROOT"
then
preserve=t
for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
do
if test -f "$REWRITTEN"/$p -a \( $p != $ONTO -o $sha1 = $first_after_upstream \)
then
preserve=f
fi
done
else
preserve=f
fi
if test f = "$preserve"
then
touch "$REWRITTEN"/$sha1
printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
fi
fi
done done
else
# Watch for commits that been dropped by --cherry-pick mkdir "$REWRITTEN" &&
if test t = "$PRESERVE_MERGES" echo $ONTO > "$REWRITTEN"/root ||
die "Could not init rewritten commits"
fi
# No cherry-pick because our first pass is to determine
# parents to rewrite and skipping dropped commits would
# prematurely end our probe
MERGES_OPTION=
first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)"
else
MERGES_OPTION="--no-merges --cherry-pick"
fi
SHORTHEAD=$(git rev-parse --short $HEAD)
SHORTONTO=$(git rev-parse --short $ONTO)
if test -z "$REBASE_ROOT"
# this is now equivalent to ! -z "$UPSTREAM"
then
SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
REVISIONS=$UPSTREAM...$HEAD
SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
else
REVISIONS=$ONTO...$HEAD
SHORTREVISIONS=$SHORTHEAD
fi
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
--abbrev=7 --reverse --left-right --topo-order \
$REVISIONS | \
sed -n "s/^>//p" |
while read -r shortsha1 rest
do
if test t != "$PRESERVE_MERGES"
then
printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
else
sha1=$(git rev-parse $shortsha1)
if test -z "$REBASE_ROOT"
then then
mkdir "$DROPPED" preserve=t
# Save all non-cherry-picked changes for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
git rev-list $REVISIONS --left-right --cherry-pick | \
sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
# Now all commits and note which ones are missing in
# not-cherry-picks and hence being dropped
git rev-list $REVISIONS |
while read rev
do do
if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = "" if test -f "$REWRITTEN"/$p -a \( $p != $ONTO -o $sha1 = $first_after_upstream \)
then then
# Use -f2 because if rev-list is telling us this commit is preserve=f
# not worthwhile, we don't want to track its multiple heads,
# just the history of its first-parent for others that will
# be rebasing on top of it
git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
rm "$REWRITTEN"/$rev
fi fi
done done
else
preserve=f
fi
if test f = "$preserve"
then
touch "$REWRITTEN"/$sha1
printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
fi fi
fi
done
test -s "$TODO" || echo noop >> "$TODO" # Watch for commits that been dropped by --cherry-pick
test -n "$AUTOSQUASH" && rearrange_squash "$TODO" if test t = "$PRESERVE_MERGES"
cat >> "$TODO" << EOF then
mkdir "$DROPPED"
# Save all non-cherry-picked changes
git rev-list $REVISIONS --left-right --cherry-pick | \
sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
# Now all commits and note which ones are missing in
# not-cherry-picks and hence being dropped
git rev-list $REVISIONS |
while read rev
do
if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
then
# Use -f2 because if rev-list is telling us this commit is
# not worthwhile, we don't want to track its multiple heads,
# just the history of its first-parent for others that will
# be rebasing on top of it
git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
rm "$REWRITTEN"/$rev
fi
done
fi
test -s "$TODO" || echo noop >> "$TODO"
test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
cat >> "$TODO" << EOF
# Rebase $SHORTREVISIONS onto $SHORTONTO # Rebase $SHORTREVISIONS onto $SHORTONTO
# #
...@@ -1028,22 +1034,18 @@ first and then run 'git rebase --continue' again." ...@@ -1028,22 +1034,18 @@ first and then run 'git rebase --continue' again."
# #
EOF EOF
has_action "$TODO" || has_action "$TODO" ||
die_abort "Nothing to do" die_abort "Nothing to do"
cp "$TODO" "$TODO".backup cp "$TODO" "$TODO".backup
git_editor "$TODO" || git_editor "$TODO" ||
die_abort "Could not execute editor" die_abort "Could not execute editor"
has_action "$TODO" || has_action "$TODO" ||
die_abort "Nothing to do" die_abort "Nothing to do"
test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks
output git checkout $ONTO || die_abort "could not detach HEAD" output git checkout $ONTO || die_abort "could not detach HEAD"
git update-ref ORIG_HEAD $HEAD git update-ref ORIG_HEAD $HEAD
do_rest do_rest
;;
esac
shift
done
...@@ -62,6 +62,8 @@ in_progress= ...@@ -62,6 +62,8 @@ in_progress=
type= type=
# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge} # One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
state_dir= state_dir=
# One of {'', continue, skip, abort}, as parsed from command line
action=
read_state () { read_state () {
if test "$type" = merge if test "$type" = merge
...@@ -236,66 +238,10 @@ do ...@@ -236,66 +238,10 @@ do
--verify) --verify)
OK_TO_SKIP_PRE_REBASE= OK_TO_SKIP_PRE_REBASE=
;; ;;
--continue) --continue|--skip|--abort)
test -z "$in_progress" && die "No rebase in progress?" action=${1##--}
shift
git update-index --ignore-submodules --refresh && break
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_state
if test -d "$merge_dir"
then
continue_merge
while test "$msgnum" -le "$end"
do
call_merge "$msgnum"
continue_merge
done
finish_rb_merge
exit
fi
git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
;;
--skip)
test -z "$in_progress" && die "No rebase in progress?"
git reset --hard HEAD || exit $?
read_state
if test -d "$merge_dir"
then
git rerere clear
msgnum=$(($msgnum + 1))
while test "$msgnum" -le "$end"
do
call_merge "$msgnum"
continue_merge
done
finish_rb_merge
exit
fi
git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
;;
--abort)
test -z "$in_progress" && die "No rebase in progress?"
git rerere clear
read_state
case "$head_name" in
refs/*)
git symbolic-ref HEAD $head_name ||
die "Could not move back to $head_name"
;;
esac
git reset --hard $orig_head
rm -r "$state_dir"
exit
;; ;;
--onto) --onto)
test 2 -le "$#" || usage test 2 -le "$#" || usage
...@@ -391,6 +337,66 @@ do ...@@ -391,6 +337,66 @@ do
done done
test $# -gt 2 && usage test $# -gt 2 && usage
test -n "$action" && test -z "$in_progress" && die "No rebase in progress?"
case "$action" in
continue)
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_state
if test -d "$merge_dir"
then
continue_merge
while test "$msgnum" -le "$end"
do
call_merge "$msgnum"
continue_merge
done
finish_rb_merge
exit
fi
git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
;;
skip)
git reset --hard HEAD || exit $?
read_state
if test -d "$merge_dir"
then
git rerere clear
msgnum=$(($msgnum + 1))
while test "$msgnum" -le "$end"
do
call_merge "$msgnum"
continue_merge
done
finish_rb_merge
exit
fi
git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
;;
abort)
git rerere clear
read_state
case "$head_name" in
refs/*)
git symbolic-ref HEAD $head_name ||
die "Could not move back to $head_name"
;;
esac
git reset --hard $orig_head
rm -r "$state_dir"
exit
;;
esac
# Make sure no rebase is in progress # Make sure no rebase is in progress
if test -n "$in_progress" if test -n "$in_progress"
then then
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册