From 69a636ad1ac73a596d8c99a4206a6475b15e8d8d Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:30 -0500 Subject: rebase: clearer names for directory variables Instead of using the old variable name 'dotest' for "$GIT_DIR"/rebase-merge and no variable for "$GIT_DIR"/rebase-apply, introduce two variables 'merge_dir' and 'apply_dir' for these paths. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 141 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index cbb0ea90ed..72696bfef6 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -46,7 +46,8 @@ unset newbase strategy=recursive strategy_opts= do_merge= -dotest="$GIT_DIR"/rebase-merge +merge_dir="$GIT_DIR"/rebase-merge +apply_dir="$GIT_DIR"/rebase-apply prec=4 verbose= diffstat= @@ -58,7 +59,7 @@ allow_rerere_autoupdate= continue_merge () { test -n "$prev_head" || die "prev_head must be defined" - test -d "$dotest" || die "$dotest directory does not exist" + test -d "$merge_dir" || die "$merge_dir directory does not exist" unmerged=$(git ls-files -u) if test -n "$unmerged" @@ -68,7 +69,7 @@ continue_merge () { die "$RESOLVEMSG" fi - cmt=`cat "$dotest/current"` + cmt=`cat "$merge_dir/current"` if ! git diff-index --quiet --ignore-submodules HEAD -- then if ! git commit --no-verify -C "$cmt" @@ -81,7 +82,7 @@ continue_merge () { then printf "Committed: %0${prec}d " $msgnum fi - echo "$cmt $(git rev-parse HEAD^0)" >> "$dotest/rewritten" + echo "$cmt $(git rev-parse HEAD^0)" >> "$merge_dir/rewritten" else if test -z "$GIT_QUIET" then @@ -93,22 +94,22 @@ continue_merge () { prev_head=`git rev-parse HEAD^0` # save the resulting commit so we can read-tree on it later - echo "$prev_head" > "$dotest/prev_head" + echo "$prev_head" > "$merge_dir/prev_head" # onto the next patch: msgnum=$(($msgnum + 1)) - echo "$msgnum" >"$dotest/msgnum" + echo "$msgnum" >"$merge_dir/msgnum" } call_merge () { - cmt="$(cat "$dotest/cmt.$1")" - echo "$cmt" > "$dotest/current" + cmt="$(cat "$merge_dir/cmt.$1")" + echo "$cmt" > "$merge_dir/current" hd=$(git rev-parse --verify HEAD) cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) - msgnum=$(cat "$dotest/msgnum") - end=$(cat "$dotest/end") + msgnum=$(cat "$merge_dir/msgnum") + end=$(cat "$merge_dir/end") eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' - eval GITHEAD_$hd='$(cat "$dotest/onto_name")' + eval GITHEAD_$hd='$(cat "$merge_dir/onto_name")' export GITHEAD_$cmt GITHEAD_$hd if test -n "$GIT_QUIET" then @@ -138,9 +139,9 @@ call_merge () { move_to_original_branch () { test -z "$head_name" && - head_name="$(cat "$dotest"/head-name)" && - onto="$(cat "$dotest"/onto)" && - orig_head="$(cat "$dotest"/orig-head)" + head_name="$(cat "$merge_dir"/head-name)" && + onto="$(cat "$merge_dir"/onto)" && + orig_head="$(cat "$merge_dir"/orig-head)" case "$head_name" in refs/*) message="rebase finished: $head_name onto $onto" @@ -154,12 +155,12 @@ move_to_original_branch () { finish_rb_merge () { move_to_original_branch - git notes copy --for-rewrite=rebase < "$dotest"/rewritten + git notes copy --for-rewrite=rebase < "$merge_dir"/rewritten if test -x "$GIT_DIR"/hooks/post-rewrite && - test -s "$dotest"/rewritten; then - "$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten + test -s "$merge_dir"/rewritten; then + "$GIT_DIR"/hooks/post-rewrite rebase < "$merge_dir"/rewritten fi - rm -r "$dotest" + rm -r "$merge_dir" say All done. } @@ -183,7 +184,7 @@ is_interactive () { export GIT_EDITOR fi - test -n "$interactive_rebase" || test -f "$dotest"/interactive + test -n "$interactive_rebase" || test -f "$merge_dir"/interactive } run_pre_rebase_hook () { @@ -195,7 +196,7 @@ run_pre_rebase_hook () { fi } -test -f "$GIT_DIR"/rebase-apply/applying && +test -f "$apply_dir"/applying && die 'It looks like git-am is in progress. Cannot rebase.' is_interactive "$@" && exec git-rebase--interactive "$@" @@ -210,7 +211,7 @@ do OK_TO_SKIP_PRE_REBASE= ;; --continue) - test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || + test -d "$merge_dir" -o -d "$apply_dir" || die "No rebase in progress?" git update-index --ignore-submodules --refresh && @@ -219,13 +220,13 @@ do echo "mark them as resolved using git add" exit 1 } - if test -d "$dotest" + if test -d "$merge_dir" then - prev_head=$(cat "$dotest/prev_head") - end=$(cat "$dotest/end") - msgnum=$(cat "$dotest/msgnum") - onto=$(cat "$dotest/onto") - GIT_QUIET=$(cat "$dotest/quiet") + prev_head=$(cat "$merge_dir/prev_head") + end=$(cat "$merge_dir/end") + msgnum=$(cat "$merge_dir/msgnum") + onto=$(cat "$merge_dir/onto") + GIT_QUIET=$(cat "$merge_dir/quiet") continue_merge while test "$msgnum" -le "$end" do @@ -235,28 +236,28 @@ do 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) + head_name=$(cat "$apply_dir"/head-name) && + onto=$(cat "$apply_dir"/onto) && + orig_head=$(cat "$apply_dir"/orig-head) && + GIT_QUIET=$(cat "$apply_dir"/quiet) git am --resolved --3way --resolvemsg="$RESOLVEMSG" && move_to_original_branch exit ;; --skip) - test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || + test -d "$merge_dir" -o -d "$apply_dir" || die "No rebase in progress?" git reset --hard HEAD || exit $? - if test -d "$dotest" + if test -d "$merge_dir" then git rerere clear - prev_head=$(cat "$dotest/prev_head") - end=$(cat "$dotest/end") - msgnum=$(cat "$dotest/msgnum") + prev_head=$(cat "$merge_dir/prev_head") + end=$(cat "$merge_dir/end") + msgnum=$(cat "$merge_dir/msgnum") msgnum=$(($msgnum + 1)) - onto=$(cat "$dotest/onto") - GIT_QUIET=$(cat "$dotest/quiet") + onto=$(cat "$merge_dir/onto") + GIT_QUIET=$(cat "$merge_dir/quiet") while test "$msgnum" -le "$end" do call_merge "$msgnum" @@ -265,31 +266,31 @@ do 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) + head_name=$(cat "$apply_dir"/head-name) && + onto=$(cat "$apply_dir"/onto) && + orig_head=$(cat "$apply_dir"/orig-head) && + GIT_QUIET=$(cat "$apply_dir"/quiet) git am -3 --skip --resolvemsg="$RESOLVEMSG" && move_to_original_branch exit ;; --abort) - test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || + test -d "$merge_dir" -o -d "$apply_dir" || die "No rebase in progress?" git rerere clear - test -d "$dotest" || dotest="$GIT_DIR"/rebase-apply + test -d "$merge_dir" || merge_dir="$apply_dir" - head_name="$(cat "$dotest"/head-name)" && + head_name="$(cat "$merge_dir"/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" + git reset --hard $(cat "$merge_dir/orig-head") + rm -r "$merge_dir" exit ;; --onto) @@ -388,31 +389,31 @@ test $# -gt 2 && usage if test $# -eq 0 && test -z "$rebase_root" then - test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage - test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing && + test -d "$merge_dir" -o -d "$apply_dir" || usage + test -d "$merge_dir" -o -f "$apply_dir"/rebasing && die 'A rebase is in progress, try --continue, --skip or --abort.' fi -# Make sure we do not have $GIT_DIR/rebase-apply +# Make sure we do not have $apply_dir or $merge_dir if test -z "$do_merge" then - if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null + if mkdir "$apply_dir" 2>/dev/null then - rmdir "$GIT_DIR"/rebase-apply + rmdir "$apply_dir" else echo >&2 ' It seems that I cannot create a rebase-apply directory, and I wonder if you are in the middle of patch application or another rebase. If that is not the case, please - rm -fr '"$GIT_DIR"'/rebase-apply + rm -fr '"$apply_dir"' and run me again. I am stopping in case you still have something valuable there.' exit 1 fi else - if test -d "$dotest" + if test -d "$merge_dir" then - die "previous rebase directory $dotest still exists." \ + die "previous rebase directory $merge_dir still exists." \ 'Try git rebase (--continue | --abort | --skip)' fi fi @@ -561,35 +562,35 @@ then 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 + test 0 != $ret -a -d "$apply_dir" && + echo $head_name > "$apply_dir/head-name" && + echo $onto > "$apply_dir/onto" && + echo $orig_head > "$apply_dir/orig-head" && + echo "$GIT_QUIET" > "$apply_dir/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" +mkdir -p "$merge_dir" +echo "$onto" > "$merge_dir/onto" +echo "$onto_name" > "$merge_dir/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" +echo "$prev_head" > "$merge_dir/prev_head" +echo "$orig_head" > "$merge_dir/orig-head" +echo "$head_name" > "$merge_dir/head-name" +echo "$GIT_QUIET" > "$merge_dir/quiet" msgnum=0 for cmt in `git rev-list --reverse --no-merges "$revisions"` do msgnum=$(($msgnum + 1)) - echo "$cmt" > "$dotest/cmt.$msgnum" + echo "$cmt" > "$merge_dir/cmt.$msgnum" done -echo 1 >"$dotest/msgnum" -echo $msgnum >"$dotest/end" +echo 1 >"$merge_dir/msgnum" +echo $msgnum >"$merge_dir/end" end=$msgnum msgnum=1 -- cgit v1.2.3 From 02ac45fa628ef7c529e63bb99fe198704606e7f8 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:31 -0500 Subject: rebase: refactor reading of state The code reading the state saved in $merge_dir or $rebase_dir is currently spread out in many places, making it harder to read and to introduce additional state. Extract this code into one method that reads the state. Only extract the code associated with the state that is written when the rebase is initiated. Leave the state that changes for each commmit, at least for now. Currently, when resuming a merge-based rebase using --continue or --skip, move_to_original_branch (via finish_rb_merge) will be called without head_name and orig_head set. These variables are then lazily read in move_to_original_branch if head_name is not set (together with onto, which is unnecessarily read again). Change this by always eagerly reading the state, for both am-based and merge-based rebase, in the --continue and --skip cases. Note that this does not change the behavior for am-based rebase, which read the state eagerly even before this commit. Reading the state eagerly means that part of the state will sometimes be read unnecessarily. One example is when the rebase is continued, but stops again at another merge conflict. Another example is when the rebase is aborted. However, since both of these cases involve user interaction, the delay is hopefully not noticeable. The call_merge/continue_merge loop is not affected. Helped-by: Junio C Hamano Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 53 +++++++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index 72696bfef6..63b56837aa 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -57,6 +57,22 @@ rebase_root= force_rebase= allow_rerere_autoupdate= +read_state () { + if test -d "$merge_dir" + then + state_dir="$merge_dir" + prev_head=$(cat "$merge_dir"/prev_head) && + end=$(cat "$merge_dir"/end) && + msgnum=$(cat "$merge_dir"/msgnum) + else + state_dir="$apply_dir" + fi && + head_name=$(cat "$state_dir"/head-name) && + onto=$(cat "$state_dir"/onto) && + orig_head=$(cat "$state_dir"/orig-head) && + GIT_QUIET=$(cat "$state_dir"/quiet) +} + continue_merge () { test -n "$prev_head" || die "prev_head must be defined" test -d "$merge_dir" || die "$merge_dir directory does not exist" @@ -138,10 +154,6 @@ call_merge () { } move_to_original_branch () { - test -z "$head_name" && - head_name="$(cat "$merge_dir"/head-name)" && - onto="$(cat "$merge_dir"/onto)" && - orig_head="$(cat "$merge_dir"/orig-head)" case "$head_name" in refs/*) message="rebase finished: $head_name onto $onto" @@ -220,13 +232,9 @@ do echo "mark them as resolved using git add" exit 1 } + read_state if test -d "$merge_dir" then - prev_head=$(cat "$merge_dir/prev_head") - end=$(cat "$merge_dir/end") - msgnum=$(cat "$merge_dir/msgnum") - onto=$(cat "$merge_dir/onto") - GIT_QUIET=$(cat "$merge_dir/quiet") continue_merge while test "$msgnum" -le "$end" do @@ -236,10 +244,6 @@ do finish_rb_merge exit fi - head_name=$(cat "$apply_dir"/head-name) && - onto=$(cat "$apply_dir"/onto) && - orig_head=$(cat "$apply_dir"/orig-head) && - GIT_QUIET=$(cat "$apply_dir"/quiet) git am --resolved --3way --resolvemsg="$RESOLVEMSG" && move_to_original_branch exit @@ -249,15 +253,11 @@ do die "No rebase in progress?" git reset --hard HEAD || exit $? + read_state if test -d "$merge_dir" then git rerere clear - prev_head=$(cat "$merge_dir/prev_head") - end=$(cat "$merge_dir/end") - msgnum=$(cat "$merge_dir/msgnum") msgnum=$(($msgnum + 1)) - onto=$(cat "$merge_dir/onto") - GIT_QUIET=$(cat "$merge_dir/quiet") while test "$msgnum" -le "$end" do call_merge "$msgnum" @@ -266,10 +266,6 @@ do finish_rb_merge exit fi - head_name=$(cat "$apply_dir"/head-name) && - onto=$(cat "$apply_dir"/onto) && - orig_head=$(cat "$apply_dir"/orig-head) && - GIT_QUIET=$(cat "$apply_dir"/quiet) git am -3 --skip --resolvemsg="$RESOLVEMSG" && move_to_original_branch exit @@ -279,18 +275,15 @@ do die "No rebase in progress?" git rerere clear - - test -d "$merge_dir" || merge_dir="$apply_dir" - - head_name="$(cat "$merge_dir"/head-name)" && + 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 $(cat "$merge_dir/orig-head") - rm -r "$merge_dir" + git reset --hard $orig_head + rm -r "$state_dir" exit ;; --onto) @@ -574,12 +567,12 @@ fi # this is rename-aware if the recursive (default) strategy is used mkdir -p "$merge_dir" -echo "$onto" > "$merge_dir/onto" echo "$onto_name" > "$merge_dir/onto_name" prev_head=$orig_head echo "$prev_head" > "$merge_dir/prev_head" -echo "$orig_head" > "$merge_dir/orig-head" echo "$head_name" > "$merge_dir/head-name" +echo "$onto" > "$merge_dir/onto" +echo "$orig_head" > "$merge_dir/orig-head" echo "$GIT_QUIET" > "$merge_dir/quiet" msgnum=0 -- cgit v1.2.3 From 10ffca7db2946b4392a38a8f114a0cb3fd6e069c Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:32 -0500 Subject: rebase: read state outside loop The 'onto_name' state used in 'git rebase --merge' is currently read once for each commit that need to be applied. It doesn't change between each iteration, however, so it should be moved out of the loop. This also makes the code more readable. Also remove the unused variable 'end'. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index 63b56837aa..70948bcd23 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -62,6 +62,7 @@ read_state () { then state_dir="$merge_dir" prev_head=$(cat "$merge_dir"/prev_head) && + onto_name=$(cat "$merge_dir"/onto_name) && end=$(cat "$merge_dir"/end) && msgnum=$(cat "$merge_dir"/msgnum) else @@ -123,9 +124,8 @@ call_merge () { hd=$(git rev-parse --verify HEAD) cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) msgnum=$(cat "$merge_dir/msgnum") - end=$(cat "$merge_dir/end") eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' - eval GITHEAD_$hd='$(cat "$merge_dir/onto_name")' + eval GITHEAD_$hd='$onto_name' export GITHEAD_$cmt GITHEAD_$hd if test -n "$GIT_QUIET" then -- cgit v1.2.3 From dc4a4b7387f2d7ac5ecce2f5feb2dfa85f378beb Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:33 -0500 Subject: rebase: remove unused rebase state 'prev_head' The state stored in $GIT_DIR/rebase-merge/prev_head was introduced in 58634db (rebase: Allow merge strategies to be used when rebasing, 2006-06-21), but it was never used and should therefore be removed. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 8 -------- 1 file changed, 8 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index 70948bcd23..8c1c4ed02c 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -61,7 +61,6 @@ read_state () { if test -d "$merge_dir" then state_dir="$merge_dir" - prev_head=$(cat "$merge_dir"/prev_head) && onto_name=$(cat "$merge_dir"/onto_name) && end=$(cat "$merge_dir"/end) && msgnum=$(cat "$merge_dir"/msgnum) @@ -75,7 +74,6 @@ read_state () { } continue_merge () { - test -n "$prev_head" || die "prev_head must be defined" test -d "$merge_dir" || die "$merge_dir directory does not exist" unmerged=$(git ls-files -u) @@ -109,10 +107,6 @@ continue_merge () { test -z "$GIT_QUIET" && GIT_PAGER='' git log --format=%s -1 "$cmt" - prev_head=`git rev-parse HEAD^0` - # save the resulting commit so we can read-tree on it later - echo "$prev_head" > "$merge_dir/prev_head" - # onto the next patch: msgnum=$(($msgnum + 1)) echo "$msgnum" >"$merge_dir/msgnum" @@ -568,8 +562,6 @@ fi mkdir -p "$merge_dir" echo "$onto_name" > "$merge_dir/onto_name" -prev_head=$orig_head -echo "$prev_head" > "$merge_dir/prev_head" echo "$head_name" > "$merge_dir/head-name" echo "$onto" > "$merge_dir/onto" echo "$orig_head" > "$merge_dir/orig-head" -- cgit v1.2.3 From 99de0640f2837d31f84d2889a770d936ae4394be Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:34 -0500 Subject: rebase: improve detection of rebase in progress Detect early on if a rebase is in progress and what type of rebase it is (interactive, merge-based or am-based). This prepares for further refactoring where am-based rebase will be dispatched to git-rebase--am.sh and merge-based rebase will be dispatched to git-rebase--merge.sh. The idea is to use the same variables whether the type of rebase was detected from rebase-apply/ or rebase-merge/ directories or from the command line options. This will make the code more readable and will later also make it easier to dispatch to the type-specific scripts. Also show a consistent error message independent of the type of rebase that was in progress and remove the obsolete wording about being in the middle of a 'patch application', since that (an existing "$GIT_DIR"/rebase-apply/applying) aborts 'git rebase' at an earlier stage. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 80 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index 8c1c4ed02c..1d34d43440 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -56,16 +56,19 @@ git_am_opt= rebase_root= force_rebase= 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= read_state () { - if test -d "$merge_dir" + if test "$type" = merge then - state_dir="$merge_dir" - onto_name=$(cat "$merge_dir"/onto_name) && - end=$(cat "$merge_dir"/end) && - msgnum=$(cat "$merge_dir"/msgnum) - else - state_dir="$apply_dir" + onto_name=$(cat "$state_dir"/onto_name) && + end=$(cat "$state_dir"/end) && + msgnum=$(cat "$state_dir"/msgnum) fi && head_name=$(cat "$state_dir"/head-name) && onto=$(cat "$state_dir"/onto) && @@ -207,6 +210,23 @@ test -f "$apply_dir"/applying && 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 + while test $# != 0 do case "$1" in @@ -217,8 +237,7 @@ do OK_TO_SKIP_PRE_REBASE= ;; --continue) - test -d "$merge_dir" -o -d "$apply_dir" || - die "No rebase in progress?" + test -z "$in_progress" && die "No rebase in progress?" git update-index --ignore-submodules --refresh && git diff-files --quiet --ignore-submodules || { @@ -243,8 +262,7 @@ do exit ;; --skip) - test -d "$merge_dir" -o -d "$apply_dir" || - die "No rebase in progress?" + test -z "$in_progress" && die "No rebase in progress?" git reset --hard HEAD || exit $? read_state @@ -265,8 +283,7 @@ do exit ;; --abort) - test -d "$merge_dir" -o -d "$apply_dir" || - die "No rebase in progress?" + test -z "$in_progress" && die "No rebase in progress?" git rerere clear read_state @@ -374,37 +391,22 @@ do done test $# -gt 2 && usage -if test $# -eq 0 && test -z "$rebase_root" +# Make sure no rebase is in progress +if test -n "$in_progress" then - test -d "$merge_dir" -o -d "$apply_dir" || usage - test -d "$merge_dir" -o -f "$apply_dir"/rebasing && - die 'A rebase is in progress, try --continue, --skip or --abort.' -fi - -# Make sure we do not have $apply_dir or $merge_dir -if test -z "$do_merge" -then - if mkdir "$apply_dir" 2>/dev/null - then - rmdir "$apply_dir" - else - echo >&2 ' -It seems that I cannot create a rebase-apply directory, and -I wonder if you are in the middle of patch application or another -rebase. If that is not the case, please - rm -fr '"$apply_dir"' + die ' +It seems that there is already a '"${state_dir##*/}"' directory, and +I wonder if you are in the middle of another rebase. If that is the +case, please try + git rebase (--continue | --abort | --skip) +If that is not the case, please + rm -fr '"$state_dir"' and run me again. I am stopping in case you still have something valuable there.' - exit 1 - fi -else - if test -d "$merge_dir" - then - die "previous rebase directory $merge_dir still exists." \ - 'Try git rebase (--continue | --abort | --skip)' - fi fi +test $# -eq 0 && test -z "$rebase_root" && usage + require_clean_work_tree "rebase" "Please commit or stash them." if test -z "$rebase_root" -- cgit v1.2.3 From 342623224823cbadf61370a43df6941fba477b59 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:35 -0500 Subject: 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: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 300 +++++++++++++++++++++++---------------------- git-rebase.sh | 126 ++++++++++--------- 2 files changed, 217 insertions(+), 209 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5873ba4bc3..824f4f303d 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -866,152 +866,158 @@ first and then run 'git rebase --continue' again." ;; --) shift - 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" - - 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 + break + ;; + esac + shift +done - HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?" - mkdir "$DOTEST" || die "Could not create temporary $DOTEST" +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" - : > "$DOTEST"/interactive || die "Could not mark as interactive" - git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null || - echo "detached HEAD" > "$DOTEST"/head-name +git var GIT_COMMITTER_IDENT >/dev/null || + die "You need to set your committer info first" - echo $HEAD > "$DOTEST"/head - case "$REBASE_ROOT" in - '') - rm -f "$DOTEST"/rebase-root ;; - *) - : >"$DOTEST"/rebase-root ;; - esac - echo $ONTO > "$DOTEST"/onto - test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy - test t = "$VERBOSE" && : > "$DOTEST"/verbose - if test t = "$PRESERVE_MERGES" - then - if test -z "$REBASE_ROOT" - then - mkdir "$REWRITTEN" && - for c in $(git merge-base --all $HEAD $UPSTREAM) - do - echo $ONTO > "$REWRITTEN"/$c || - die "Could not init rewritten commits" - done - else - mkdir "$REWRITTEN" && - 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 +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?" +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 > "$DOTEST"/head +case "$REBASE_ROOT" in +'') + rm -f "$DOTEST"/rebase-root ;; +*) + : >"$DOTEST"/rebase-root ;; +esac +echo $ONTO > "$DOTEST"/onto +test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy +test t = "$VERBOSE" && : > "$DOTEST"/verbose +if test t = "$PRESERVE_MERGES" +then + if test -z "$REBASE_ROOT" + then + mkdir "$REWRITTEN" && + for c in $(git merge-base --all $HEAD $UPSTREAM) 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 - 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 + echo $ONTO > "$REWRITTEN"/$c || + die "Could not init rewritten commits" done - - # Watch for commits that been dropped by --cherry-pick - if test t = "$PRESERVE_MERGES" + else + mkdir "$REWRITTEN" && + 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 - 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 + preserve=t + for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) 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 - # 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 + 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 - test -s "$TODO" || echo noop >> "$TODO" - test -n "$AUTOSQUASH" && rearrange_squash "$TODO" - cat >> "$TODO" << EOF +# Watch for commits that been dropped by --cherry-pick +if test t = "$PRESERVE_MERGES" +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 # @@ -1028,22 +1034,18 @@ first and then run 'git rebase --continue' again." # EOF - has_action "$TODO" || - die_abort "Nothing to do" +has_action "$TODO" || + die_abort "Nothing to do" - cp "$TODO" "$TODO".backup - git_editor "$TODO" || - die_abort "Could not execute editor" +cp "$TODO" "$TODO".backup +git_editor "$TODO" || + die_abort "Could not execute editor" - has_action "$TODO" || - die_abort "Nothing to do" +has_action "$TODO" || + 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" - git update-ref ORIG_HEAD $HEAD - do_rest - ;; - esac - shift -done +output git checkout $ONTO || die_abort "could not detach HEAD" +git update-ref ORIG_HEAD $HEAD +do_rest diff --git a/git-rebase.sh b/git-rebase.sh index 1d34d43440..e3fd001f7b 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -62,6 +62,8 @@ in_progress= type= # One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge} state_dir= +# One of {'', continue, skip, abort}, as parsed from command line +action= read_state () { if test "$type" = merge @@ -236,66 +238,10 @@ do --verify) OK_TO_SKIP_PRE_REBASE= ;; - --continue) - test -z "$in_progress" && die "No rebase in progress?" - - 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) - 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 + --continue|--skip|--abort) + action=${1##--} + shift + break ;; --onto) test 2 -le "$#" || usage @@ -391,6 +337,66 @@ do done 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 if test -n "$in_progress" then -- cgit v1.2.3 From 95135b06fe5f44f1efaeac729021a350b52652e5 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:36 -0500 Subject: rebase: stricter check of standalone sub command The sub commands '--continue', '--skip' or '--abort' may only be used standalone according to the documentation. Other options following the sub command are currently not accepted, but options preceeding them are. For example, 'git rebase --continue -v' is not accepted, while 'git rebase -v --continue' is. Tighten up the check and allow no other options when one of these sub commands are used. Only check that it is standalone for non-interactive rebase for now. Once the command line processing for interactive rebase has been replaced by the command line processing in git-rebase.sh, this check will also apply to interactive rebase. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 4 ++-- t/t3403-rebase-skip.sh | 5 +++++ t/t3407-rebase-abort.sh | 10 ++++++++++ t/t3418-rebase-continue.sh | 5 +++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index e3fd001f7b..d689aad38c 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -229,6 +229,7 @@ then fi test -n "$type" && in_progress=t +total_argc=$# while test $# != 0 do case "$1" in @@ -239,9 +240,8 @@ do OK_TO_SKIP_PRE_REBASE= ;; --continue|--skip|--abort) + test $total_argc -eq 1 || usage action=${1##--} - shift - break ;; --onto) test 2 -le "$#" || usage diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index 64446e3db3..826500bd18 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -35,6 +35,11 @@ test_expect_success 'rebase with git am -3 (default)' ' 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' ' git rebase --skip ' diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh index e573dc845b..a6a6c40a98 100755 --- a/t/t3407-rebase-abort.sh +++ b/t/t3407-rebase-abort.sh @@ -84,6 +84,16 @@ testrebase() { test_cmp 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 diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 3b0d27350e..1d90191e54 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -40,4 +40,9 @@ test_expect_success 'non-interactive rebase --continue works with touched file' 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_done -- cgit v1.2.3 From 6bb4e485cff86d87b5265f26d6138357444e5eb9 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:37 -0500 Subject: rebase: align variable names git-rebase--interactive.sh will soon be sourced from git-rebase.sh. Align the names of variables used in these scripts to prepare for that. Some names in git-rebase--interactive.sh, such as "author_script" and "amend", are currently used in their upper case form to refer to a file and in their lower case form to refer to something else. In these cases, change the name of the existing lower case variable and downcase the name of the variable that refers to the file. Currently, git-rebase.sh uses mostly lower case variable names, while git-rebase--interactive.sh uses mostly upper case variable names. For consistency, downcase all variables, not just the ones that will be shared between the two script files. Helped-by: Thomas Rast Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 480 ++++++++++++++++++++++----------------------- git-rebase.sh | 32 +-- 2 files changed, 256 insertions(+), 256 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 824f4f303d..2fa348bae8 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -36,22 +36,22 @@ autosquash move commits that begin with squash!/fixup! under -i . git-sh-setup require_work_tree -DOTEST="$GIT_DIR/rebase-merge" +dotest="$GIT_DIR/rebase-merge" # The file containing rebase commands, comments, and empty lines. # This file is created by "git rebase -i" then edited by the user. As # the lines are processed, they are removed from the front of this -# file and written to the tail of $DONE. -TODO="$DOTEST"/git-rebase-todo +# file and written to the tail of $done. +todo="$dotest"/git-rebase-todo # The rebase command lines that have already been processed. A line # is moved here when it is first handled, before any associated user # actions. -DONE="$DOTEST"/done +done="$dotest"/done # The commit message that is planned to be used for any changes that # need to be committed following a user interaction. -MSG="$DOTEST"/message +msg="$dotest"/message # The file into which is accumulated the suggested commit message for # squash/fixup commands. When the first of a series of squash/fixups @@ -61,34 +61,34 @@ MSG="$DOTEST"/message # is appended to the file as it is processed. # # The first line of the file is of the form -# # This is a combination of $COUNT commits. -# where $COUNT is the number of commits whose messages have been +# # This is a combination of $count commits. +# where $count is the number of commits whose messages have been # written to the file so far (including the initial "pick" commit). # Each time that a commit message is processed, this line is read and # updated. It is deleted just before the combined commit is made. -SQUASH_MSG="$DOTEST"/message-squash +squash_msg="$dotest"/message-squash # If the current series of squash/fixups has not yet included a squash # command, then this file exists and holds the commit message of the # original "pick" commit. (If the series ends without a "squash" # command, then this can be used as the commit message of the combined # commit without opening the editor.) -FIXUP_MSG="$DOTEST"/message-fixup +fixup_msg="$dotest"/message-fixup -# $REWRITTEN is the name of a directory containing files for each -# commit that is reachable by at least one merge base of $HEAD and -# $UPSTREAM. They are not necessarily rewritten, but their children +# $rewritten is the name of a directory containing files for each +# commit that is reachable by at least one merge base of $head and +# $upstream. They are not necessarily rewritten, but their children # might be. This ensures that commits on merged, but otherwise # unrelated side branches are left alone. (Think "X" in the man page's # example.) -REWRITTEN="$DOTEST"/rewritten +rewritten="$dotest"/rewritten -DROPPED="$DOTEST"/dropped +dropped="$dotest"/dropped # A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and # GIT_AUTHOR_DATE that will be used for the commit that is currently # being rebased. -AUTHOR_SCRIPT="$DOTEST"/author-script +author_script="$dotest"/author-script # When an "edit" rebase command is being processed, the SHA1 of the # commit to be edited is recorded in this file. When "git rebase @@ -96,24 +96,24 @@ AUTHOR_SCRIPT="$DOTEST"/author-script # will be amended to the HEAD commit, but only provided the HEAD # commit is still the commit to be edited. When any other rebase # command is processed, this file is deleted. -AMEND="$DOTEST"/amend +amend="$dotest"/amend # For the post-rewrite hook, we make a list of rewritten commits and # their new sha1s. The rewritten-pending list keeps the sha1s of # commits that have been processed, but not committed yet, # e.g. because they are waiting for a 'squash' command. -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 -NEVER_FF= +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 @@ -125,7 +125,7 @@ warn () { } output () { - case "$VERBOSE" in + case "$verbose" in '') output=$("$@" 2>&1 ) status=$? @@ -144,7 +144,7 @@ commit_message () { } 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" then "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || { @@ -155,10 +155,10 @@ run_pre_rebase_hook () { } -ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION" +orig_reflog_action="$GIT_REFLOG_ACTION" comment_for_reflog () { - case "$ORIG_REFLOG_ACTION" in + case "$orig_reflog_action" in ''|rebase*) GIT_REFLOG_ACTION="rebase -i ($1)" export GIT_REFLOG_ACTION @@ -168,16 +168,16 @@ comment_for_reflog () { last_count= mark_action_done () { - sed -e 1q < "$TODO" >> "$DONE" - sed -e 1d < "$TODO" >> "$TODO".new - mv -f "$TODO".new "$TODO" - count=$(sane_grep -c '^[^#]' < "$DONE") - total=$(($count+$(sane_grep -c '^[^#]' < "$TODO"))) - if test "$last_count" != "$count" + sed -e 1q < "$todo" >> "$done" + sed -e 1d < "$todo" >> "$todo".new + mv -f "$todo".new "$todo" + new_count=$(sane_grep -c '^[^#]' < "$done") + total=$(($new_count+$(sane_grep -c '^[^#]' < "$todo"))) + if test "$last_count" != "$new_count" then - last_count=$count - printf "Rebasing (%d/%d)\r" $count $total - test -z "$VERBOSE" || echo + last_count=$new_count + printf "Rebasing (%d/%d)\r" $new_count $total + test -z "$verbose" || echo fi } @@ -193,22 +193,22 @@ make_patch () { *) echo "Root commit" ;; - esac > "$DOTEST"/patch - test -f "$MSG" || - commit_message "$1" > "$MSG" - test -f "$AUTHOR_SCRIPT" || - get_author_ident_from_commit "$1" > "$AUTHOR_SCRIPT" + esac > "$dotest"/patch + test -f "$msg" || + commit_message "$1" > "$msg" + test -f "$author_script" || + get_author_ident_from_commit "$1" > "$author_script" } die_with_patch () { - echo "$1" > "$DOTEST"/stopped-sha + echo "$1" > "$dotest"/stopped-sha make_patch "$1" git rerere die "$2" } die_abort () { - rm -rf "$DOTEST" + rm -rf "$dotest" die "$1" } @@ -228,11 +228,11 @@ do_with_author () { pick_one () { ff=--ff case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac - case "$NEVER_FF" in '') ;; ?*) ff= ;; esac + case "$force_rebase" in '') ;; ?*) ff= ;; esac output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" - test -d "$REWRITTEN" && + test -d "$rewritten" && pick_one_preserving_merges "$@" && return - if test -n "$REBASE_ROOT" + if test -n "$rebase_root" then output git cherry-pick "$@" return @@ -253,20 +253,20 @@ pick_one_preserving_merges () { esac sha1=$(git rev-parse $sha1) - if test -f "$DOTEST"/current-commit + if test -f "$dotest"/current-commit then if test "$fast_forward" = t then while read current_commit do - git rev-parse HEAD > "$REWRITTEN"/$current_commit - done <"$DOTEST"/current-commit - rm "$DOTEST"/current-commit || + git rev-parse HEAD > "$rewritten"/$current_commit + done <"$dotest"/current-commit + rm "$dotest"/current-commit || die "Cannot write current commit's replacement sha1" fi fi - echo $sha1 >> "$DOTEST"/current-commit + echo $sha1 >> "$dotest"/current-commit # rewrite parents; if none were rewritten, we can fast-forward. new_parents= @@ -280,9 +280,9 @@ pick_one_preserving_merges () { p=$(expr "$pend" : ' \([^ ]*\)') pend="${pend# $p}" - if test -f "$REWRITTEN"/$p + if test -f "$rewritten"/$p then - new_p=$(cat "$REWRITTEN"/$p) + new_p=$(cat "$rewritten"/$p) # If the todo reordered commits, and our parent is marked for # rewriting, but hasn't been gotten to yet, assume the user meant to @@ -301,10 +301,10 @@ pick_one_preserving_merges () { ;; esac else - if test -f "$DROPPED"/$p + if test -f "$dropped"/$p then fast_forward=f - replacement="$(cat "$DROPPED"/$p)" + replacement="$(cat "$dropped"/$p)" test -z "$replacement" && replacement=root pend=" $replacement$pend" else @@ -333,18 +333,18 @@ pick_one_preserving_merges () { test "a$1" = a-n && die "Refusing to squash a merge: $sha1" # redo merge - author_script=$(get_author_ident_from_commit $sha1) - eval "$author_script" - msg="$(commit_message $sha1)" + author_script_content=$(get_author_ident_from_commit $sha1) + eval "$author_script_content" + msg_content="$(commit_message $sha1)" # 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" $new_parents + git merge $strategy -m "$msg_content" $new_parents then - printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG + printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG die_with_patch $sha1 "Error redoing merge $sha1" fi - echo "$sha1 $(git rev-parse HEAD^0)" >> "$REWRITTEN_LIST" + echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list" ;; *) output git cherry-pick "$@" || @@ -365,46 +365,46 @@ nth_string () { } update_squash_messages () { - if test -f "$SQUASH_MSG"; then - mv "$SQUASH_MSG" "$SQUASH_MSG".bak || exit - COUNT=$(($(sed -n \ + if test -f "$squash_msg"; then + mv "$squash_msg" "$squash_msg".bak || exit + count=$(($(sed -n \ -e "1s/^# This is a combination of \(.*\) commits\./\1/p" \ - -e "q" < "$SQUASH_MSG".bak)+1)) + -e "q" < "$squash_msg".bak)+1)) { - echo "# This is a combination of $COUNT commits." + echo "# This is a combination of $count commits." sed -e 1d -e '2,/^./{ /^$/d - }' <"$SQUASH_MSG".bak - } >"$SQUASH_MSG" + }' <"$squash_msg".bak + } >"$squash_msg" else - commit_message HEAD > "$FIXUP_MSG" || die "Cannot write $FIXUP_MSG" - COUNT=2 + commit_message HEAD > "$fixup_msg" || die "Cannot write $fixup_msg" + count=2 { echo "# This is a combination of 2 commits." echo "# The first commit's message is:" echo - cat "$FIXUP_MSG" - } >"$SQUASH_MSG" + cat "$fixup_msg" + } >"$squash_msg" fi case $1 in squash) - rm -f "$FIXUP_MSG" + rm -f "$fixup_msg" echo - echo "# This is the $(nth_string $COUNT) commit message:" + echo "# This is the $(nth_string $count) commit message:" echo commit_message $2 ;; fixup) echo - echo "# The $(nth_string $COUNT) commit message will be skipped:" + echo "# The $(nth_string $count) commit message will be skipped:" echo commit_message $2 | sed -e 's/^/# /' ;; - esac >>"$SQUASH_MSG" + esac >>"$squash_msg" } peek_next_command () { - sed -n -e "/^#/d" -e '/^$/d' -e "s/ .*//p" -e "q" < "$TODO" + sed -n -e "/^#/d" -e '/^$/d' -e "s/ .*//p" -e "q" < "$todo" } # A squash/fixup has failed. Prepare the long version of the squash @@ -414,24 +414,24 @@ peek_next_command () { # messages, effectively causing the combined commit to be used as the # new basis for any further squash/fixups. Args: sha1 rest die_failed_squash() { - mv "$SQUASH_MSG" "$MSG" || exit - rm -f "$FIXUP_MSG" - cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit + mv "$squash_msg" "$msg" || exit + rm -f "$fixup_msg" + cp "$msg" "$GIT_DIR"/MERGE_MSG || exit warn warn "Could not apply $1... $2" die_with_patch $1 "" } flush_rewritten_pending() { - test -s "$REWRITTEN_PENDING" || return + test -s "$rewritten_pending" || return newsha1="$(git rev-parse HEAD^0)" - sed "s/$/ $newsha1/" < "$REWRITTEN_PENDING" >> "$REWRITTEN_LIST" - rm -f "$REWRITTEN_PENDING" + sed "s/$/ $newsha1/" < "$rewritten_pending" >> "$rewritten_list" + rm -f "$rewritten_pending" } record_in_rewritten() { oldsha1="$(git rev-parse $1)" - echo "$oldsha1" >> "$REWRITTEN_PENDING" + echo "$oldsha1" >> "$rewritten_pending" case "$(peek_next_command)" in squash|s|fixup|f) @@ -443,8 +443,8 @@ record_in_rewritten() { } do_next () { - rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit - read -r command sha1 rest < "$TODO" + rm -f "$msg" "$author_script" "$amend" || exit + read -r command sha1 rest < "$todo" case "$command" in '#'*|''|noop) mark_action_done @@ -472,9 +472,9 @@ do_next () { mark_action_done pick_one $sha1 || die_with_patch $sha1 "Could not apply $sha1... $rest" - echo "$sha1" > "$DOTEST"/stopped-sha + echo "$sha1" > "$dotest"/stopped-sha make_patch $sha1 - git rev-parse --verify HEAD > "$AMEND" + git rev-parse --verify HEAD > "$amend" warn "Stopped at $sha1... $rest" warn "You can amend the commit now, with" warn @@ -497,47 +497,47 @@ do_next () { esac comment_for_reflog $squash_style - test -f "$DONE" && has_action "$DONE" || + test -f "$done" && has_action "$done" || die "Cannot '$squash_style' without a previous commit" mark_action_done update_squash_messages $squash_style $sha1 - author_script=$(get_author_ident_from_commit HEAD) - echo "$author_script" > "$AUTHOR_SCRIPT" - eval "$author_script" + author_script_content=$(get_author_ident_from_commit HEAD) + echo "$author_script_content" > "$author_script" + eval "$author_script_content" output git reset --soft HEAD^ pick_one -n $sha1 || die_failed_squash $sha1 "$rest" case "$(peek_next_command)" in squash|s|fixup|f) # This is an intermediate commit; its message will only be # used in case of trouble. So use the long version: - do_with_author output git commit --no-verify -F "$SQUASH_MSG" || + do_with_author output git commit --no-verify -F "$squash_msg" || die_failed_squash $sha1 "$rest" ;; *) # This is the final command of this squash/fixup group - if test -f "$FIXUP_MSG" + if test -f "$fixup_msg" then - do_with_author git commit --no-verify -F "$FIXUP_MSG" || + do_with_author git commit --no-verify -F "$fixup_msg" || die_failed_squash $sha1 "$rest" else - cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit + cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit rm -f "$GIT_DIR"/MERGE_MSG do_with_author git commit --no-verify -e || die_failed_squash $sha1 "$rest" fi - rm -f "$SQUASH_MSG" "$FIXUP_MSG" + rm -f "$squash_msg" "$fixup_msg" ;; esac record_in_rewritten $sha1 ;; x|"exec") - read -r command rest < "$TODO" + read -r command rest < "$todo" mark_action_done printf 'Executing: %s\n' "$rest" # "exec" command doesn't take a sha1 in the todo-list. # => can't just use $sha1 here. - git rev-parse --verify HEAD > "$DOTEST"/stopped-sha + git rev-parse --verify HEAD > "$dotest"/stopped-sha ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution status=$? if test "$status" -ne 0 @@ -563,42 +563,42 @@ do_next () { warn "Unknown command: $command $sha1 $rest" if git rev-parse --verify -q "$sha1" >/dev/null then - die_with_patch $sha1 "Please fix this in the file $TODO." + die_with_patch $sha1 "Please fix this in the file $todo." else - die "Please fix this in the file $TODO." + die "Please fix this in the file $todo." fi ;; esac - test -s "$TODO" && return + test -s "$todo" && return comment_for_reflog finish && - HEADNAME=$(cat "$DOTEST"/head-name) && - OLDHEAD=$(cat "$DOTEST"/head) && - SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) && - NEWHEAD=$(git rev-parse HEAD) && - case $HEADNAME in + headname=$(cat "$dotest"/head-name) && + oldhead=$(cat "$dotest"/head) && + shortonto=$(git rev-parse --short $(cat "$dotest"/onto)) && + newhead=$(git rev-parse HEAD) && + case $headname in refs/*) - message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO" && - git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD && - git symbolic-ref HEAD $HEADNAME + message="$GIT_REFLOG_ACTION: $headname onto $shortonto" && + git update-ref -m "$message" $headname $newhead $oldhead && + git symbolic-ref HEAD $headname ;; esac && { - test ! -f "$DOTEST"/verbose || - git diff-tree --stat $(cat "$DOTEST"/head)..HEAD + test ! -f "$dotest"/verbose || + git diff-tree --stat $(cat "$dotest"/head)..HEAD } && { - test -s "$REWRITTEN_LIST" && - git notes copy --for-rewrite=rebase < "$REWRITTEN_LIST" || + test -s "$rewritten_list" && + git notes copy --for-rewrite=rebase < "$rewritten_list" || true # we don't care if this copying failed } && if test -x "$GIT_DIR"/hooks/post-rewrite && - test -s "$REWRITTEN_LIST"; then - "$GIT_DIR"/hooks/post-rewrite rebase < "$REWRITTEN_LIST" + test -s "$rewritten_list"; then + "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list" true # we don't care if this hook failed fi && - rm -rf "$DOTEST" && + rm -rf "$dotest" && git gc --auto && - warn "Successfully rebased and updated $HEADNAME." + warn "Successfully rebased and updated $headname." exit } @@ -618,11 +618,11 @@ skip_unnecessary_picks () { # fd=3 means we skip the command case "$fd,$command" in 3,pick|3,p) - # pick a commit whose parent is current $ONTO -> skip + # pick a commit whose parent is current $onto -> skip sha1=${rest%% *} case "$(git rev-parse --verify --quiet "$sha1"^)" in - "$ONTO"*) - ONTO=$sha1 + "$onto"*) + onto=$sha1 ;; *) fd=1 @@ -637,11 +637,11 @@ skip_unnecessary_picks () { ;; esac printf '%s\n' "$command${rest:+ }$rest" >&$fd - done <"$TODO" >"$TODO.new" 3>>"$DONE" && - mv -f "$TODO".new "$TODO" && + done <"$todo" >"$todo.new" 3>>"$done" && + mv -f "$todo".new "$todo" && case "$(peek_next_command)" in squash|s|fixup|f) - record_in_rewritten "$ONTO" + record_in_rewritten "$onto" ;; esac || die "Could not skip unnecessary pick commands" @@ -650,17 +650,17 @@ skip_unnecessary_picks () { # 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" + 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)" - test -f "$DOTEST"/verbose && VERBOSE=t - test -f "$DOTEST"/rebase-root && REBASE_ROOT=t + test -d "$rewritten" && preserve_merges=t + test -f "$dotest"/strategy && strategy="$(cat "$dotest"/strategy)" + test -f "$dotest"/verbose && verbose=t + test -f "$dotest"/rebase-root && rebase_root=t } # Rearrange the todo list that has both "pick sha1 msg" and @@ -699,7 +699,7 @@ rearrange_squash () { esac printf '%s\n' "$pick $sha1 $message" used="$used$sha1 " - while read -r squash action msg + while read -r squash action msg_content do case " $used" in *" $squash "*) continue ;; @@ -709,13 +709,13 @@ rearrange_squash () { +*) action="${action#+}" # full sha1 prefix test - case "$msg" in "$sha1"*) emit=1;; esac ;; + case "$msg_content" in "$sha1"*) emit=1;; esac ;; *) # message prefix test - case "$message" in "$msg"*) emit=1;; esac ;; + case "$message" in "$msg_content"*) emit=1;; esac ;; esac if test $emit = 1; then - printf '%s\n' "$action $squash $action! $msg" + printf '%s\n' "$action $squash $action! $msg_content" used="$used$squash " fi done <"$1.sq" @@ -747,17 +747,17 @@ while test $# != 0 do case "$1" in --no-verify) - OK_TO_SKIP_PRE_REBASE=yes + ok_to_skip_pre_rebase=yes ;; --verify) - OK_TO_SKIP_PRE_REBASE= + ok_to_skip_pre_rebase= ;; --continue) is_standalone "$@" || usage get_saved_options comment_for_reflog continue - test -d "$DOTEST" || die "No interactive rebase running" + test -d "$dotest" || die "No interactive rebase running" # Sanity check git rev-parse --verify HEAD >/dev/null || @@ -771,26 +771,26 @@ do then : Nothing to commit -- skip this else - . "$AUTHOR_SCRIPT" || + . "$author_script" || die "Cannot find the author identity" - amend= - if test -f "$AMEND" + current_head= + if test -f "$amend" then - amend=$(git rev-parse --verify HEAD) - test "$amend" = $(cat "$AMEND") || + 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 "$amend" && git reset --soft $amend + 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 @@ -801,17 +801,17 @@ first and then run 'git rebase --continue' again." comment_for_reflog abort git rerere clear - test -d "$DOTEST" || die "No interactive rebase running" + test -d "$dotest" || die "No interactive rebase running" - HEADNAME=$(cat "$DOTEST"/head-name) - HEAD=$(cat "$DOTEST"/head) - case $HEADNAME in + headname=$(cat "$dotest"/head-name) + head=$(cat "$dotest"/head) + case $headname in refs/*) - git symbolic-ref HEAD $HEADNAME + git symbolic-ref HEAD $headname ;; esac && - output git reset --hard $HEAD && - rm -rf "$DOTEST" + output git reset --hard $head && + rm -rf "$dotest" exit ;; --skip) @@ -820,18 +820,18 @@ first and then run 'git rebase --continue' again." comment_for_reflog skip git rerere clear - test -d "$DOTEST" || die "No interactive rebase running" + test -d "$dotest" || die "No interactive rebase running" output git reset --hard && do_rest ;; -s) case "$#,$1" in *,*=*) - STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; + strategy="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 1,*) usage ;; *) - STRATEGY="-s $2" + strategy="-s $2" shift ;; esac ;; @@ -839,29 +839,29 @@ first and then run 'git rebase --continue' again." # we use merge anyway ;; -v) - VERBOSE=t + verbose=t ;; -p) - PRESERVE_MERGES=t + preserve_merges=t ;; -i) # yeah, we know ;; --no-ff) - NEVER_FF=t + force_rebase=t ;; --root) - REBASE_ROOT=t + rebase_root=t ;; --autosquash) - AUTOSQUASH=t + autosquash=t ;; --no-autosquash) - AUTOSQUASH= + autosquash= ;; --onto) shift - ONTO=$(parse_onto "$1") || + onto=$(parse_onto "$1") || die "Does not point to a valid commit: $1" ;; --) @@ -872,27 +872,27 @@ first and then run 'git rebase --continue' again." shift done -test -z "$REBASE_ROOT" -a $# -ge 1 -a $# -le 2 || -test ! -z "$REBASE_ROOT" -a $# -le 1 || usage -test -d "$DOTEST" && +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" git var GIT_COMMITTER_IDENT >/dev/null || die "You need to set your committer info first" -if test -z "$REBASE_ROOT" +if test -z "$rebase_root" then - UPSTREAM_ARG="$1" - UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base" - test -z "$ONTO" && ONTO=$UPSTREAM + 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" + upstream= + upstream_arg=--root + test -z "$onto" && + die "You must specify --onto when using --root" fi -run_pre_rebase_hook "$UPSTREAM_ARG" "$@" +run_pre_rebase_hook "$upstream_arg" "$@" comment_for_reflog start @@ -904,76 +904,76 @@ then die "Could not checkout $1" fi -HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?" -mkdir "$DOTEST" || die "Could not create temporary $DOTEST" +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 +: > "$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 > "$DOTEST"/head -case "$REBASE_ROOT" in +echo $head > "$dotest"/head +case "$rebase_root" in '') - rm -f "$DOTEST"/rebase-root ;; + rm -f "$dotest"/rebase-root ;; *) - : >"$DOTEST"/rebase-root ;; + : >"$dotest"/rebase-root ;; esac -echo $ONTO > "$DOTEST"/onto -test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy -test t = "$VERBOSE" && : > "$DOTEST"/verbose -if test t = "$PRESERVE_MERGES" +echo $onto > "$dotest"/onto +test -z "$strategy" || echo "$strategy" > "$dotest"/strategy +test t = "$verbose" && : > "$dotest"/verbose +if test t = "$preserve_merges" then - if test -z "$REBASE_ROOT" + if test -z "$rebase_root" then - mkdir "$REWRITTEN" && - for c in $(git merge-base --all $HEAD $UPSTREAM) + mkdir "$rewritten" && + for c in $(git merge-base --all $head $upstream) do - echo $ONTO > "$REWRITTEN"/$c || + echo $onto > "$rewritten"/$c || die "Could not init rewritten commits" done else - mkdir "$REWRITTEN" && - echo $ONTO > "$REWRITTEN"/root || + mkdir "$rewritten" && + 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)" + merges_option= + first_after_upstream="$(git rev-list --reverse --first-parent $upstream..$head | head -n 1)" else - MERGES_OPTION="--no-merges --cherry-pick" + 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" +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 + shortupstream=$(git rev-parse --short $upstream) + revisions=$upstream...$head + shortrevisions=$shortupstream..$shorthead else - REVISIONS=$ONTO...$HEAD - SHORTREVISIONS=$SHORTHEAD + revisions=$onto...$head + shortrevisions=$shorthead fi -git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \ +git rev-list $merges_option --pretty=oneline --abbrev-commit \ --abbrev=7 --reverse --left-right --topo-order \ - $REVISIONS | \ + $revisions | \ sed -n "s/^>//p" | while read -r shortsha1 rest do - if test t != "$PRESERVE_MERGES" + if test t != "$preserve_merges" then - printf '%s\n' "pick $shortsha1 $rest" >> "$TODO" + printf '%s\n' "pick $shortsha1 $rest" >> "$todo" else sha1=$(git rev-parse $shortsha1) - if test -z "$REBASE_ROOT" + 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 \) + if test -f "$rewritten"/$p -a \( $p != $onto -o $sha1 = $first_after_upstream \) then preserve=f fi @@ -983,43 +983,43 @@ do fi if test f = "$preserve" then - touch "$REWRITTEN"/$sha1 - printf '%s\n' "pick $shortsha1 $rest" >> "$TODO" + touch "$rewritten"/$sha1 + printf '%s\n' "pick $shortsha1 $rest" >> "$todo" fi fi done # Watch for commits that been dropped by --cherry-pick -if test t = "$PRESERVE_MERGES" +if test t = "$preserve_merges" then - mkdir "$DROPPED" + mkdir "$dropped" # Save all non-cherry-picked changes - git rev-list $REVISIONS --left-right --cherry-pick | \ - sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks + 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 | + git rev-list $revisions | while read rev do - if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = "" + 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 + 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 + 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 +test -s "$todo" || echo noop >> "$todo" +test -n "$autosquash" && rearrange_squash "$todo" +cat >> "$todo" << EOF -# Rebase $SHORTREVISIONS onto $SHORTONTO +# Rebase $shortrevisions onto $shortonto # # Commands: # p, pick = use commit @@ -1034,18 +1034,18 @@ cat >> "$TODO" << EOF # EOF -has_action "$TODO" || +has_action "$todo" || die_abort "Nothing to do" -cp "$TODO" "$TODO".backup -git_editor "$TODO" || +cp "$todo" "$todo".backup +git_editor "$todo" || die_abort "Could not execute editor" -has_action "$TODO" || +has_action "$todo" || die_abort "Nothing to do" -test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks +test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks -output git checkout $ONTO || die_abort "could not detach HEAD" -git update-ref ORIG_HEAD $HEAD +output git checkout $onto || die_abort "could not detach HEAD" +git update-ref ORIG_HEAD $head do_rest diff --git a/git-rebase.sh b/git-rebase.sh index d689aad38c..dfde62f788 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -36,13 +36,13 @@ cd_to_toplevel LF=' ' -OK_TO_SKIP_PRE_REBASE= -RESOLVEMSG=" +ok_to_skip_pre_rebase= +resolvemsg=" When you have resolved this problem run \"git rebase --continue\". 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\". " -unset newbase +unset onto strategy=recursive strategy_opts= do_merge= @@ -86,7 +86,7 @@ continue_merge () { then echo "You still have unmerged paths in your index" echo "did you forget to use git add?" - die "$RESOLVEMSG" + die "$resolvemsg" fi cmt=`cat "$merge_dir/current"` @@ -96,7 +96,7 @@ continue_merge () { then echo "Commit failed, please do not call \"git commit\"" echo "directly, but instead do one of the following: " - die "$RESOLVEMSG" + die "$resolvemsg" fi if test -z "$GIT_QUIET" then @@ -139,11 +139,11 @@ call_merge () { ;; 1) git rerere $allow_rerere_autoupdate - die "$RESOLVEMSG" + die "$resolvemsg" ;; 2) echo "Strategy: $rv $strategy failed, try another" 1>&2 - die "$RESOLVEMSG" + die "$resolvemsg" ;; *) die "Unknown exit code ($rv) from command:" \ @@ -199,7 +199,7 @@ is_interactive () { } 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" then "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || @@ -234,10 +234,10 @@ while test $# != 0 do case "$1" in --no-verify) - OK_TO_SKIP_PRE_REBASE=yes + ok_to_skip_pre_rebase=yes ;; --verify) - OK_TO_SKIP_PRE_REBASE= + ok_to_skip_pre_rebase= ;; --continue|--skip|--abort) test $total_argc -eq 1 || usage @@ -245,7 +245,7 @@ do ;; --onto) test 2 -le "$#" || usage - newbase="$2" + onto="$2" shift ;; -M|-m|--m|--me|--mer|--merg|--merge) @@ -359,7 +359,7 @@ continue) finish_rb_merge exit fi - git am --resolved --3way --resolvemsg="$RESOLVEMSG" && + git am --resolved --3way --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; @@ -378,7 +378,7 @@ skip) finish_rb_merge exit fi - git am -3 --skip --resolvemsg="$RESOLVEMSG" && + git am -3 --skip --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; @@ -425,7 +425,7 @@ then unset root_flag upstream_arg="$upstream_name" else - test -z "$newbase" && die "--root must be used with --onto" + test -z "$onto" && die "--root must be used with --onto" unset upstream_name unset upstream root_flag="--root" @@ -433,7 +433,7 @@ else fi # Make sure the branch to rebase onto is valid. -onto_name=${newbase-"$upstream_name"} +onto_name=${onto-"$upstream_name"} case "$onto_name" in *...*) if left=${onto_name%...*} right=${onto_name#*...} && @@ -554,7 +554,7 @@ 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" && + git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" && move_to_original_branch ret=$? test 0 != $ret -a -d "$apply_dir" && -- cgit v1.2.3 From 9765b6abeb00145df18cde6b76a9b1fa97eeef53 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:38 -0500 Subject: rebase: align variable content Make sure to interpret variables with the same name in the same way in git-rebase.sh and git-rebase--interactive.sh. This will make it easier to factor out code from git-rebase.sh to git-rebase--interactive and export the variables. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 16 +++++++++++----- git-rebase.sh | 4 +++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2fa348bae8..8b0d7b0ac1 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -339,7 +339,8 @@ pick_one_preserving_merges () { # 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" @@ -827,11 +828,11 @@ first and then run 'git rebase --continue' again." -s) case "$#,$1" in *,*=*) - strategy="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; + strategy=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 1,*) usage ;; *) - strategy="-s $2" + strategy="$2" shift ;; esac ;; @@ -860,9 +861,9 @@ first and then run 'git rebase --continue' again." autosquash= ;; --onto) + test 2 -le "$#" || usage + onto="$2" shift - onto=$(parse_onto "$1") || - die "Does not point to a valid commit: $1" ;; --) shift @@ -872,6 +873,11 @@ first and then run 'git rebase --continue' again." shift done +if test -n "$onto" +then + onto=$(parse_onto "$onto") || die "Does not point to a valid commit: $1" +fi + test -z "$rebase_root" -a $# -ge 1 -a $# -le 2 || test ! -z "$rebase_root" -a $# -le 1 || usage test -d "$dotest" && diff --git a/git-rebase.sh b/git-rebase.sh index dfde62f788..3eac5a48b6 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -43,7 +43,7 @@ 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\". " unset onto -strategy=recursive +strategy= strategy_opts= do_merge= merge_dir="$GIT_DIR"/rebase-merge @@ -130,6 +130,7 @@ call_merge () { 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 @@ -267,6 +268,7 @@ do esac strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")" do_merge=t + test -z "$strategy" && strategy=recursive ;; -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ --strateg=*|--strategy=*|\ -- cgit v1.2.3 From cf432ca0512d68afa603941ecddbb45bb7ded01d Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:39 -0500 Subject: rebase: factor out command line option processing Factor out the command line processing in git-rebase--interactive.sh to git-rebase.sh. Store the options in variables in git-rebase.sh and then source git-rebase--interactive.sh. Suggested-by: Johannes Sixt Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 224 +++++++++++++-------------------------------- git-rebase.sh | 58 ++++++++---- 2 files changed, 100 insertions(+), 182 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 8b0d7b0ac1..9c43c60170 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -10,31 +10,7 @@ # 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] [--] [] -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" @@ -105,16 +81,6 @@ amend="$dotest"/amend 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 ' and run 'git rebase --continue'" @@ -648,15 +614,6 @@ skip_unnecessary_picks () { 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)" @@ -744,134 +701,77 @@ parse_onto () { git rev-parse --verify "$1^0" } -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 -- +case "$action" in +continue) + 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 -- + 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 + test -d "$dotest" || die "No interactive rebase running" - output git reset --hard && do_rest - ;; - -s) - case "$#,$1" in - *,*=*) - strategy=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; - 1,*) - usage ;; - *) - strategy="$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) - test 2 -le "$#" || usage - onto="$2" - shift - ;; - --) - 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 -d "$dotest" || die "No interactive rebase running" + + output git reset --hard && do_rest + ;; +esac if test -n "$onto" then diff --git a/git-rebase.sh b/git-rebase.sh index 3eac5a48b6..aa1bcaf07f 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -64,6 +64,9 @@ type= 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 read_state () { if test "$type" = merge @@ -176,27 +179,12 @@ finish_rb_merge () { 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 - +run_interactive_rebase () { if [ "$interactive_rebase" = implied ]; then GIT_EDITOR=: export GIT_EDITOR fi - - test -n "$interactive_rebase" || test -f "$merge_dir"/interactive + . git-rebase--interactive "$@" } run_pre_rebase_hook () { @@ -211,8 +199,6 @@ run_pre_rebase_hook () { test -f "$apply_dir"/applying && 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 @@ -249,6 +235,19 @@ do onto="$2" shift ;; + -i|--interactive) + interactive_rebase=explicit + ;; + -p|--preserve-merges) + preserve_merges=t + test -z "$interactive_rebase" && interactive_rebase=implied + ;; + --autosquash) + autosquash=t + ;; + --no-autosquash) + autosquash= + ;; -M|-m|--m|--me|--mer|--merg|--merge) do_merge=t ;; @@ -339,7 +338,11 @@ do done test $# -gt 2 && usage -test -n "$action" && test -z "$in_progress" && die "No rebase in progress?" +if test -n "$action" +then + test -z "$in_progress" && die "No rebase in progress?" + test "$type" = interactive && run_interactive_rebase +fi case "$action" in continue) @@ -415,6 +418,21 @@ fi test $# -eq 0 && test -z "$rebase_root" && usage +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 + +test "$type" = interactive && run_interactive_rebase "$@" + require_clean_work_tree "rebase" "Please commit or stash them." if test -z "$rebase_root" -- cgit v1.2.3 From f3889b84010f16558421fd45cb3d0062f9d6e024 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:40 -0500 Subject: rebase -i: remove now unnecessary directory checks Remove directory checks from git-rebase--interactive.sh that are done in git-rebase.sh. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 9c43c60170..4f4fb29a49 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -706,8 +706,6 @@ continue) 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" @@ -749,7 +747,6 @@ abort) comment_for_reflog abort git rerere clear - test -d "$dotest" || die "No interactive rebase running" headname=$(cat "$dotest"/head-name) head=$(cat "$dotest"/head) @@ -767,7 +764,6 @@ skip) comment_for_reflog skip git rerere clear - test -d "$dotest" || die "No interactive rebase running" output git reset --hard && do_rest ;; @@ -780,8 +776,6 @@ fi 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" git var GIT_COMMITTER_IDENT >/dev/null || die "You need to set your committer info first" -- cgit v1.2.3 From 8f9bfb64c5d5179cc7439715379077875248c4ab Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:41 -0500 Subject: rebase: reorder validation steps Reorder validation steps in preparation for the validation to be factored out from git-rebase--interactive.sh into git-rebase.sh. The main functional difference is that the pre-rebase hook will no longer be run if the work tree is dirty. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 4 ++-- git-rebase.sh | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 4f4fb29a49..0f04f36eba 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -792,12 +792,12 @@ else test -z "$onto" && die "You must specify --onto when using --root" fi +require_clean_work_tree "rebase" "Please commit or stash them." + 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" -- || diff --git a/git-rebase.sh b/git-rebase.sh index aa1bcaf07f..4a83d10426 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -433,8 +433,6 @@ fi test "$type" = interactive && run_interactive_rebase "$@" -require_clean_work_tree "rebase" "Please commit or stash them." - if test -z "$rebase_root" then # The upstream head must be given. Make sure it is valid. @@ -476,9 +474,6 @@ case "$onto_name" in ;; 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 # $branch_name -- branch being rebased, or HEAD (already detached) # $orig_head -- commit object name of tip of the branch before rebasing @@ -517,6 +512,8 @@ case "$#" in esac orig_head=$branch +require_clean_work_tree "rebase" "Please commit or stash them." + # Now we are rebasing commits $upstream..$branch (or with --root, # everything leading up to $branch) on top of $onto @@ -538,6 +535,9 @@ then fi fi +# If a hook exists, give it a chance to interrupt +run_pre_rebase_hook "$upstream_arg" "$@" + # 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" -- cgit v1.2.3 From 71786f54c4128821eab8a23f258848c76b5a2071 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:42 -0500 Subject: rebase: factor out reference parsing Remove the parsing and validation of references (onto, upstream, branch) from git-rebase--interactive.sh and rely on the information exported from git-rebase.sh. By using the parsing of the --onto parameter in git-rebase.sh, this improves the error message when the parameter is invalid. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 48 ++++------------------------------------------ git-rebase.sh | 9 +++++---- 2 files changed, 9 insertions(+), 48 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0f04f36eba..fbe12a64ec 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -682,25 +682,6 @@ rearrange_squash () { 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 @@ -769,47 +750,26 @@ skip) ;; esac -if test -n "$onto" -then - onto=$(parse_onto "$onto") || die "Does not point to a valid commit: $1" -fi - -test -z "$rebase_root" -a $# -ge 1 -a $# -le 2 || -test ! -z "$rebase_root" -a $# -le 1 || usage - 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 require_clean_work_tree "rebase" "Please commit or stash them." run_pre_rebase_hook "$upstream_arg" "$@" comment_for_reflog start -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 diff --git a/git-rebase.sh b/git-rebase.sh index 4a83d10426..0f5f5fb206 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -431,8 +431,6 @@ else state_dir="$apply_dir" fi -test "$type" = interactive && run_interactive_rebase "$@" - if test -z "$rebase_root" then # The upstream head must be given. Make sure it is valid. @@ -443,7 +441,7 @@ then unset root_flag upstream_arg="$upstream_name" else - test -z "$onto" && die "--root must be used with --onto" + test -z "$onto" && die "You must specify --onto when using --root" unset upstream_name unset upstream root_flag="--root" @@ -470,7 +468,8 @@ case "$onto_name" in 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 @@ -512,6 +511,8 @@ case "$#" in esac orig_head=$branch +test "$type" = interactive && run_interactive_rebase "$@" + require_clean_work_tree "rebase" "Please commit or stash them." # Now we are rebasing commits $upstream..$branch (or with --root, -- cgit v1.2.3 From caf038cb4ec224ce2fcc241de302a7b37f73963e Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:43 -0500 Subject: rebase: factor out clean work tree check Remove the check for clean work tree from git-rebase--interactive.sh and rely on the check in git-rebase.sh. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 -- git-rebase.sh | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index fbe12a64ec..1ba98a2c67 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -753,8 +753,6 @@ esac git var GIT_COMMITTER_IDENT >/dev/null || die "You need to set your committer info first" -require_clean_work_tree "rebase" "Please commit or stash them." - run_pre_rebase_hook "$upstream_arg" "$@" comment_for_reflog start diff --git a/git-rebase.sh b/git-rebase.sh index 0f5f5fb206..265f01df27 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -511,10 +511,10 @@ case "$#" in esac orig_head=$branch -test "$type" = interactive && run_interactive_rebase "$@" - require_clean_work_tree "rebase" "Please commit or stash them." +test "$type" = interactive && run_interactive_rebase "$@" + # Now we are rebasing commits $upstream..$branch (or with --root, # everything leading up to $branch) on top of $onto -- cgit v1.2.3 From cc1453e1dadc750a2d5c68b0e053b2221d212ef6 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:44 -0500 Subject: rebase: factor out call to pre-rebase hook Remove the call to the pre-rebase hook from git-rebase--interactive.sh and rely on the call in git-rebase.sh. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 14 -------------- git-rebase.sh | 12 +++++++----- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 1ba98a2c67..f94f057dff 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -109,18 +109,6 @@ commit_message () { 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 () { @@ -753,8 +741,6 @@ esac git var GIT_COMMITTER_IDENT >/dev/null || die "You need to set your committer info first" -run_pre_rebase_hook "$upstream_arg" "$@" - comment_for_reflog start if test ! -z "$switch_to" diff --git a/git-rebase.sh b/git-rebase.sh index 265f01df27..87d7fde95c 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -184,7 +184,7 @@ run_interactive_rebase () { GIT_EDITOR=: export GIT_EDITOR fi - . git-rebase--interactive "$@" + . git-rebase--interactive } run_pre_rebase_hook () { @@ -513,15 +513,15 @@ orig_head=$branch require_clean_work_tree "rebase" "Please commit or stash them." -test "$type" = interactive && run_interactive_rebase "$@" - # Now we are rebasing commits $upstream..$branch (or with --root, # everything leading up to $branch) on top of $onto # 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 +# and if this is not an interactive rebase. mb=$(git merge-base "$onto" "$branch") -if test "$upstream" = "$onto" && test "$mb" = "$onto" && +if test "$type" != interactive && test "$upstream" = "$onto" && + test "$mb" = "$onto" && # linear history? ! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null then @@ -539,6 +539,8 @@ fi # If a hook exists, give it a chance to interrupt run_pre_rebase_hook "$upstream_arg" "$@" +test "$type" = interactive && run_interactive_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" -- cgit v1.2.3 From f4107d9cdce49177a056353a162d82555595850e Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:45 -0500 Subject: rebase -i: support --stat Move up the code that displays the diffstat if '--stat' is passed, so that it will be executed before calling git-rebase--interactive.sh. A side effect is that the diffstat is now displayed before "First, rewinding head to replay your work on top of it...". Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index 87d7fde95c..c8a7e4ea56 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -539,13 +539,6 @@ fi # If a hook exists, give it a chance to interrupt run_pre_rebase_hook "$upstream_arg" "$@" -test "$type" = interactive && run_interactive_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 $branch - if test -n "$diffstat" then if test -n "$verbose" @@ -556,6 +549,13 @@ then GIT_PAGER='' git diff --stat --summary "$mb" "$onto" fi +test "$type" = interactive && run_interactive_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 $branch + # If the $onto is a proper descendant of the tip of the branch, then # we just fast-forwarded. if test "$mb" = "$branch" -- cgit v1.2.3 From cb82a05d5e2277d2019c43cadf8abee8bc6f97b6 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:46 -0500 Subject: rebase: remove $branch as synonym for $orig_head The variables $branch and $orig_head were used as synonyms. To avoid confusion, remove $branch. The name 'orig_head' seems more suitable, since that is the name used when the variable is persisted. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index c8a7e4ea56..ed349064a1 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -485,10 +485,10 @@ case "$#" in switch_to="$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 head_name="refs/heads/$1" - elif branch=$(git rev-parse -q --verify "$1") + elif orig_head=$(git rev-parse -q --verify "$1") then head_name="detached HEAD" else @@ -506,24 +506,23 @@ case "$#" in head_name="detached HEAD" branch_name=HEAD ;# detached fi - branch=$(git rev-parse --verify "${branch_name}^0") || exit + orig_head=$(git rev-parse --verify "${branch_name}^0") || exit ;; esac -orig_head=$branch require_clean_work_tree "rebase" "Please commit or stash them." -# Now we are rebasing commits $upstream..$branch (or with --root, -# 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, # but this should be done only when upstream and onto are the same # and if this is not an interactive rebase. -mb=$(git merge-base "$onto" "$branch") +mb=$(git merge-base "$onto" "$orig_head") if test "$type" != interactive && test "$upstream" = "$onto" && test "$mb" = "$onto" && # linear history? - ! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null + ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null then if test -z "$force_rebase" then @@ -554,11 +553,11 @@ test "$type" = interactive && run_interactive_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 $branch +git update-ref ORIG_HEAD $orig_head # If the $onto is a proper descendant of the tip of the branch, then # we just fast-forwarded. -if test "$mb" = "$branch" +if test "$mb" = "$orig_head" then say "Fast-forwarded $branch_name to $onto_name." move_to_original_branch -- cgit v1.2.3 From fa99c1e1e16d347a354c817d96c5abbd5a08fcd8 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:47 -0500 Subject: rebase: extract merge code to new source file Extract the code for merge-based rebase to git-rebase--merge.sh. Suggested-by: Johannes Sixt Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- .gitignore | 1 + Makefile | 1 + git-rebase--merge.sh | 154 ++++++++++++++++++++++++++++++++++++++++++++++++ git-rebase.sh | 162 ++++----------------------------------------------- 4 files changed, 167 insertions(+), 151 deletions(-) create mode 100644 git-rebase--merge.sh diff --git a/.gitignore b/.gitignore index 3dd6ef7d25..a8b98b45e3 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ /git-read-tree /git-rebase /git-rebase--interactive +/git-rebase--merge /git-receive-pack /git-reflog /git-relink diff --git a/Makefile b/Makefile index ade79232f4..9c59e88b8d 100644 --- a/Makefile +++ b/Makefile @@ -370,6 +370,7 @@ SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-pull.sh SCRIPT_SH += git-quiltimport.sh SCRIPT_SH += git-rebase--interactive.sh +SCRIPT_SH += git-rebase--merge.sh SCRIPT_SH += git-rebase.sh SCRIPT_SH += git-repack.sh SCRIPT_SH += git-request-pull.sh diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh new file mode 100644 index 0000000000..c04ce8a297 --- /dev/null +++ b/git-rebase--merge.sh @@ -0,0 +1,154 @@ +#!/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: $rv $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" +echo "$head_name" > "$state_dir/head-name" +echo "$onto" > "$state_dir/onto" +echo "$orig_head" > "$state_dir/orig-head" +echo "$GIT_QUIET" > "$state_dir/quiet" + +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 diff --git a/git-rebase.sh b/git-rebase.sh index ed349064a1..44e169fe15 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -48,7 +48,6 @@ strategy_opts= do_merge= merge_dir="$GIT_DIR"/rebase-merge apply_dir="$GIT_DIR"/rebase-apply -prec=4 verbose= diffstat= test "$(git config --bool rebase.stat)" = true && diffstat=t @@ -68,94 +67,13 @@ preserve_merges= autosquash= test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t -read_state () { - if test "$type" = merge - then - onto_name=$(cat "$state_dir"/onto_name) && - end=$(cat "$state_dir"/end) && - msgnum=$(cat "$state_dir"/msgnum) - fi && +read_basic_state () { head_name=$(cat "$state_dir"/head-name) && onto=$(cat "$state_dir"/onto) && orig_head=$(cat "$state_dir"/orig-head) && GIT_QUIET=$(cat "$state_dir"/quiet) } -continue_merge () { - test -d "$merge_dir" || die "$merge_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 "$merge_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)" >> "$merge_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" >"$merge_dir/msgnum" -} - -call_merge () { - cmt="$(cat "$merge_dir/cmt.$1")" - echo "$cmt" > "$merge_dir/current" - hd=$(git rev-parse --verify HEAD) - cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) - msgnum=$(cat "$merge_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: $rv $strategy failed, try another" 1>&2 - die "$resolvemsg" - ;; - *) - die "Unknown exit code ($rv) from command:" \ - "git-merge-$strategy $cmt^ -- HEAD $cmt" - ;; - esac -} - move_to_original_branch () { case "$head_name" in refs/*) @@ -168,23 +86,12 @@ move_to_original_branch () { esac } -finish_rb_merge () { - move_to_original_branch - git notes copy --for-rewrite=rebase < "$merge_dir"/rewritten - if test -x "$GIT_DIR"/hooks/post-rewrite && - test -s "$merge_dir"/rewritten; then - "$GIT_DIR"/hooks/post-rewrite rebase < "$merge_dir"/rewritten - fi - rm -r "$merge_dir" - say All done. -} - -run_interactive_rebase () { +run_specific_rebase () { if [ "$interactive_rebase" = implied ]; then GIT_EDITOR=: export GIT_EDITOR fi - . git-rebase--interactive + test "$type" != am && . git-rebase--$type } run_pre_rebase_hook () { @@ -341,7 +248,7 @@ test $# -gt 2 && usage if test -n "$action" then test -z "$in_progress" && die "No rebase in progress?" - test "$type" = interactive && run_interactive_rebase + test "$type" = interactive && run_specific_rebase fi case "$action" in @@ -352,44 +259,23 @@ continue) 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 + read_basic_state + run_specific_rebase 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 + read_basic_state + run_specific_rebase git am -3 --skip --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; abort) git rerere clear - read_state + read_basic_state case "$head_name" in refs/*) git symbolic-ref HEAD $head_name || @@ -548,7 +434,7 @@ then GIT_PAGER='' git diff --stat --summary "$mb" "$onto" fi -test "$type" = interactive && run_interactive_rebase +test "$type" = interactive && run_specific_rebase # Detach HEAD and reset the tree say "First, rewinding head to replay your work on top of it..." @@ -590,30 +476,4 @@ fi # start doing a rebase with git-merge # this is rename-aware if the recursive (default) strategy is used -mkdir -p "$merge_dir" -echo "$onto_name" > "$merge_dir/onto_name" -echo "$head_name" > "$merge_dir/head-name" -echo "$onto" > "$merge_dir/onto" -echo "$orig_head" > "$merge_dir/orig-head" -echo "$GIT_QUIET" > "$merge_dir/quiet" - -msgnum=0 -for cmt in `git rev-list --reverse --no-merges "$revisions"` -do - msgnum=$(($msgnum + 1)) - echo "$cmt" > "$merge_dir/cmt.$msgnum" -done - -echo 1 >"$merge_dir/msgnum" -echo $msgnum >"$merge_dir/end" - -end=$msgnum -msgnum=1 - -while test "$msgnum" -le "$end" -do - call_merge "$msgnum" - continue_merge -done - -finish_rb_merge +run_specific_rebase -- cgit v1.2.3 From 46df82d5fa0f83d3c1108ad70248877d6d9b56bb Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:48 -0500 Subject: rebase: extract am code to new source file Extract the code for am-based rebase to git-rebase--am.sh. Suggested-by: Johannes Sixt Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- .gitignore | 1 + Makefile | 1 + git-rebase--am.sh | 34 ++++++++++++++++++++++++++++++++++ git-rebase.sh | 31 ++----------------------------- 4 files changed, 38 insertions(+), 29 deletions(-) create mode 100644 git-rebase--am.sh diff --git a/.gitignore b/.gitignore index a8b98b45e3..7aaf5c7383 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,7 @@ /git-quiltimport /git-read-tree /git-rebase +/git-rebase--am /git-rebase--interactive /git-rebase--merge /git-receive-pack diff --git a/Makefile b/Makefile index 9c59e88b8d..b2501cc03e 100644 --- a/Makefile +++ b/Makefile @@ -369,6 +369,7 @@ SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-pull.sh SCRIPT_SH += git-quiltimport.sh +SCRIPT_SH += git-rebase--am.sh SCRIPT_SH += git-rebase--interactive.sh SCRIPT_SH += git-rebase--merge.sh SCRIPT_SH += git-rebase.sh diff --git a/git-rebase--am.sh b/git-rebase--am.sh new file mode 100644 index 0000000000..263987c55d --- /dev/null +++ b/git-rebase--am.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# Copyright (c) 2010 Junio C Hamano. +# + +. git-sh-setup + +case "$action" in +continue) + git am --resolved --3way --resolvemsg="$resolvemsg" && + move_to_original_branch + exit + ;; +skip) + git am --skip -3 --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" && + echo $head_name > "$state_dir/head-name" && + echo $onto > "$state_dir/onto" && + echo $orig_head > "$state_dir/orig-head" && + echo "$GIT_QUIET" > "$state_dir/quiet" +exit $ret diff --git a/git-rebase.sh b/git-rebase.sh index 44e169fe15..c60221b5a4 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -91,7 +91,7 @@ run_specific_rebase () { GIT_EDITOR=: export GIT_EDITOR fi - test "$type" != am && . git-rebase--$type + . git-rebase--$type } run_pre_rebase_hook () { @@ -261,17 +261,11 @@ continue) } read_basic_state run_specific_rebase - git am --resolved --3way --resolvemsg="$resolvemsg" && - move_to_original_branch - exit ;; skip) git reset --hard HEAD || exit $? read_basic_state run_specific_rebase - git am -3 --skip --resolvemsg="$resolvemsg" && - move_to_original_branch - exit ;; abort) git rerere clear @@ -324,14 +318,12 @@ then shift upstream=`git rev-parse --verify "${upstream_name}^0"` || die "invalid upstream $upstream_name" - unset root_flag upstream_arg="$upstream_name" else test -z "$onto" && die "You must specify --onto when using --root" unset upstream_name unset upstream - root_flag="--root" - upstream_arg="$root_flag" + upstream_arg=--root fi # Make sure the branch to rebase onto is valid. @@ -457,23 +449,4 @@ else revisions="$upstream..$orig_head" fi -if test -z "$do_merge" -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 "$apply_dir" && - echo $head_name > "$apply_dir/head-name" && - echo $onto > "$apply_dir/onto" && - echo $orig_head > "$apply_dir/orig-head" && - echo "$GIT_QUIET" > "$apply_dir/quiet" - exit $ret -fi - -# start doing a rebase with git-merge -# this is rename-aware if the recursive (default) strategy is used - run_specific_rebase -- cgit v1.2.3 From 89c7ae9c3bffe599b46a18a9a504fd3e28a9e715 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:49 -0500 Subject: rebase: show consistent conflict resolution hint When rebase stops due to conflict, interactive rebase currently displays a different hint to the user than non-interactive rebase does. Use the same message for both types of rebase. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f94f057dff..0499f9edd2 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -81,9 +81,7 @@ amend="$dotest"/amend rewritten_list="$dotest"/rewritten-list rewritten_pending="$dotest"/rewritten-pending -GIT_CHERRY_PICK_HELP="\ -hint: after resolving the conflicts, mark the corrected paths -hint: with 'git add ' and run 'git rebase --continue'" +GIT_CHERRY_PICK_HELP="$resolvemsg" export GIT_CHERRY_PICK_HELP warn () { -- cgit v1.2.3 From 431b7e7818fe3d118e4bf9e40ba6807ed2c511be Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:50 -0500 Subject: rebase -i: align variable names Rename variables HEAD and OLDHEAD to orig_head and HEADNAME to head_name, which are the names used in git-rebase.sh. This prepares for factoring out of the code that persists these variables during the entire rebase process. Using the same variable names to mean the same thing in both files also makes the code easier to read. While at it, also remove the DOTEST variable and use the state_dir variable that was inherited from git-rebase.sh instead. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 120 ++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0499f9edd2..fa8bfda765 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -12,22 +12,20 @@ . git-sh-setup -dotest="$GIT_DIR/rebase-merge" - # The file containing rebase commands, comments, and empty lines. # This file is created by "git rebase -i" then edited by the user. As # the lines are processed, they are removed from the front of this # file and written to the tail of $done. -todo="$dotest"/git-rebase-todo +todo="$state_dir"/git-rebase-todo # The rebase command lines that have already been processed. A line # is moved here when it is first handled, before any associated user # actions. -done="$dotest"/done +done="$state_dir"/done # The commit message that is planned to be used for any changes that # need to be committed following a user interaction. -msg="$dotest"/message +msg="$state_dir"/message # The file into which is accumulated the suggested commit message for # squash/fixup commands. When the first of a series of squash/fixups @@ -42,14 +40,14 @@ msg="$dotest"/message # written to the file so far (including the initial "pick" commit). # Each time that a commit message is processed, this line is read and # updated. It is deleted just before the combined commit is made. -squash_msg="$dotest"/message-squash +squash_msg="$state_dir"/message-squash # If the current series of squash/fixups has not yet included a squash # command, then this file exists and holds the commit message of the # original "pick" commit. (If the series ends without a "squash" # command, then this can be used as the commit message of the combined # commit without opening the editor.) -fixup_msg="$dotest"/message-fixup +fixup_msg="$state_dir"/message-fixup # $rewritten is the name of a directory containing files for each # commit that is reachable by at least one merge base of $head and @@ -57,14 +55,14 @@ fixup_msg="$dotest"/message-fixup # might be. This ensures that commits on merged, but otherwise # unrelated side branches are left alone. (Think "X" in the man page's # example.) -rewritten="$dotest"/rewritten +rewritten="$state_dir"/rewritten -dropped="$dotest"/dropped +dropped="$state_dir"/dropped # A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and # GIT_AUTHOR_DATE that will be used for the commit that is currently # being rebased. -author_script="$dotest"/author-script +author_script="$state_dir"/author-script # When an "edit" rebase command is being processed, the SHA1 of the # commit to be edited is recorded in this file. When "git rebase @@ -72,14 +70,14 @@ author_script="$dotest"/author-script # will be amended to the HEAD commit, but only provided the HEAD # commit is still the commit to be edited. When any other rebase # command is processed, this file is deleted. -amend="$dotest"/amend +amend="$state_dir"/amend # For the post-rewrite hook, we make a list of rewritten commits and # their new sha1s. The rewritten-pending list keeps the sha1s of # commits that have been processed, but not committed yet, # e.g. because they are waiting for a 'squash' command. -rewritten_list="$dotest"/rewritten-list -rewritten_pending="$dotest"/rewritten-pending +rewritten_list="$state_dir"/rewritten-list +rewritten_pending="$state_dir"/rewritten-pending GIT_CHERRY_PICK_HELP="$resolvemsg" export GIT_CHERRY_PICK_HELP @@ -145,7 +143,7 @@ make_patch () { *) echo "Root commit" ;; - esac > "$dotest"/patch + esac > "$state_dir"/patch test -f "$msg" || commit_message "$1" > "$msg" test -f "$author_script" || @@ -153,14 +151,14 @@ make_patch () { } die_with_patch () { - echo "$1" > "$dotest"/stopped-sha + echo "$1" > "$state_dir"/stopped-sha make_patch "$1" git rerere die "$2" } die_abort () { - rm -rf "$dotest" + rm -rf "$state_dir" die "$1" } @@ -205,20 +203,20 @@ pick_one_preserving_merges () { esac sha1=$(git rev-parse $sha1) - if test -f "$dotest"/current-commit + if test -f "$state_dir"/current-commit then if test "$fast_forward" = t then while read current_commit do git rev-parse HEAD > "$rewritten"/$current_commit - done <"$dotest"/current-commit - rm "$dotest"/current-commit || + done <"$state_dir"/current-commit + rm "$state_dir"/current-commit || die "Cannot write current commit's replacement sha1" fi fi - echo $sha1 >> "$dotest"/current-commit + echo $sha1 >> "$state_dir"/current-commit # rewrite parents; if none were rewritten, we can fast-forward. new_parents= @@ -425,7 +423,7 @@ do_next () { mark_action_done pick_one $sha1 || die_with_patch $sha1 "Could not apply $sha1... $rest" - echo "$sha1" > "$dotest"/stopped-sha + echo "$sha1" > "$state_dir"/stopped-sha make_patch $sha1 git rev-parse --verify HEAD > "$amend" warn "Stopped at $sha1... $rest" @@ -490,7 +488,7 @@ do_next () { printf 'Executing: %s\n' "$rest" # "exec" command doesn't take a sha1 in the todo-list. # => can't just use $sha1 here. - git rev-parse --verify HEAD > "$dotest"/stopped-sha + git rev-parse --verify HEAD > "$state_dir"/stopped-sha ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution status=$? if test "$status" -ne 0 @@ -525,19 +523,19 @@ do_next () { test -s "$todo" && return comment_for_reflog finish && - headname=$(cat "$dotest"/head-name) && - oldhead=$(cat "$dotest"/head) && - shortonto=$(git rev-parse --short $(cat "$dotest"/onto)) && + head_name=$(cat "$state_dir"/head-name) && + orig_head=$(cat "$state_dir"/head) && + shortonto=$(git rev-parse --short $(cat "$state_dir"/onto)) && newhead=$(git rev-parse HEAD) && - case $headname in + case $head_name in refs/*) - message="$GIT_REFLOG_ACTION: $headname onto $shortonto" && - git update-ref -m "$message" $headname $newhead $oldhead && - git symbolic-ref HEAD $headname + message="$GIT_REFLOG_ACTION: $head_name onto $shortonto" && + git update-ref -m "$message" $head_name $newhead $orig_head && + git symbolic-ref HEAD $head_name ;; esac && { - test ! -f "$dotest"/verbose || - git diff-tree --stat $(cat "$dotest"/head)..HEAD + test ! -f "$state_dir"/verbose || + git diff-tree --stat $(cat "$state_dir"/head)..HEAD } && { test -s "$rewritten_list" && @@ -549,9 +547,9 @@ do_next () { "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list" true # we don't care if this hook failed fi && - rm -rf "$dotest" && + rm -rf "$state_dir" && git gc --auto && - warn "Successfully rebased and updated $headname." + warn "Successfully rebased and updated $head_name." exit } @@ -602,9 +600,9 @@ skip_unnecessary_picks () { get_saved_options () { test -d "$rewritten" && preserve_merges=t - test -f "$dotest"/strategy && strategy="$(cat "$dotest"/strategy)" - test -f "$dotest"/verbose && verbose=t - test -f "$dotest"/rebase-root && rebase_root=t + test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" + test -f "$state_dir"/verbose && verbose=t + test -f "$state_dir"/rebase-root && rebase_root=t } # Rearrange the todo list that has both "pick sha1 msg" and @@ -704,7 +702,7 @@ first and then run 'git rebase --continue' again." } fi - record_in_rewritten "$(cat "$dotest"/stopped-sha)" + record_in_rewritten "$(cat "$state_dir"/stopped-sha)" require_clean_work_tree "rebase" do_rest @@ -715,15 +713,15 @@ abort) git rerere clear - headname=$(cat "$dotest"/head-name) - head=$(cat "$dotest"/head) - case $headname in + head_name=$(cat "$state_dir"/head-name) + orig_head=$(cat "$state_dir"/head) + case $head_name in refs/*) - git symbolic-ref HEAD $headname + git symbolic-ref HEAD $head_name ;; esac && - output git reset --hard $head && - rm -rf "$dotest" + output git reset --hard $orig_head && + rm -rf "$state_dir" exit ;; skip) @@ -747,28 +745,28 @@ then die "Could not checkout $switch_to" fi -head=$(git rev-parse --verify HEAD) || die "No HEAD?" -mkdir "$dotest" || die "Could not create temporary $dotest" +orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?" +mkdir "$state_dir" || die "Could not create temporary $state_dir" -: > "$dotest"/interactive || die "Could not mark as interactive" -echo "$head_name" > "$dotest"/head-name +: > "$state_dir"/interactive || die "Could not mark as interactive" +echo "$head_name" > "$state_dir"/head-name -echo $head > "$dotest"/head +echo $orig_head > "$state_dir"/head case "$rebase_root" in '') - rm -f "$dotest"/rebase-root ;; + rm -f "$state_dir"/rebase-root ;; *) - : >"$dotest"/rebase-root ;; + : >"$state_dir"/rebase-root ;; esac -echo $onto > "$dotest"/onto -test -z "$strategy" || echo "$strategy" > "$dotest"/strategy -test t = "$verbose" && : > "$dotest"/verbose +echo $onto > "$state_dir"/onto +test -z "$strategy" || echo "$strategy" > "$state_dir"/strategy +test t = "$verbose" && : > "$state_dir"/verbose if test t = "$preserve_merges" then if test -z "$rebase_root" then mkdir "$rewritten" && - for c in $(git merge-base --all $head $upstream) + for c in $(git merge-base --all $orig_head $upstream) do echo $onto > "$rewritten"/$c || die "Could not init rewritten commits" @@ -782,21 +780,21 @@ then # 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)" + first_after_upstream="$(git rev-list --reverse --first-parent $upstream..$orig_head | head -n 1)" else merges_option="--no-merges --cherry-pick" fi -shorthead=$(git rev-parse --short $head) +shorthead=$(git rev-parse --short $orig_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 + revisions=$upstream...$orig_head shortrevisions=$shortupstream..$shorthead else - revisions=$onto...$head + revisions=$onto...$orig_head shortrevisions=$shorthead fi git rev-list $merges_option --pretty=oneline --abbrev-commit \ @@ -837,13 +835,13 @@ 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 + sed -n "s/^>//p" > "$state_dir"/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)" = "" + if test -f "$rewritten"/$rev -a "$(sane_grep "$rev" "$state_dir"/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, @@ -889,5 +887,5 @@ has_action "$todo" || test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks output git checkout $onto || die_abort "could not detach HEAD" -git update-ref ORIG_HEAD $head +git update-ref ORIG_HEAD $orig_head do_rest -- cgit v1.2.3 From 4974c2caa215a78dd0c6e3665e23e029d98cbbeb Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:51 -0500 Subject: rebase: make -v a tiny bit more verbose To make it possible to later remove the handling of --abort from git-rebase--interactive.sh, align the implementation in git-rebase.sh with the former by making it a bit more verbose. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 14 -------------- git-rebase.sh | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index fa8bfda765..affa467a63 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -86,20 +86,6 @@ warn () { printf '%s\n' "$*" >&2 } -output () { - case "$verbose" in - '') - output=$("$@" 2>&1 ) - status=$? - test $status != 0 && printf "%s\n" "$output" - return $status - ;; - *) - "$@" - ;; - esac -} - # Output the commit message for the specified commit. commit_message () { git cat-file commit "$1" | sed "1,/^$/d" diff --git a/git-rebase.sh b/git-rebase.sh index c60221b5a4..42d635bc29 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -74,6 +74,20 @@ read_basic_state () { GIT_QUIET=$(cat "$state_dir"/quiet) } +output () { + case "$verbose" in + '') + output=$("$@" 2>&1 ) + status=$? + test $status != 0 && printf "%s\n" "$output" + return $status + ;; + *) + "$@" + ;; + esac +} + move_to_original_branch () { case "$head_name" in refs/*) @@ -263,7 +277,7 @@ continue) run_specific_rebase ;; skip) - git reset --hard HEAD || exit $? + output git reset --hard HEAD || exit $? read_basic_state run_specific_rebase ;; @@ -276,7 +290,7 @@ abort) die "Could not move back to $head_name" ;; esac - git reset --hard $orig_head + output git reset --hard $orig_head rm -r "$state_dir" exit ;; -- cgit v1.2.3 From 2959c283662c62e90d08d3795073534f278deee6 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:52 -0500 Subject: rebase: factor out sub command handling Factor out the common parts of the handling of the sub commands '--continue', '--skip' and '--abort'. The '--abort' handling can handled completely in git-rebase.sh. After this refactoring, the calls to git-rebase--am.sh, git-rebase--merge.sh and git-rebase--interactive.sh will be better aligned. There will only be one call to interactive rebase that will shortcut the very last part of git-rebase.sh. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 34 +++------------------------------- git-rebase.sh | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index affa467a63..4af0bc6c8f 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -509,9 +509,7 @@ do_next () { test -s "$todo" && return comment_for_reflog finish && - head_name=$(cat "$state_dir"/head-name) && - orig_head=$(cat "$state_dir"/head) && - shortonto=$(git rev-parse --short $(cat "$state_dir"/onto)) && + shortonto=$(git rev-parse --short $onto) && newhead=$(git rev-parse HEAD) && case $head_name in refs/*) @@ -521,7 +519,7 @@ do_next () { ;; esac && { test ! -f "$state_dir"/verbose || - git diff-tree --stat $(cat "$state_dir"/head)..HEAD + git diff-tree --stat $orig_head..HEAD } && { test -s "$rewritten_list" && @@ -655,14 +653,6 @@ rearrange_squash () { case "$action" in continue) get_saved_options - comment_for_reflog 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 || - die "Working tree is dirty" # do we have anything to commit? if git diff-index --cached --quiet --ignore-submodules HEAD -- @@ -693,30 +683,12 @@ first and then run 'git rebase --continue' again." require_clean_work_tree "rebase" do_rest ;; -abort) - get_saved_options - comment_for_reflog abort - - git rerere clear - - head_name=$(cat "$state_dir"/head-name) - orig_head=$(cat "$state_dir"/head) - case $head_name in - refs/*) - git symbolic-ref HEAD $head_name - ;; - esac && - output git reset --hard $orig_head && - rm -rf "$state_dir" - exit - ;; skip) get_saved_options - comment_for_reflog skip git rerere clear - output git reset --hard && do_rest + do_rest ;; esac diff --git a/git-rebase.sh b/git-rebase.sh index 42d635bc29..21bb0276e1 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -70,7 +70,12 @@ test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t read_basic_state () { head_name=$(cat "$state_dir"/head-name) && onto=$(cat "$state_dir"/onto) && - orig_head=$(cat "$state_dir"/orig-head) && + if test "$type" = interactive + then + orig_head=$(cat "$state_dir"/head) + else + orig_head=$(cat "$state_dir"/orig-head) + fi && GIT_QUIET=$(cat "$state_dir"/quiet) } @@ -262,11 +267,19 @@ test $# -gt 2 && usage if test -n "$action" then test -z "$in_progress" && die "No rebase in progress?" - test "$type" = interactive && run_specific_rebase + # Only interactive rebase uses detailed reflog messages + if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase + then + GIT_REFLOG_ACTION="rebase -i ($action)" + export GIT_REFLOG_ACTION + fi fi case "$action" in 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" -- cgit v1.2.3 From 84df4560ed92a771d38081ecca2d40ca35811907 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:53 -0500 Subject: rebase: extract code for writing basic state Extract the code for writing the state to rebase-apply/ or rebase-merge/ when a rebase is initiated. This will make it easier to later make both interactive and non-interactive rebase remember the options used. Note that non-interactive rebase stores the sha1 of the original head in a file called orig-head, while interactive rebase stores it in a file called head. Change this by writing to orig-head in both cases. When reading, try to read from orig-head. If that fails, read from head instead. This protects users who upgraded git while they had an ongoing interactive rebase, while still making it possible to remove the code that reads from head at some point in the future. Helped-by: Thomas Rast Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--am.sh | 6 +----- git-rebase--interactive.sh | 5 +---- git-rebase--merge.sh | 5 +---- git-rebase.sh | 16 +++++++++++++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/git-rebase--am.sh b/git-rebase--am.sh index 263987c55d..c9604a67d1 100644 --- a/git-rebase--am.sh +++ b/git-rebase--am.sh @@ -26,9 +26,5 @@ git format-patch -k --stdout --full-index --ignore-if-in-upstream \ git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" && move_to_original_branch ret=$? -test 0 != $ret -a -d "$state_dir" && - echo $head_name > "$state_dir/head-name" && - echo $onto > "$state_dir/onto" && - echo $orig_head > "$state_dir/orig-head" && - echo "$GIT_QUIET" > "$state_dir/quiet" +test 0 != $ret -a -d "$state_dir" && write_basic_state exit $ret diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 4af0bc6c8f..437cc52b24 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -707,16 +707,13 @@ orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?" mkdir "$state_dir" || die "Could not create temporary $state_dir" : > "$state_dir"/interactive || die "Could not mark as interactive" -echo "$head_name" > "$state_dir"/head-name - -echo $orig_head > "$state_dir"/head +write_basic_state case "$rebase_root" in '') rm -f "$state_dir"/rebase-root ;; *) : >"$state_dir"/rebase-root ;; esac -echo $onto > "$state_dir"/onto test -z "$strategy" || echo "$strategy" > "$state_dir"/strategy test t = "$verbose" && : > "$state_dir"/verbose if test t = "$preserve_merges" diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index c04ce8a297..eb0f7bc157 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -127,10 +127,7 @@ esac mkdir -p "$state_dir" echo "$onto_name" > "$state_dir/onto_name" -echo "$head_name" > "$state_dir/head-name" -echo "$onto" > "$state_dir/onto" -echo "$orig_head" > "$state_dir/orig-head" -echo "$GIT_QUIET" > "$state_dir/quiet" +write_basic_state msgnum=0 for cmt in `git rev-list --reverse --no-merges "$revisions"` diff --git a/git-rebase.sh b/git-rebase.sh index 21bb0276e1..5a399aa4cf 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -70,15 +70,25 @@ test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t read_basic_state () { head_name=$(cat "$state_dir"/head-name) && onto=$(cat "$state_dir"/onto) && - if test "$type" = interactive + # We always write to orig-head, but interactive rebase used to write to + # head. Fall back to reading from head to cover for the case that the + # user upgraded git with an ongoing interactive rebase. + if test -f "$state_dir"/orig-head then - orig_head=$(cat "$state_dir"/head) - else orig_head=$(cat "$state_dir"/orig-head) + else + orig_head=$(cat "$state_dir"/head) fi && GIT_QUIET=$(cat "$state_dir"/quiet) } +write_basic_state () { + echo "$head_name" > "$state_dir"/head-name && + echo "$onto" > "$state_dir"/onto && + echo "$orig_head" > "$state_dir"/orig-head && + echo "$GIT_QUIET" > "$state_dir"/quiet +} + output () { case "$verbose" in '') -- cgit v1.2.3 From 7b37a7c6204998faa80a4bdc1e1ab824bd37d941 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:54 -0500 Subject: rebase: remember verbose option Currently, only interactive rebase remembers the value of the '-v' flag from the initial invocation. Make non-interactive rebase also remember it. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 -- git-rebase.sh | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 437cc52b24..f076a6edfb 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -585,7 +585,6 @@ skip_unnecessary_picks () { get_saved_options () { test -d "$rewritten" && preserve_merges=t test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" - test -f "$state_dir"/verbose && verbose=t test -f "$state_dir"/rebase-root && rebase_root=t } @@ -715,7 +714,6 @@ case "$rebase_root" in : >"$state_dir"/rebase-root ;; esac test -z "$strategy" || echo "$strategy" > "$state_dir"/strategy -test t = "$verbose" && : > "$state_dir"/verbose if test t = "$preserve_merges" then if test -z "$rebase_root" diff --git a/git-rebase.sh b/git-rebase.sh index 5a399aa4cf..8a36e7a861 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -79,14 +79,16 @@ read_basic_state () { else orig_head=$(cat "$state_dir"/head) fi && - GIT_QUIET=$(cat "$state_dir"/quiet) + GIT_QUIET=$(cat "$state_dir"/quiet) && + test -f "$state_dir"/verbose && verbose=t } write_basic_state () { echo "$head_name" > "$state_dir"/head-name && echo "$onto" > "$state_dir"/onto && echo "$orig_head" > "$state_dir"/orig-head && - echo "$GIT_QUIET" > "$state_dir"/quiet + echo "$GIT_QUIET" > "$state_dir"/quiet && + test t = "$verbose" && : > "$state_dir"/verbose } output () { -- cgit v1.2.3 From 80ff47957b3a8ae057178a7b1113d171404e938f Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:55 -0500 Subject: rebase: remember strategy and strategy options When a rebase is resumed, interactive rebase remembers any merge strategy passed when the rebase was initated. Make non-interactive rebase remember any merge strategy as well. Also make non-interactive rebase remember any merge strategy options. To be able to resume a rebase that was initiated with an older version of git (older than this commit), make sure not to expect the saved option files to exist. Test case idea taken from Junio's 71fc224 (t3402: test "rebase -s -X", 2010-11-11). Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 -- git-rebase.sh | 6 ++++++ t/t3418-rebase-continue.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f076a6edfb..5773b75f54 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -584,7 +584,6 @@ skip_unnecessary_picks () { get_saved_options () { test -d "$rewritten" && preserve_merges=t - test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" test -f "$state_dir"/rebase-root && rebase_root=t } @@ -713,7 +712,6 @@ case "$rebase_root" in *) : >"$state_dir"/rebase-root ;; esac -test -z "$strategy" || echo "$strategy" > "$state_dir"/strategy if test t = "$preserve_merges" then if test -z "$rebase_root" diff --git a/git-rebase.sh b/git-rebase.sh index 8a36e7a861..f4ad7c1659 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -81,6 +81,9 @@ read_basic_state () { fi && GIT_QUIET=$(cat "$state_dir"/quiet) && test -f "$state_dir"/verbose && verbose=t + test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" + test -f "$state_dir"/strategy_opts && + strategy_opts="$(cat "$state_dir"/strategy_opts)" } write_basic_state () { @@ -89,6 +92,9 @@ write_basic_state () { echo "$orig_head" > "$state_dir"/orig-head && echo "$GIT_QUIET" > "$state_dir"/quiet && test t = "$verbose" && : > "$state_dir"/verbose + test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy + test -n "$strategy_opts" && echo "$strategy_opts" > \ + "$state_dir"/strategy_opts } output () { diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 1d90191e54..5469546c32 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -45,4 +45,33 @@ test_expect_success 'rebase --continue can not be used with other options' ' 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_done -- cgit v1.2.3 From b3e4847e50cf0ab3da4ad9664a5e4382e778ebd5 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:56 -0500 Subject: rebase -m: remember allow_rerere_autoupdate option If '--[no-]allow_rerere_autoupdate' is passed when 'git rebase -m' is called and a merge conflict occurs, the flag will be forgotten for the rest of the rebase process. Make rebase remember it by saving the value. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 4 ++++ t/t3418-rebase-continue.sh | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/git-rebase.sh b/git-rebase.sh index f4ad7c1659..be9ec2a1f7 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -84,6 +84,8 @@ read_basic_state () { test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" test -f "$state_dir"/strategy_opts && strategy_opts="$(cat "$state_dir"/strategy_opts)" + test -f "$state_dir"/allow_rerere_autoupdate && + allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)" } write_basic_state () { @@ -95,6 +97,8 @@ write_basic_state () { test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy test -n "$strategy_opts" && echo "$strategy_opts" > \ "$state_dir"/strategy_opts + test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \ + "$state_dir"/allow_rerere_autoupdate } output () { diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 5469546c32..1e855cdae5 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -74,4 +74,25 @@ test_expect_success 'rebase --continue remembers merge strategy and options' ' 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 -- cgit v1.2.3 From b325680930c007f87d35fdc60566b3441fedc7c3 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:57 -0500 Subject: rebase -m: don't print exit code 2 when merge fails When the merge strategy fails, a message suggesting the user to try another strategy is displayed. Remove the "$rv" (which is always equal to "2" in this case) from that message. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--merge.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index eb0f7bc157..26afc75cc7 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -78,7 +78,7 @@ call_merge () { die "$resolvemsg" ;; 2) - echo "Strategy: $rv $strategy failed, try another" 1>&2 + echo "Strategy: $strategy failed, try another" 1>&2 die "$resolvemsg" ;; *) -- cgit v1.2.3 From c5e610be5049f04b3ab8370bb8d1649347d2db87 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:58 -0500 Subject: git-rebase--am: remove unnecessary --3way option Since 22db240 (git-am: propagate --3way options as well, 2008-12-04), the --3way has been propageted across failure, so it is since pointless to pass it to git-am when resuming. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--am.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-rebase--am.sh b/git-rebase--am.sh index c9604a67d1..c815a2412c 100644 --- a/git-rebase--am.sh +++ b/git-rebase--am.sh @@ -7,12 +7,12 @@ case "$action" in continue) - git am --resolved --3way --resolvemsg="$resolvemsg" && + git am --resolved --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; skip) - git am --skip -3 --resolvemsg="$resolvemsg" && + git am --skip --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; -- cgit v1.2.3 From c6f7de5455269ac1fcd268cd3bf592a0f74c1ef8 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:43:59 -0500 Subject: rebase -i: don't read unused variable preserve_merges Since 8e4a91b (rebase -i: remember the settings of -v, -s and -p when interrupted, 2007-07-08), the variable preserve_merges (then called PRESERVE_MERGES) was detected from the state saved in $GIT_DIR/rebase-merge in order to be used when the rebase resumed, but its value was never actually used. The variable's value was only used when the rebase was initated. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5773b75f54..cf19bf5ae2 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -583,7 +583,6 @@ skip_unnecessary_picks () { } get_saved_options () { - test -d "$rewritten" && preserve_merges=t test -f "$state_dir"/rebase-root && rebase_root=t } -- cgit v1.2.3 From c71f8f3d501b155c3efa6aea2bc7768f7ace8cd1 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sun, 6 Feb 2011 13:44:00 -0500 Subject: rebase -i: remove unnecessary state rebase-root Before calling 'git cherry-pick', interactive rebase currently checks if we are rebasing from root (if --root was passed). If we are, the '--ff' flag to 'git cherry-pick' is omitted. However, according to the documentation for 'git cherry-pick --ff', "If the current HEAD is the same as the parent of the cherry-picked commit, then a fast forward to this commit will be performed.". This should never be the case when rebasing from root, so it should not matter whether --ff is passed, so simplify the code by removing the condition. Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index cf19bf5ae2..6566d319aa 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -168,11 +168,6 @@ pick_one () { output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" test -d "$rewritten" && pick_one_preserving_merges "$@" && return - if test -n "$rebase_root" - then - output git cherry-pick "$@" - return - fi output git cherry-pick $ff "$@" } @@ -582,10 +577,6 @@ skip_unnecessary_picks () { die "Could not skip unnecessary pick commands" } -get_saved_options () { - test -f "$state_dir"/rebase-root && rebase_root=t -} - # Rearrange the todo list that has both "pick sha1 msg" and # "pick sha1 fixup!/squash! msg" appears in it so that the latter # comes immediately after the former, and change "pick" to @@ -649,8 +640,6 @@ rearrange_squash () { case "$action" in continue) - get_saved_options - # do we have anything to commit? if git diff-index --cached --quiet --ignore-submodules HEAD -- then @@ -681,8 +670,6 @@ first and then run 'git rebase --continue' again." do_rest ;; skip) - get_saved_options - git rerere clear do_rest @@ -705,12 +692,6 @@ mkdir "$state_dir" || die "Could not create temporary $state_dir" : > "$state_dir"/interactive || die "Could not mark as interactive" write_basic_state -case "$rebase_root" in -'') - rm -f "$state_dir"/rebase-root ;; -*) - : >"$state_dir"/rebase-root ;; -esac if test t = "$preserve_merges" then if test -z "$rebase_root" -- cgit v1.2.3 From 15a147e61898d25ec8b539190e87f3a09592c9c8 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Wed, 9 Feb 2011 20:54:02 -0500 Subject: rebase: use @{upstream} if no upstream specified 'git rebase' without arguments is currently not supported. Make it default to 'git rebase @{upstream}'. That is also what 'git pull [--rebase]' defaults to, so it only makes sense that 'git rebase' defaults to the same thing. Defaulting to @{upstream} will make it possible to run e.g. 'git rebase -i' without arguments, which is probably a quite common use case. It also improves the scenario where you have multiple branches that rebase against a remote-tracking branch, where you currently have to choose between the extra network delay of 'git pull' or the slightly awkward keys to enter 'git rebase @{u}'. The error reporting when no upstream is configured for the current branch or when no branch is checked out is reused from git-pull.sh. A function is extracted into git-parse-remote.sh for this purpose. Helped-by: Yann Dirson Helped-by: Jonathan Nieder Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- Documentation/config.txt | 2 +- Documentation/git-rebase.txt | 11 +++++++++-- git-parse-remote.sh | 38 ++++++++++++++++++++++++++++++++++++++ git-pull.sh | 32 ++++---------------------------- git-rebase.sh | 21 +++++++++++++++------ t/t3400-rebase.sh | 27 ++++++++++++++++++--------- 6 files changed, 85 insertions(+), 46 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c5e183516a..b4e65b8151 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -646,7 +646,7 @@ branch..remote:: branch..merge:: Defines, together with branch..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). When in branch , it tells 'git fetch' the default refspec to be marked for merging in FETCH_HEAD. The value is diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 96680c8456..d3e998df46 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git rebase' [-i | --interactive] [options] [--onto ] - [] + [] [] 'git rebase' [-i | --interactive] [options] --onto --root [] @@ -21,6 +21,12 @@ If is specified, 'git rebase' will perform an automatic `git checkout ` before doing anything else. Otherwise it remains on the current branch. +If is not specified, the upstream configured in +branch..remote and branch..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 in are saved to a temporary area. This is the same set of commits that would be shown by `git log ..HEAD` (or @@ -216,7 +222,8 @@ leave out at most one of A and B, in which case it defaults to HEAD. :: 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. :: Working branch; defaults to HEAD. diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 1cc2ba6e09..be17ecbd1e 100644 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -99,3 +99,41 @@ get_remote_merge_branch () { 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..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 = + merge = " + test rebase = "$op_type" && + echo " rebase = true" + echo " + [remote \"\"] + url = + fetch = + +See git-config(1) for details." + fi + exit 1 +} diff --git a/git-pull.sh b/git-pull.sh index eb87f49062..2cdea26265 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -163,34 +163,10 @@ error_on_no_merge_candidates () { 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 "for your current branch, you must specify a branch on the command line." - elif [ -z "$curr_branch" ]; then - echo "You are not currently on a branch, so I cannot use any" - echo "'branch..merge' in your configuration file." - echo "Please specify which remote branch you want to use on the command" - echo "line and try again (e.g. 'git pull ')." - 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 ')." - 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 = " - echo " merge = " - test rebase = "$op_type" && - echo " rebase = true" - echo - echo " [remote \"\"]" - echo " url = " - echo " fetch = " - echo - echo "See git-config(1) for details." + elif [ -z "$curr_branch" -o -z "$upstream" ]; then + . git-parse-remote + error_on_missing_default_upstream "pull" $op_type $op_prep \ + "git pull " else echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" echo "from the remote, but no such ref was fetched." diff --git a/git-rebase.sh b/git-rebase.sh index be9ec2a1f7..a040ab51cc 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Junio C Hamano. # -USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto ] (|--root) [] [--quiet | -q]' +USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto ] [|--root] [] [--quiet | -q]' LONG_USAGE='git-rebase replaces with a new branch of the same name. When the --onto option is provided the new branch starts out with a HEAD equal to , otherwise it is equal to @@ -345,8 +345,6 @@ and run me again. I am stopping in case you still have something valuable there.' fi -test $# -eq 0 && test -z "$rebase_root" && usage - if test -n "$interactive_rebase" then type=interactive @@ -362,9 +360,20 @@ fi if test -z "$rebase_root" then - # The upstream head must be given. Make sure it is valid. - upstream_name="$1" - shift + case "$#" in + 0) + 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 " + fi + ;; + *) upstream_name="$1" + shift + ;; + esac upstream=`git rev-parse --verify "${upstream_name}^0"` || die "invalid upstream $upstream_name" upstream_arg="$upstream_name" diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 349eebd542..6eaecec906 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -158,15 +158,24 @@ test_expect_success 'Show verbose error when HEAD could not be detached' ' ' rm -f B -test_expect_success 'dump usage when upstream arg is missing' ' - git checkout -b usage topic && - test_must_fail git rebase 2>error1 && - grep "[Uu]sage" error1 && - test_must_fail git rebase --abort 2>error2 && - grep "No rebase in progress" error2 && - test_must_fail git rebase --onto master 2>error3 && - grep "[Uu]sage" error3 && - ! grep "can.t shift" error3 +test_expect_success 'fail when upstream arg is missing and not on branch' ' + git checkout topic && + test_must_fail git rebase >output.out && + grep "You are not currently on a branch" output.out +' + +test_expect_success 'fail when upstream arg is missing and not configured' ' + git checkout -b no-config topic && + 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' ' -- cgit v1.2.3 From fdb76c104af5196fe1faf6d84209daf752e87010 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Thu, 24 Feb 2011 22:32:06 -0500 Subject: Makefile: do not install sourced rebase scripts When git-rebase.sh recently started sourcing git-rebase--interactive.sh instead of executing it, executable bit of the latter file should have been turned off and it should have been moved from SCRIPT_SH to SCRIPT_LIB in the Makefile. Its two new siblings, git-rebase--am.sh and git-rebase--merge.sh (whose executable bits are already off) should also be moved to SCRIPT_LIB in the Makefile. Reported-by: Johannes Sixt Helped-by: Jeff King Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- Makefile | 6 +++--- git-rebase--interactive.sh | 0 2 files changed, 3 insertions(+), 3 deletions(-) mode change 100755 => 100644 git-rebase--interactive.sh diff --git a/Makefile b/Makefile index b2501cc03e..acde60aaba 100644 --- a/Makefile +++ b/Makefile @@ -369,9 +369,6 @@ SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-pull.sh SCRIPT_SH += git-quiltimport.sh -SCRIPT_SH += git-rebase--am.sh -SCRIPT_SH += git-rebase--interactive.sh -SCRIPT_SH += git-rebase--merge.sh SCRIPT_SH += git-rebase.sh SCRIPT_SH += git-repack.sh SCRIPT_SH += git-request-pull.sh @@ -381,6 +378,9 @@ SCRIPT_SH += git-web--browse.sh SCRIPT_LIB += git-mergetool--lib 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_PERL += git-add--interactive.perl diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh old mode 100755 new mode 100644 -- cgit v1.2.3 From 45e2acf3d33b2bc635f14af0c1d9ce698328954f Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Mon, 28 Feb 2011 20:59:26 -0500 Subject: rebase: define options in OPTIONS_SPEC Interactive rebase used to have its own command line processing. Since it used the 'git rev-parse --parseopt' functionality exposed through git-sh-setup, it had some flexibility, like matching prefixes of long options, that non-interactive rebase didn't. When interactive rebase's command line processing was factored out into git-rebase.sh in cf432ca (rebase: factor out command line option processing, 2011-02-06), this flexibility was lost. Give back that flexibility to interactive and non-interactive by defining its options in OPTIONS_SPEC. Also improve the usage message to contain the --continue, --skip and --abort sub commands. Reported-by: Johannes Sixt Signed-off-by: Martin von Zweigbergk Signed-off-by: Junio C Hamano --- git-rebase.sh | 101 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/git-rebase.sh b/git-rebase.sh index a040ab51cc..7a54bfc618 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -28,7 +28,39 @@ Example: git-rebase master~1 topic ' SUBDIRECTORY_OK=Yes -OPTIONS_SPEC= +OPTIONS_KEEPDASHDASH= +OPTIONS_SPEC="\ +git rebase [-i] [options] [--onto ] [] [] +git rebase [-i] [options] --onto --root [] +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 set_reflog_action rebase require_work_tree @@ -175,7 +207,7 @@ do ok_to_skip_pre_rebase= ;; --continue|--skip|--abort) - test $total_argc -eq 1 || usage + test $total_argc -eq 2 || usage action=${1##--} ;; --onto) @@ -183,10 +215,10 @@ do onto="$2" shift ;; - -i|--interactive) + -i) interactive_rebase=explicit ;; - -p|--preserve-merges) + -p) preserve_merges=t test -z "$interactive_rebase" && interactive_rebase=implied ;; @@ -196,62 +228,42 @@ do --no-autosquash) autosquash= ;; - -M|-m|--m|--me|--mer|--merg|--merge) + -M|-m) do_merge=t ;; - -X*|--strategy-option*) - case "$#,$1" in - 1,-X|1,--strategy-option) - usage ;; - *,-X|*,--strategy-option) - newopt="$2" - shift ;; - *,--strategy-option=*) - newopt="$(expr " $1" : ' --strategy-option=\(.*\)')" ;; - *,-X*) - newopt="$(expr " $1" : ' -X\(.*\)')" ;; - 1,*) - usage ;; - esac - strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")" + -X) + shift + strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")" do_merge=t test -z "$strategy" && strategy=recursive ;; - -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ - --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 + -s) + shift + strategy="$1" do_merge=t ;; - -n|--no-stat) + -n) diffstat= ;; --stat) diffstat=t ;; - -v|--verbose) + -v) verbose=t diffstat=t GIT_QUIET= ;; - -q|--quiet) + -q) GIT_QUIET=t git_am_opt="$git_am_opt -q" verbose= diffstat= ;; - --whitespace=*) - git_am_opt="$git_am_opt $1" + --whitespace) + shift + git_am_opt="$git_am_opt --whitespace=$1" case "$1" in - --whitespace=fix|--whitespace=strip) + fix|strip) force_rebase=t ;; esac @@ -263,22 +275,21 @@ do git_am_opt="$git_am_opt $1" force_rebase=t ;; - -C*) - git_am_opt="$git_am_opt $1" + -C) + shift + git_am_opt="$git_am_opt -C$1" ;; --root) 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 ;; --rerere-autoupdate|--no-rerere-autoupdate) allow_rerere_autoupdate="$1" ;; - -*) - usage - ;; - *) + --) + shift break ;; esac -- cgit v1.2.3