Merge branch 'mh/rebase-fixup' (early part)
* 'mh/rebase-fixup' (early part): rebase-i: Ignore comments and blank lines in peek_next_command lib-rebase: Allow comments and blank lines to be added to the rebase script lib-rebase: Provide clearer debugging info about what the editor did Add a command "fixup" to rebase --interactive t3404: Use test_commit to set up test repository
This commit is contained in:
commit
cc6b41cc7d
@ -382,9 +382,12 @@ If you just want to edit the commit message for a commit, replace the
|
|||||||
command "pick" with the command "reword".
|
command "pick" with the command "reword".
|
||||||
|
|
||||||
If you want to fold two or more commits into one, replace the command
|
If you want to fold two or more commits into one, replace the command
|
||||||
"pick" with "squash" for the second and subsequent commit. If the
|
"pick" for the second and subsequent commits with "squash" or "fixup".
|
||||||
commits had different authors, it will attribute the squashed commit to
|
If the commits had different authors, the folded commit will be
|
||||||
the author of the first commit.
|
attributed to the author of the first commit. The suggested commit
|
||||||
|
message for the folded commit is the concatenation of the commit
|
||||||
|
messages of the first commit and of those with the "squash" command,
|
||||||
|
but omits the commit messages of commits with the "fixup" command.
|
||||||
|
|
||||||
'git-rebase' will stop when "pick" has been replaced with "edit" or
|
'git-rebase' will stop when "pick" has been replaced with "edit" or
|
||||||
when a command fails due to merge errors. When you are done editing
|
when a command fails due to merge errors. When you are done editing
|
||||||
@ -512,8 +515,8 @@ Easy case: The changes are literally the same.::
|
|||||||
Hard case: The changes are not the same.::
|
Hard case: The changes are not the same.::
|
||||||
|
|
||||||
This happens if the 'subsystem' rebase had conflicts, or used
|
This happens if the 'subsystem' rebase had conflicts, or used
|
||||||
`\--interactive` to omit, edit, or squash commits; or if the
|
`\--interactive` to omit, edit, squash, or fixup commits; or
|
||||||
upstream used one of `commit \--amend`, `reset`, or
|
if the upstream used one of `commit \--amend`, `reset`, or
|
||||||
`filter-branch`.
|
`filter-branch`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,7 +302,10 @@ nth_string () {
|
|||||||
|
|
||||||
make_squash_message () {
|
make_squash_message () {
|
||||||
if test -f "$SQUASH_MSG"; then
|
if test -f "$SQUASH_MSG"; then
|
||||||
COUNT=$(($(sed -n "s/^# This is [^0-9]*\([1-9][0-9]*\).*/\1/p" \
|
# We want to be careful about matching only the commit
|
||||||
|
# message comment lines generated by this function.
|
||||||
|
# "[snrt][tdh]" matches the nth_string endings.
|
||||||
|
COUNT=$(($(sed -n "s/^# Th[^0-9]*\([1-9][0-9]*\)[snrt][tdh] commit message.*:/\1/p" \
|
||||||
< "$SQUASH_MSG" | sed -ne '$p')+1))
|
< "$SQUASH_MSG" | sed -ne '$p')+1))
|
||||||
echo "# This is a combination of $COUNT commits."
|
echo "# This is a combination of $COUNT commits."
|
||||||
sed -e 1d -e '2,/^./{
|
sed -e 1d -e '2,/^./{
|
||||||
@ -315,10 +318,23 @@ make_squash_message () {
|
|||||||
echo
|
echo
|
||||||
git cat-file commit HEAD | sed -e '1,/^$/d'
|
git cat-file commit HEAD | sed -e '1,/^$/d'
|
||||||
fi
|
fi
|
||||||
|
case $1 in
|
||||||
|
squash)
|
||||||
echo
|
echo
|
||||||
echo "# This is the $(nth_string $COUNT) commit message:"
|
echo "# This is the $(nth_string $COUNT) commit message:"
|
||||||
echo
|
echo
|
||||||
git cat-file commit $1 | sed -e '1,/^$/d'
|
git cat-file commit $2 | sed -e '1,/^$/d'
|
||||||
|
;;
|
||||||
|
fixup)
|
||||||
|
echo
|
||||||
|
echo "# The $(nth_string $COUNT) commit message will be skipped:"
|
||||||
|
echo
|
||||||
|
# Comment the lines of the commit message out using
|
||||||
|
# "# " rather than "# " to make them less likely to
|
||||||
|
# confuse the sed regexp above.
|
||||||
|
git cat-file commit $2 | sed -e '1,/^$/d' -e 's/^/# /'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
peek_next_command () {
|
peek_next_command () {
|
||||||
@ -367,20 +383,28 @@ do_next () {
|
|||||||
warn
|
warn
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
squash|s|fixup|f)
|
||||||
|
case "$command" in
|
||||||
squash|s)
|
squash|s)
|
||||||
comment_for_reflog squash
|
squash_style=squash
|
||||||
|
;;
|
||||||
|
fixup|f)
|
||||||
|
squash_style=fixup
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
comment_for_reflog $squash_style
|
||||||
|
|
||||||
test -f "$DONE" && has_action "$DONE" ||
|
test -f "$DONE" && has_action "$DONE" ||
|
||||||
die "Cannot 'squash' without a previous commit"
|
die "Cannot '$squash_style' without a previous commit"
|
||||||
|
|
||||||
mark_action_done
|
mark_action_done
|
||||||
make_squash_message $sha1 > "$MSG"
|
make_squash_message $squash_style $sha1 > "$MSG"
|
||||||
failed=f
|
failed=f
|
||||||
author_script=$(get_author_ident_from_commit HEAD)
|
author_script=$(get_author_ident_from_commit HEAD)
|
||||||
output git reset --soft HEAD^
|
output git reset --soft HEAD^
|
||||||
pick_one -n $sha1 || failed=t
|
pick_one -n $sha1 || failed=t
|
||||||
case "$(peek_next_command)" in
|
case "$(peek_next_command)" in
|
||||||
squash|s)
|
squash|s|fixup|f)
|
||||||
USE_OUTPUT=output
|
USE_OUTPUT=output
|
||||||
MSG_OPT=-F
|
MSG_OPT=-F
|
||||||
EDIT_OR_FILE="$MSG"
|
EDIT_OR_FILE="$MSG"
|
||||||
@ -787,6 +811,7 @@ first and then run 'git rebase --continue' again."
|
|||||||
# r, reword = use commit, but edit the commit message
|
# r, reword = use commit, but edit the commit message
|
||||||
# e, edit = use commit, but stop for amending
|
# e, edit = use commit, but stop for amending
|
||||||
# s, squash = use commit, but meld into previous commit
|
# s, squash = use commit, but meld into previous commit
|
||||||
|
# f, fixup = like "squash", but discard this commit's log message
|
||||||
#
|
#
|
||||||
# If you remove a line here THAT COMMIT WILL BE LOST.
|
# If you remove a line here THAT COMMIT WILL BE LOST.
|
||||||
# However, if you remove everything, the rebase will be aborted.
|
# However, if you remove everything, the rebase will be aborted.
|
||||||
|
@ -5,12 +5,20 @@
|
|||||||
# - override the commit message with $FAKE_COMMIT_MESSAGE,
|
# - override the commit message with $FAKE_COMMIT_MESSAGE,
|
||||||
# - amend the commit message with $FAKE_COMMIT_AMEND
|
# - amend the commit message with $FAKE_COMMIT_AMEND
|
||||||
# - check that non-commit messages have a certain line count with $EXPECT_COUNT
|
# - check that non-commit messages have a certain line count with $EXPECT_COUNT
|
||||||
# - rewrite a rebase -i script with $FAKE_LINES in the form
|
# - rewrite a rebase -i script as directed by $FAKE_LINES.
|
||||||
|
# $FAKE_LINES consists of a sequence of words separated by spaces.
|
||||||
|
# The following word combinations are possible:
|
||||||
#
|
#
|
||||||
# "[<lineno1>] [<lineno2>]..."
|
# "<lineno>" -- add a "pick" line with the SHA1 taken from the
|
||||||
|
# specified line.
|
||||||
#
|
#
|
||||||
# If a line number is prefixed with "squash", "edit", or "reword", the
|
# "<cmd> <lineno>" -- add a line with the specified command
|
||||||
# respective line's command will be replaced with the specified one.
|
# ("squash", "fixup", "edit", or "reword") and the SHA1 taken
|
||||||
|
# from the specified line.
|
||||||
|
#
|
||||||
|
# "#" -- Add a comment line.
|
||||||
|
#
|
||||||
|
# ">" -- Add a blank line.
|
||||||
|
|
||||||
set_fake_editor () {
|
set_fake_editor () {
|
||||||
echo "#!$SHELL_PATH" >fake-editor.sh
|
echo "#!$SHELL_PATH" >fake-editor.sh
|
||||||
@ -28,19 +36,24 @@ test -z "$EXPECT_COUNT" ||
|
|||||||
test -z "$FAKE_LINES" && exit
|
test -z "$FAKE_LINES" && exit
|
||||||
grep -v '^#' < "$1" > "$1".tmp
|
grep -v '^#' < "$1" > "$1".tmp
|
||||||
rm -f "$1"
|
rm -f "$1"
|
||||||
|
echo 'rebase -i script before editing:'
|
||||||
cat "$1".tmp
|
cat "$1".tmp
|
||||||
action=pick
|
action=pick
|
||||||
for line in $FAKE_LINES; do
|
for line in $FAKE_LINES; do
|
||||||
case $line in
|
case $line in
|
||||||
squash|edit|reword)
|
squash|fixup|edit|reword)
|
||||||
action="$line";;
|
action="$line";;
|
||||||
|
"#")
|
||||||
|
echo '# comment' >> "$1";;
|
||||||
|
">")
|
||||||
|
echo >> "$1";;
|
||||||
*)
|
*)
|
||||||
echo sed -n "${line}s/^pick/$action/p"
|
|
||||||
sed -n "${line}p" < "$1".tmp
|
|
||||||
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
|
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
|
||||||
action=pick;;
|
action=pick;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
echo 'rebase -i script after editing:'
|
||||||
|
cat "$1"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_set_editor "$(pwd)/fake-editor.sh"
|
test_set_editor "$(pwd)/fake-editor.sh"
|
||||||
|
@ -16,53 +16,26 @@ set_fake_editor
|
|||||||
|
|
||||||
# set up two branches like this:
|
# set up two branches like this:
|
||||||
#
|
#
|
||||||
# A - B - C - D - E
|
# A - B - C - D - E (master)
|
||||||
# \
|
# \
|
||||||
# F - G - H
|
# F - G - H (branch1)
|
||||||
# \
|
# \
|
||||||
# I
|
# I (branch2)
|
||||||
#
|
#
|
||||||
# where B, D and G touch the same file.
|
# where A, B, D and G touch the same file.
|
||||||
|
|
||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
: > file1 &&
|
test_commit A file1 &&
|
||||||
git add file1 &&
|
test_commit B file1 &&
|
||||||
test_tick &&
|
test_commit C file2 &&
|
||||||
git commit -m A &&
|
test_commit D file1 &&
|
||||||
git tag A &&
|
test_commit E file3 &&
|
||||||
echo 1 > file1 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m B file1 &&
|
|
||||||
: > file2 &&
|
|
||||||
git add file2 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m C &&
|
|
||||||
echo 2 > file1 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m D file1 &&
|
|
||||||
: > file3 &&
|
|
||||||
git add file3 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m E &&
|
|
||||||
git checkout -b branch1 A &&
|
git checkout -b branch1 A &&
|
||||||
: > file4 &&
|
test_commit F file4 &&
|
||||||
git add file4 &&
|
test_commit G file1 &&
|
||||||
test_tick &&
|
test_commit H file5 &&
|
||||||
git commit -m F &&
|
|
||||||
git tag F &&
|
|
||||||
echo 3 > file1 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m G file1 &&
|
|
||||||
: > file5 &&
|
|
||||||
git add file5 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m H &&
|
|
||||||
git checkout -b branch2 F &&
|
git checkout -b branch2 F &&
|
||||||
: > file6 &&
|
test_commit I file6
|
||||||
git add file6 &&
|
|
||||||
test_tick &&
|
|
||||||
git commit -m I &&
|
|
||||||
git tag I
|
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'no changes are a nop' '
|
test_expect_success 'no changes are a nop' '
|
||||||
@ -111,19 +84,20 @@ test_expect_success 'exchange two commits' '
|
|||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
diff --git a/file1 b/file1
|
diff --git a/file1 b/file1
|
||||||
index e69de29..00750ed 100644
|
index f70f10e..fd79235 100644
|
||||||
--- a/file1
|
--- a/file1
|
||||||
+++ b/file1
|
+++ b/file1
|
||||||
@@ -0,0 +1 @@
|
@@ -1 +1 @@
|
||||||
+3
|
-A
|
||||||
|
+G
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat > expect2 << EOF
|
cat > expect2 << EOF
|
||||||
<<<<<<< HEAD
|
<<<<<<< HEAD
|
||||||
2
|
D
|
||||||
=======
|
=======
|
||||||
3
|
G
|
||||||
>>>>>>> b7ca976... G
|
>>>>>>> 91201e5... G
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_expect_success 'stop on conflicting pick' '
|
test_expect_success 'stop on conflicting pick' '
|
||||||
@ -261,6 +235,60 @@ test_expect_success 'multi-squash only fires up editor once' '
|
|||||||
test 1 = $(git show | grep ONCE | wc -l)
|
test 1 = $(git show | grep ONCE | wc -l)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'multi-fixup only fires up editor once' '
|
||||||
|
git checkout -b multi-fixup E &&
|
||||||
|
base=$(git rev-parse HEAD~4) &&
|
||||||
|
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
|
||||||
|
git rebase -i $base &&
|
||||||
|
test $base = $(git rev-parse HEAD^) &&
|
||||||
|
test 1 = $(git show | grep ONCE | wc -l) &&
|
||||||
|
git checkout to-be-rebased &&
|
||||||
|
git branch -D multi-fixup
|
||||||
|
'
|
||||||
|
|
||||||
|
cat > expect-squash-fixup << EOF
|
||||||
|
B
|
||||||
|
|
||||||
|
D
|
||||||
|
|
||||||
|
ONCE
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'squash and fixup generate correct log messages' '
|
||||||
|
git checkout -b squash-fixup E &&
|
||||||
|
base=$(git rev-parse HEAD~4) &&
|
||||||
|
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
|
||||||
|
git rebase -i $base &&
|
||||||
|
git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
|
||||||
|
test_cmp expect-squash-fixup actual-squash-fixup &&
|
||||||
|
git checkout to-be-rebased &&
|
||||||
|
git branch -D squash-fixup
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'squash ignores comments' '
|
||||||
|
git checkout -b skip-comments E &&
|
||||||
|
base=$(git rev-parse HEAD~4) &&
|
||||||
|
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
|
||||||
|
EXPECT_HEADER_COUNT=4 \
|
||||||
|
git rebase -i $base &&
|
||||||
|
test $base = $(git rev-parse HEAD^) &&
|
||||||
|
test 1 = $(git show | grep ONCE | wc -l) &&
|
||||||
|
git checkout to-be-rebased &&
|
||||||
|
git branch -D skip-comments
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'squash ignores blank lines' '
|
||||||
|
git checkout -b skip-blank-lines E &&
|
||||||
|
base=$(git rev-parse HEAD~4) &&
|
||||||
|
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
|
||||||
|
EXPECT_HEADER_COUNT=4 \
|
||||||
|
git rebase -i $base &&
|
||||||
|
test $base = $(git rev-parse HEAD^) &&
|
||||||
|
test 1 = $(git show | grep ONCE | wc -l) &&
|
||||||
|
git checkout to-be-rebased &&
|
||||||
|
git branch -D skip-blank-lines
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'squash works as expected' '
|
test_expect_success 'squash works as expected' '
|
||||||
for n in one two three four
|
for n in one two three four
|
||||||
do
|
do
|
||||||
|
Loading…
Reference in New Issue
Block a user