From 8a93f9576a705753845ffa9fc5eb62c1d7fdd4a1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 16 Mar 2012 07:48:33 -0700 Subject: rebase -i: remind that the lines are top-to-bottom Nelson Benitez Leon opened a discussion with a patch with this in the note: Hi, I was using git rebase -i for some time now and never occured to me I could reorder the commit lines to affect the order the commits are applied, learnt that recently from a git tutorial. Nelson's patch was to stress the fact that the lines in the insn sheet can be re-ordered in a much more verbose way. Let's add a one-liner reminder and also remind that the lines in the insn sheet is read from top to bottom, unlike the "git log" output. Discussion-triggered-by: Nelson Benitez Leon Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 ++ 1 file changed, 2 insertions(+) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5812222eb9..2b7eb6dda4 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -846,6 +846,8 @@ cat >> "$todo" << EOF # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # +# These lines can be re-ordered; they are executed from top to bottom. +# # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # -- cgit v1.2.1 From a6754cda4362d129738d42d2683d07d433379e99 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Sat, 7 Apr 2012 11:20:53 +0100 Subject: rebase -i continue: don't skip commits that only change submodules When git-rebase--interactive stops due to a conflict and the only change to be committed is in a submodule, the test for whether there is anything to be committed ignores the staged submodule change. This leads rebase to skip creating the commit for the change. While unstaged submodule changes should be ignored to avoid needing to update submodules during a rebase, it is safe to remove the --ignore-submodules option to diff-index because --cached ensures that it is only checking the index. This was discussed in [1] and a test is included to ensure that unstaged changes are still ignored correctly. [1] http://thread.gmane.org/gmane.comp.version-control.git/188713 Signed-off-by: John Keeping Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5812222eb9..454674976e 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -672,7 +672,7 @@ rearrange_squash () { case "$action" in continue) # do we have anything to commit? - if git diff-index --cached --quiet --ignore-submodules HEAD -- + if git diff-index --cached --quiet HEAD -- then : Nothing to commit -- skip this else -- cgit v1.2.1 From 90e1818f9a06015159712e204dd90868e0a6c421 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 20 Apr 2012 10:36:17 -0400 Subject: git-rebase: add keep_empty flag Add a command line switch to git-rebase to allow a user the ability to specify that they want to keep any commits in a series that are empty. When git-rebase's type is am, then this option will automatically keep any commit that has a tree object identical to its parent. This patch changes the default behavior of interactive rebases as well. With this patch, git-rebase -i will produce a revision set passed to git-revision-editor, in which empty commits are commented out. Empty commits may be kept manually by uncommenting them. If the new --keep-empty option is used in an interactive rebase the empty commits will automatically all be uncommented in the editor. Signed-off-by: Neil Horman Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5812222eb9..70538bb20f 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -167,6 +167,14 @@ has_action () { sane_grep '^[^#]' "$1" >/dev/null } +is_empty_commit() { + tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null || + die "$1: not a commit that can be picked") + ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null || + ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904) + test "$tree" = "$ptree" +} + # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and # GIT_AUTHOR_DATE exported from the current environment. do_with_author () { @@ -191,12 +199,19 @@ git_sequence_editor () { pick_one () { ff=--ff + case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac case "$force_rebase" in '') ;; ?*) ff= ;; esac output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" + + if is_empty_commit "$sha1" + then + empty_args="--allow-empty" + fi + test -d "$rewritten" && pick_one_preserving_merges "$@" && return - output git cherry-pick $ff "$@" + output git cherry-pick $empty_args $ff "$@" } pick_one_preserving_merges () { @@ -780,9 +795,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \ sed -n "s/^>//p" | while read -r shortsha1 rest do + + if test -z "$keep_empty" && is_empty_commit $shortsha1 + then + comment_out="# " + else + comment_out= + fi + if test t != "$preserve_merges" then - printf '%s\n' "pick $shortsha1 $rest" >> "$todo" + printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo" else sha1=$(git rev-parse $shortsha1) if test -z "$rebase_root" @@ -801,7 +824,7 @@ do if test f = "$preserve" then touch "$rewritten"/$sha1 - printf '%s\n' "pick $shortsha1 $rest" >> "$todo" + printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo" fi fi done @@ -851,6 +874,12 @@ cat >> "$todo" << EOF # EOF +if test -z "$keep_empty" +then + echo "# Note that empty commits are commented out" >>"$todo" +fi + + has_action "$todo" || die_abort "Nothing to do" -- cgit v1.2.1 From c214538416ee55b951b77b0628b61370bc4d5de4 Mon Sep 17 00:00:00 2001 From: Lucien Kong Date: Tue, 12 Jun 2012 10:05:12 +0200 Subject: rebase -i: teach "--exec " During an interactive rebase session, it is sometimes desirable to run tests on each commit in the resulting history. This can be done by adding "exec " when editing the insn sheet, but the command used for testing is often the same for all resulting commits. By passing "--exec " from the command line, automatically add these "exec" lines after each commit in the final history. To work well with the --autosquash option, these are added at the end of each run of "fixup" and "squash". Helped-by: Johannes Sixt Signed-off-by: Lucien Kong Signed-off-by: Valentin Duperray Signed-off-by: Franck Jonas Signed-off-by: Thomas Nguy Signed-off-by: Huynh Khoi Nguyen Nguyen Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0c19b7c753..5f566726ab 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -684,6 +684,27 @@ rearrange_squash () { rm -f "$1.sq" "$1.rearranged" } +# Add commands after a pick or after a squash/fixup serie +# in the todo list. +add_exec_commands () { + { + first=t + while read -r insn rest + do + case $insn in + pick) + test -n "$first" || + printf "%s" "$cmd" + ;; + esac + printf "%s %s\n" "$insn" "$rest" + first= + done + printf "%s" "$cmd" + } <"$1" >"$1.new" && + mv "$1.new" "$1" +} + case "$action" in continue) # do we have anything to commit? @@ -857,6 +878,8 @@ fi test -s "$todo" || echo noop >> "$todo" test -n "$autosquash" && rearrange_squash "$todo" +test -n "$cmd" && add_exec_commands "$todo" + cat >> "$todo" << EOF # Rebase $shortrevisions onto $shortonto -- cgit v1.2.1 From 572a7c52bb12e22b3b8471133253b9884643a4e2 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Tue, 26 Jun 2012 07:51:54 -0700 Subject: rebase: don't source git-sh-setup twice The git-sh-setup script is already sourced in git-rebase.sh before calling into git-rebase--(am|interactive|merge).sh. There are no other callers of these scripts. It is therefore unnecessary to source git-sh-setup again in them. Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0c19b7c753..a5b018d4ac 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -9,9 +9,7 @@ # # The original idea comes from Eric W. Biederman, in # http://article.gmane.org/gmane.comp.version-control.git/22407 - -. git-sh-setup - +# # 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 -- cgit v1.2.1 From df5df20c1308f936ea542c86df1e9c6974168472 Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Tue, 26 Jun 2012 22:55:23 +0100 Subject: rebase -i: support --root without --onto Allow --root to be specified to rebase -i without --onto, making it possible to edit and re-order all commits right back to the root(s). If there is a conflict to be resolved when applying the first change, the user will expect a sane index and working tree to get sensible behaviour from git-diff and friends, so create a sentinel commit with an empty tree to rebase onto. Automatically squash the sentinel with any commits rebased directly onto it, so they end up as root commits in their own right and retain their authorship and commit message. Implicitly use rebase -i for non-interactive rebase of --root without an --onto argument now that rebase -i can correctly do this. Signed-off-by: Chris Webb Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0c19b7c753..fcb5f618da 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -417,6 +417,29 @@ record_in_rewritten() { esac } +do_pick () { + if test "$(git rev-parse HEAD)" = "$squash_onto" + then + # Set the correct commit message and author info on the + # sentinel root before cherry-picking the original changes + # without committing (-n). Finally, update the sentinel again + # to include these changes. If the cherry-pick results in a + # conflict, this means our behaviour is similar to a standard + # failed cherry-pick during rebase, with a dirty index to + # resolve before manually running git commit --amend then git + # rebase --continue. + git commit --allow-empty --allow-empty-message --amend \ + --no-post-rewrite -n -q -C $1 && + pick_one -n $1 && + git commit --allow-empty --allow-empty-message \ + --amend --no-post-rewrite -n -q -C $1 || + die_with_patch $1 "Could not apply $1... $2" + else + pick_one $1 || + die_with_patch $1 "Could not apply $1... $2" + fi +} + do_next () { rm -f "$msg" "$author_script" "$amend" || exit read -r command sha1 rest < "$todo" @@ -428,16 +451,14 @@ do_next () { comment_for_reflog pick mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" record_in_rewritten $sha1 ;; reword|r) comment_for_reflog reword mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" git commit --amend --no-post-rewrite || { warn "Could not amend commit after successfully picking $sha1... $rest" warn "This is most likely due to an empty commit message, or the pre-commit hook" @@ -451,8 +472,7 @@ do_next () { comment_for_reflog edit mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" warn "Stopped at $sha1... $rest" exit_with_patch $sha1 0 ;; -- cgit v1.2.1 From 2147f844ed13fa5052161d38f8cf7dca6f83c06e Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Tue, 24 Jul 2012 13:17:03 +0100 Subject: rebase -i: handle fixup of root commit correctly There is a bug with git rebase -i --root when a fixup or squash line is applied to the new root. We attempt to amend the commit onto which they apply with git reset --soft HEAD^ followed by a normal commit. Unlike a real commit --amend, this sequence will fail against a root commit as it has no parent. Fix rebase -i to use commit --amend for fixup and squash instead, and add a test for the case of a fixup of the root commit. Signed-off-by: Chris Webb Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index fcb5f618da..45addba1b0 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -495,25 +495,28 @@ do_next () { 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" + if ! pick_one -n $sha1 + then + git rev-parse --verify HEAD >"$amend" + die_failed_squash $sha1 "$rest" + fi 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 --amend --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" then - do_with_author git commit --no-verify -F "$fixup_msg" || + do_with_author git commit --amend --no-verify -F "$fixup_msg" || die_failed_squash $sha1 "$rest" else cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit rm -f "$GIT_DIR"/MERGE_MSG - do_with_author git commit --no-verify -e || + do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e || die_failed_squash $sha1 "$rest" fi rm -f "$squash_msg" "$fixup_msg" @@ -729,7 +732,6 @@ In both case, once you're done, continue with: fi . "$author_script" || die "Error trying to find the author identity to amend commit" - current_head= if test -f "$amend" then current_head=$(git rev-parse --verify HEAD) @@ -737,13 +739,12 @@ In both case, once you're done, continue with: 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" + do_with_author git commit --amend --no-verify -F "$msg" -e || + die "Could not commit staged changes." + else + do_with_author git commit --no-verify -F "$msg" -e || + die "Could not commit staged changes." 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 "$state_dir"/stopped-sha)" -- cgit v1.2.1 From 1af221ef5cb84c792303a0d16ca91197e2b70279 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Fri, 10 Aug 2012 08:51:19 +0200 Subject: rebase -i: use full onto sha1 in reflog 'git rebase' uses the full onto sha1 for the reflog message whereas 'git rebase -i' uses the short sha1. This is not only inconsistent, but can lead to problems when the reflog is inspected at a later time at which that abbreviation may have become ambiguous. Make 'rebase -i' use the full onto sha1, as well. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2e1325824c..905346084c 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -533,11 +533,10 @@ do_next () { test -s "$todo" && return comment_for_reflog finish && - shortonto=$(git rev-parse --short $onto) && newhead=$(git rev-parse HEAD) && case $head_name in refs/*) - message="$GIT_REFLOG_ACTION: $head_name onto $shortonto" && + message="$GIT_REFLOG_ACTION: $head_name onto $onto" && git update-ref -m "$message" $head_name $newhead $orig_head && git symbolic-ref \ -m "$GIT_REFLOG_ACTION: returning to $head_name" \ -- cgit v1.2.1 From fcc5ef1cc90ed49400bef51d306216f290eab9cc Mon Sep 17 00:00:00 2001 From: Andrew Wong Date: Mon, 17 Sep 2012 21:28:08 -0400 Subject: rebase -i: Refactor help messages for todo file Signed-off-by: Andrew Wong Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index a09e8423dd..4d57e50f2b 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -115,6 +115,23 @@ mark_action_done () { fi } +append_todo_help () { + cat >> "$todo" << EOF +# +# Commands: +# p, pick = use commit +# r, reword = use commit, but edit the commit message +# e, edit = use commit, but stop for amending +# s, squash = use commit, but meld into previous commit +# f, fixup = like "squash", but discard this commit's log message +# x, exec = run command (the rest of the line) using shell +# +# These lines can be re-ordered; they are executed from top to bottom. +# +# If you remove a line here THAT COMMIT WILL BE LOST. +EOF +} + make_patch () { sha1_and_parents="$(git rev-list --parents -1 "$1")" case "$sha1_and_parents" in @@ -901,18 +918,10 @@ test -n "$cmd" && add_exec_commands "$todo" cat >> "$todo" << EOF # Rebase $shortrevisions onto $shortonto +EOF +append_todo_help +cat >> "$todo" << EOF # -# Commands: -# p, pick = use commit -# r, reword = use commit, but edit the commit message -# e, edit = use commit, but stop for amending -# s, squash = use commit, but meld into previous commit -# f, fixup = like "squash", but discard this commit's log message -# x, exec = run command (the rest of the line) using shell -# -# These lines can be re-ordered; they are executed from top to bottom. -# -# If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # EOF -- cgit v1.2.1 From eb9a7cb4bdbd4ea9c7e7ef2ca8de5b2753e3584c Mon Sep 17 00:00:00 2001 From: Andrew Wong Date: Mon, 17 Sep 2012 21:28:09 -0400 Subject: rebase -i: Teach "--edit-todo" action This allows users to edit the todo file while they're stopped in the middle of an interactive rebase. When this action is executed, all comments from the original todo file are stripped, and new help messages are appended to the end. Signed-off-by: Andrew Wong Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 4d57e50f2b..2b8f2a9f42 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -792,6 +792,23 @@ skip) do_rest ;; +edit-todo) + sed -e '/^#/d' < "$todo" > "$todo".new + mv -f "$todo".new "$todo" + append_todo_help + cat >> "$todo" << EOF +# +# You are editing the todo file of an ongoing interactive rebase. +# To continue rebase after editing, run: +# git rebase --continue +# +EOF + + git_sequence_editor "$todo" || + die "Could not execute editor" + + exit + ;; esac git var GIT_COMMITTER_IDENT >/dev/null || -- cgit v1.2.1 From ecfe1ea96fde1fa5756ad04f717fd2960ead988a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Sep 2012 13:15:26 +0200 Subject: rebase -i: fix misleading error message after 'exec no-such' instruction When the todo sheet of interactive rebase instructs to run a non-existing command, the operation stops with the following error: Execution failed: no-such You can fix the problem, and then run git rebase --continue fatal: 'rebase' appears to be a git command, but we were not able to execute it. Maybe git-rebase is broken? The reason is that the shell that attempted to run the command exits with code 127. rebase--interactive just forwards this code to the caller (the git wrapper). But our smart run-command infrastructure detects this special exit code and turns it into ENOENT, which in turn is interpreted by the git wrapper as if the external command that it just executed did not exist. This is finally translated to the misleading last two lines in error message cited above. Fix it by translating the error code before it is forwarded. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index a09e8423dd..56707d7a27 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -544,6 +544,10 @@ do_next () { warn warn " git rebase --continue" warn + if test $status -eq 127 # command not found + then + status=1 + fi exit "$status" elif test "$dirty" = t then -- cgit v1.2.1 From 9c8e1011b9f6979777946ff87aae7b5846ed20a7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 19 Sep 2012 08:43:54 +0200 Subject: rebase -i: suggest using --edit-todo to fix an unknown instruction We have now an explicit UI to edit the todo sheet and need not disclose the name of the file. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2b8f2a9f42..4b2ef11e59 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -575,11 +575,12 @@ do_next () { ;; *) warn "Unknown command: $command $sha1 $rest" + fixtodo="Please fix this using 'git rebase --edit-todo'." 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 "$fixtodo" else - die "Please fix this in the file $todo." + die "$fixtodo" fi ;; esac -- cgit v1.2.1 From 986977847e6fb46448fc9c567292ccd2a93d40b3 Mon Sep 17 00:00:00 2001 From: Phil Hord Date: Sat, 12 Jan 2013 15:46:01 -0500 Subject: rebase --preserve-merges: keep all merge commits including empty ones Since 90e1818f9a (git-rebase: add keep_empty flag, 2012-04-20) 'git rebase --preserve-merges' fails to preserve empty merge commits unless --keep-empty is also specified. Merge commits should be preserved in order to preserve the structure of the rebased graph, even if the merge commit does not introduce changes to the parent. Teach rebase not to drop merge commits only because they are empty. A special case which is not handled by this change is for a merge commit whose parents are now the same commit because all the previous different parents have been dropped as a result of this rebase or some previous operation. Signed-off-by: Phil Hord Acked-by: Neil Horman Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0c19b7c753..2fed92fac1 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -175,6 +175,11 @@ is_empty_commit() { test "$tree" = "$ptree" } +is_merge_commit() +{ + git rev-parse --verify --quiet "$1"^2 >/dev/null 2>&1 +} + # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and # GIT_AUTHOR_DATE exported from the current environment. do_with_author () { @@ -796,7 +801,7 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \ while read -r shortsha1 rest do - if test -z "$keep_empty" && is_empty_commit $shortsha1 + if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1 then comment_out="# " else -- cgit v1.2.1 From 180bad3d10fe3a7f6d6c990956a888dd0562bef1 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Mon, 11 Feb 2013 23:08:04 +0000 Subject: rebase -i: respect core.commentchar Commit eff80a9 (Allow custom "comment char") introduced a custom comment character for commit messages but did not teach git-rebase--interactive to use it. Change git-rebase--interactive to read core.commentchar and use its value when generating commit messages and for the command list. Signed-off-by: John Keeping Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 84 ++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 40 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 44901d53c4..5db9e2d3f3 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -80,6 +80,9 @@ rewritten_pending="$state_dir"/rewritten-pending GIT_CHERRY_PICK_HELP="$resolvemsg" export GIT_CHERRY_PICK_HELP +comment_char=$(git config --get core.commentchar 2>/dev/null | cut -c1) +: ${comment_char:=#} + warn () { printf '%s\n' "$*" >&2 } @@ -105,8 +108,8 @@ mark_action_done () { 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"))) + new_count=$(git stripspace --strip-comments <"$done" | wc -l) + total=$(($new_count + $(git stripspace --strip-comments <"$todo" | wc -l))) if test "$last_count" != "$new_count" then last_count=$new_count @@ -116,19 +119,19 @@ mark_action_done () { } append_todo_help () { - cat >> "$todo" << EOF -# -# Commands: -# p, pick = use commit -# r, reword = use commit, but edit the commit message -# e, edit = use commit, but stop for amending -# s, squash = use commit, but meld into previous commit -# f, fixup = like "squash", but discard this commit's log message -# x, exec = run command (the rest of the line) using shell -# -# These lines can be re-ordered; they are executed from top to bottom. -# -# If you remove a line here THAT COMMIT WILL BE LOST. + git stripspace --comment-lines >>"$todo" <<\EOF + +Commands: + p, pick = use commit + r, reword = use commit, but edit the commit message + e, edit = use commit, but stop for amending + s, squash = use commit, but meld into previous commit + f, fixup = like "squash", but discard this commit's log message + x, exec = run command (the rest of the line) using shell + +These lines can be re-ordered; they are executed from top to bottom. + +If you remove a line here THAT COMMIT WILL BE LOST. EOF } @@ -179,7 +182,7 @@ die_abort () { } has_action () { - sane_grep '^[^#]' "$1" >/dev/null + test -n "$(git stripspace --strip-comments <"$1")" } is_empty_commit() { @@ -358,10 +361,10 @@ update_squash_messages () { 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 "1s/^. This is a combination of \(.*\) commits\./\1/p" \ -e "q" < "$squash_msg".bak)+1)) { - echo "# This is a combination of $count commits." + printf '%s\n' "$comment_char This is a combination of $count commits." sed -e 1d -e '2,/^./{ /^$/d }' <"$squash_msg".bak @@ -370,8 +373,8 @@ update_squash_messages () { 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:" + printf '%s\n' "$comment_char This is a combination of 2 commits." + printf '%s\n' "$comment_char The first commit's message is:" echo cat "$fixup_msg" } >"$squash_msg" @@ -380,21 +383,22 @@ update_squash_messages () { squash) rm -f "$fixup_msg" echo - echo "# This is the $(nth_string $count) commit message:" + printf '%s\n' "$comment_char This is the $(nth_string $count) commit message:" echo commit_message $2 ;; fixup) echo - echo "# The $(nth_string $count) commit message will be skipped:" + printf '%s\n' "$comment_char The $(nth_string $count) commit message will be skipped:" echo - commit_message $2 | sed -e 's/^/# /' + # Change the space after the comment character to TAB: + commit_message $2 | git stripspace --comment-lines | sed -e 's/ / /' ;; esac >>"$squash_msg" } peek_next_command () { - sed -n -e "/^#/d" -e '/^$/d' -e "s/ .*//p" -e "q" < "$todo" + git stripspace --strip-comments <"$todo" | sed -n -e 's/ .*//p' -e q } # A squash/fixup has failed. Prepare the long version of the squash @@ -459,7 +463,7 @@ do_next () { rm -f "$msg" "$author_script" "$amend" || exit read -r command sha1 rest < "$todo" case "$command" in - '#'*|''|noop) + "$comment_char"*|''|noop) mark_action_done ;; pick|p) @@ -798,15 +802,15 @@ skip) do_rest ;; edit-todo) - sed -e '/^#/d' < "$todo" > "$todo".new + git stripspace --strip-comments <"$todo" >"$todo".new mv -f "$todo".new "$todo" append_todo_help - cat >> "$todo" << EOF -# -# You are editing the todo file of an ongoing interactive rebase. -# To continue rebase after editing, run: -# git rebase --continue -# + git stripspace --comment-lines >>"$todo" <<\EOF + +You are editing the todo file of an ongoing interactive rebase. +To continue rebase after editing, run: + git rebase --continue + EOF git_sequence_editor "$todo" || @@ -876,7 +880,7 @@ do if test -z "$keep_empty" && is_empty_commit $shortsha1 then - comment_out="# " + comment_out="$comment_char " else comment_out= fi @@ -937,20 +941,20 @@ test -s "$todo" || echo noop >> "$todo" test -n "$autosquash" && rearrange_squash "$todo" test -n "$cmd" && add_exec_commands "$todo" -cat >> "$todo" << EOF +cat >>"$todo" <> "$todo" << EOF -# -# However, if you remove everything, the rebase will be aborted. -# +git stripspace --comment-lines >>"$todo" <<\EOF + +However, if you remove everything, the rebase will be aborted. + EOF if test -z "$keep_empty" then - echo "# Note that empty commits are commented out" >>"$todo" + printf '%s\n' "$comment_char Note that empty commits are commented out" >>"$todo" fi -- cgit v1.2.1 From b71dc3e1a04666fae4a4e282973d9b5a122a997c Mon Sep 17 00:00:00 2001 From: Zoltan Klinger Date: Thu, 25 Apr 2013 19:28:54 +1000 Subject: bash-prompt.sh: show where rebase is at when stopped When a rebase stops (e.g. interrupted by a merge conflict), it could be useful to know how far a rebase has progressed and how many commits in total this rebase will apply. Teach the __git_ps1() command to display the number of commits so far applied and the total number of commits to be applied, like this: ((3ec0a6a...)|REBASE 2/5) In the example above the rebase has stopped at the second commit due to a merge conflict and there are a total number of five commits to be applied by this rebase. This information can be already obtained from the following files which are being generated during the rebase: GIT_DIR/.git/rebase-merge/msgnum (git-rebase--merge.sh) GIT_DIR/.git/rebase-merge/end (git-rebase--merge.sh) GIT_DIR/.git/rebase-apply/next (git-am.sh) GIT_DIR/.git/rebase-apply/last (git-am.sh) but "rebase -i" does not leave necessary clues. Implement this feature by doing these three things: 1) Modify git-rebase--interactive.sh to also create GIT_DIR/.git/rebase-merge/msgnum GIT_DIR/.git/rebase-merge/end files for the number of commits so far applied and the total number of commits to be applied. 2) Modify git-prompt.sh to read and display info from the above files. 3) Update test t9903-bash-prompt.sh to reflect changes introduced by this patch. Signed-off-by: Zoltan Klinger Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 048a140a6f..5822b2c592 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -57,6 +57,9 @@ rewritten="$state_dir"/rewritten dropped="$state_dir"/dropped +end="$state_dir"/end +msgnum="$state_dir"/msgnum + # 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. @@ -109,7 +112,9 @@ mark_action_done () { sed -e 1d < "$todo" >> "$todo".new mv -f "$todo".new "$todo" new_count=$(git stripspace --strip-comments <"$done" | wc -l) + echo $new_count >"$msgnum" total=$(($new_count + $(git stripspace --strip-comments <"$todo" | wc -l))) + echo $total >"$end" if test "$last_count" != "$new_count" then last_count=$new_count -- cgit v1.2.1 From 1224f3d0f1b47fc640e76b053f25d91e3ca84bcf Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Sun, 12 May 2013 17:26:36 +0530 Subject: rebase -i: don't error out if $state_dir already exists In preparation for a later patch that will create $state_dir/autostash in git-rebase.sh before anything else can happen, change a `mkdir $state_dir` call to `mkdir -p $state_dir`. The change is safe, because this is not a test to detect an in-progress rebase (that is already done much earlier in git-rebase.sh). Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5822b2c592..34111395b5 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -842,7 +842,7 @@ then fi orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?" -mkdir "$state_dir" || die "Could not create temporary $state_dir" +mkdir -p "$state_dir" || die "Could not create temporary $state_dir" : > "$state_dir"/interactive || die "Could not mark as interactive" write_basic_state -- cgit v1.2.1 From 15d4bf2e1e4f9853a17a86eb923b55d41da22d54 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Sun, 12 May 2013 17:26:39 +0530 Subject: rebase -i: return control to caller, for housekeeping Return control to the caller git-rebase.sh to get these two tasks rm -fr "$dotest" git gc --auto done by it. Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 34111395b5..f953d8d224 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -628,17 +628,16 @@ do_next () { "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list" true # we don't care if this hook failed fi && - rm -rf "$state_dir" && - git gc --auto && warn "Successfully rebased and updated $head_name." - exit + return 1 # not failure; just to break the do_rest loop } +# can only return 0, when the infinite loop breaks do_rest () { while : do - do_next + do_next || break done } @@ -805,11 +804,13 @@ first and then run 'git rebase --continue' again." require_clean_work_tree "rebase" do_rest + return 0 ;; skip) git rerere clear do_rest + return 0 ;; edit-todo) git stripspace --strip-comments <"$todo" >"$todo".new -- cgit v1.2.1 From 26cd160cb15635afd1c2937a3c15cfb256758323 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Sun, 16 Jun 2013 14:15:13 +0530 Subject: rebase -i: use a better reflog message Now that the "checkout" invoked internally from "rebase -i" knows to honor GIT_REFLOG_ACTION, we can start to use it to write a better reflog message when "rebase anotherbranch", "rebase --onto branch", etc. internally checks out the new fork point. We will write: rebase -i: checkout master instead of the old rebase -i As all the calls git-rebase--interactive make to underlying git commands that leave reflog messages are preceded by the internal comment_for_reflog helper function, which uses the original value of the GIT_REFLOG_ACTION variable it saw when it first started, the new assignments to GIT_REFLOG_ACTION actively contaminate the value of the variable, knowing that it will be reset to a sane value before it is used again. This does not generally hold true but it should suffice for now. Signed-off-by: Ramkumar Ramachandra Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5822b2c592..a975529353 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -837,8 +837,11 @@ comment_for_reflog start if test ! -z "$switch_to" then + GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" output git checkout "$switch_to" -- || - die "Could not checkout $switch_to" + die "Could not checkout $switch_to" + + comment_for_reflog start fi orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?" @@ -980,6 +983,7 @@ has_action "$todo" || test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks +GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "could not detach HEAD" git update-ref ORIG_HEAD $orig_head do_rest -- cgit v1.2.1 From 22c5b136363c7aa427667876e787db832548a038 Mon Sep 17 00:00:00 2001 From: Andrew Pimlott Date: Thu, 27 Jun 2013 12:26:31 -0700 Subject: rebase -i: handle fixup! fixup! in --autosquash In rebase -i --autosquash, ignore all "fixup! " or "squash! " after the first. This supports the case when a git commit --fixup/--squash referred to an earlier fixup/squash instead of the original commit (whether intentionally, as when the user expressly meant to note that the commit fixes an earlier fixup; or inadvertently, as when the user meant to refer to the original commit with :/msg; or out of laziness, as when the user could remember how to refer to the fixup but not the original). In the todo list, the full commit message is preserved, in case it provides useful cues to the user. A test helper set_cat_todo_editor is introduced to check this. Helped-by: Thomas Rast Helped-by: Junio C Hamano Signed-off-by: Andrew Pimlott Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f953d8d224..169e876eed 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -689,8 +689,22 @@ rearrange_squash () { case "$message" in "squash! "*|"fixup! "*) action="${message%%!*}" - rest="${message#*! }" - echo "$sha1 $action $rest" + rest=$message + prefix= + # skip all squash! or fixup! (but save for later) + while : + do + case "$rest" in + "squash! "*|"fixup! "*) + prefix="$prefix${rest%%!*}," + rest="${rest#*! }" + ;; + *) + break + ;; + esac + done + echo "$sha1 $action $prefix $rest" # if it's a single word, try to resolve to a full sha1 and # emit a second copy. This allows us to match on both message # and on sha1 prefix @@ -699,7 +713,7 @@ rearrange_squash () { if test -n "$fullsha"; then # prefix the action to uniquely identify this line as # intended for full sha1 match - echo "$sha1 +$action $fullsha" + echo "$sha1 +$action $prefix $fullsha" fi fi esac @@ -714,7 +728,7 @@ rearrange_squash () { esac printf '%s\n' "$pick $sha1 $message" used="$used$sha1 " - while read -r squash action msg_content + while read -r squash action msg_prefix msg_content do case " $used" in *" $squash "*) continue ;; @@ -730,7 +744,8 @@ rearrange_squash () { case "$message" in "$msg_content"*) emit=1;; esac ;; esac if test $emit = 1; then - printf '%s\n' "$action $squash $action! $msg_content" + real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g") + printf '%s\n' "$action $squash ${real_prefix}$msg_content" used="$used$squash " fi done <"$1.sq" -- cgit v1.2.1 From db2b3b820e2b28da268cc88adff076b396392dfe Mon Sep 17 00:00:00 2001 From: Arnaud Fontaine Date: Tue, 2 Jul 2013 17:05:48 +0900 Subject: Do not ignore merge options in interactive rebase Merge strategy and its options can be specified in `git rebase`, but with `--interactive`, they were completely ignored. Signed-off-by: Arnaud Fontaine Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'git-rebase--interactive.sh') diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f953d8d224..ae2da7ac0b 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -80,6 +80,18 @@ amend="$state_dir"/amend rewritten_list="$state_dir"/rewritten-list rewritten_pending="$state_dir"/rewritten-pending +strategy_args= +if test -n "$do_merge" +then + strategy_args=${strategy:+--strategy=$strategy} + eval ' + for strategy_opt in '"$strategy_opts"' + do + strategy_args="$strategy_args -X$(git rev-parse --sq-quote "${strategy_opt#--}")" + done + ' +fi + GIT_CHERRY_PICK_HELP="$resolvemsg" export GIT_CHERRY_PICK_HELP @@ -239,7 +251,7 @@ pick_one () { test -d "$rewritten" && pick_one_preserving_merges "$@" && return - output git cherry-pick $empty_args $ff "$@" + output eval git cherry-pick "$strategy_args" $empty_args $ff "$@" } pick_one_preserving_merges () { @@ -340,9 +352,8 @@ pick_one_preserving_merges () { 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 --no-ff ${strategy:+-s $strategy} -m \ - "$msg_content" $new_parents + if ! do_with_author output eval \ + 'git merge --no-ff $strategy_args -m "$msg_content" $new_parents' then printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG die_with_patch $sha1 "Error redoing merge $sha1" @@ -350,7 +361,7 @@ pick_one_preserving_merges () { echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list" ;; *) - output git cherry-pick "$@" || + output eval git cherry-pick "$strategy_args" "$@" || die_with_patch $sha1 "Could not pick $sha1" ;; esac -- cgit v1.2.1