From: Fabian Ruch <bafain@gmail.com>
To: git@vger.kernel.org
Subject: [RFC PATCH 7/7] rebase -i: Teach do_pick the options --amend and --file
Date: Thu, 19 Jun 2014 05:28:50 +0200 [thread overview]
Message-ID: <53A258F2.8050300@gmail.com> (raw)
In-Reply-To: <cover.1403146774.git.bafain@gmail.com>
The to-do list command `squash` and its close relative `fixup` replay
the changes of a commit like `pick` but do not recreate the commit.
Instead they replace the previous commit with a new commit that also
introduces the changes of the squashed commit. This is roughly like
cherry-picking without committing and using git-commit to amend the
previous commit.
The to-do list
pick a Some changes
squash b Some more changes
gets translated into the sequence of git commands
git cherry-pick a
git cherry-pick -n b
git commit --amend
and if `cherry-pick` supported `--amend` this would look even more like
the to-do list it is based on
git cherry-pick a
git cherry-pick --amend b.
Since `do_pick` takes care of `pick` entries and the above suggests
`squash` as an alias for `pick --amend`, teach `do_pick` to handle the
option `--amend` and reimplement `squash` in terms of `do_pick --amend`.
Also teach it the option `--file` which is used to specify `$squash_msg`
as commit message.
Both `--amend` and `--file` are commit rewriting options. If they are
encountered during options parsing, assign `rewrite` and pass `--amend`
(`--file` respectively) to the rewrite command. Be careful when
`--amend` is used to pick a root commit because HEAD might point to the
sentinel commit but there is still nothing to amend. Be sure to
initialize `$amend` so that commits are squashed even when `rebase` is
interrupted for resolving conflicts. It is not a mistake to do the
initialization regardless of any conflicts because `$amend` is always
cleared before the next to-do item is processed.
Signed-off-by: Fabian Ruch <bafain@gmail.com>
---
Notes:
A question about when to enable the post-rewrite hook.
`rebase` collects the hashes of all processed commits using
`record_in_rewritten` and runs the post-rewrite script after the rebase
is complete. Two points seem to confuse me.
1) For a `pick` the hash is `record_in_rewritten` regardless of whether
the hash changed or not (the commit was recreated or the head was
fast-forwarded). Ok, the hook can figure that out. Is this behaviour
intended?
2) For a `reword` the amend disables the post-rewrite hook but for a
`squash` (or `fixup`) the hook is executed each time the squash
commit is amended. Does not this result in the hook being executed
twice for each scheduled `squash` command? Once for the amend and
once for the rebase. The hook most likely does not figure that out.
This patch never executes the post-rewrite hook when processing the
to-do list. The execution after the rebase is finished is still
conducted. I am uncertain whether this is correct. The tests seem to
succeed with both implementations.
git-rebase--interactive.sh | 65 ++++++++++++++++++++++++++++------------------
1 file changed, 40 insertions(+), 25 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index ada520d..5ddc59d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -493,7 +493,7 @@ record_in_rewritten() {
# Apply the changes introduced by the given commit to the current head.
#
-# do_pick [--edit] <commit>
+# do_pick [--file <file>] [--amend] [--edit] <commit>
#
# Wrapper around git-cherry-pick.
#
@@ -505,6 +505,17 @@ record_in_rewritten() {
# commit message. The editor contents becomes the commit message of
# the new head.
#
+# --amend
+# After picking <commit>, replace the current head commit with a new
+# commit that also introduces the changes of <commit>.
+#
+# _This is not a git-cherry-pick option._
+#
+# -F <file>, --file <file>
+# Take the commit message from the given file.
+#
+# _This is not a git-cherry-pick option._
+#
# The return value is 1 if applying the changes resulted in a conflict
# and 2 if the specified arguments were incorrect. If the changes could
# be applied successfully but creating the commit failed, a value
@@ -514,9 +525,30 @@ do_pick () {
rewrite=
rewrite_amend=
rewrite_edit=
+ rewrite_message=
while test $# -gt 0
do
case "$1" in
+ -F|--file)
+ if test $# -eq 0
+ then
+ warn "do_pick: option --file specified but no <file> given"
+ return 2
+ fi
+ rewrite=y
+ rewrite_message=$2
+ shift
+ ;;
+ --amend)
+ if test "$(git rev-parse HEAD)" = "$squash_onto" || ! git rev-parse --verify HEAD
+ then
+ warn "do_pick: nothing to amend"
+ return 2
+ fi
+ rewrite=y
+ rewrite_amend=y
+ git rev-parse --verify HEAD >"$amend"
+ ;;
-e|--edit)
rewrite=y
rewrite_edit=y
@@ -561,6 +593,7 @@ do_pick () {
git commit --allow-empty --no-post-rewrite -n -q \
${rewrite_amend:+--amend} \
${rewrite_edit:+--edit} \
+ ${rewrite_message:+--file "$rewrite_message"} \
${gpg_sign_opt:+"$gpg_sign_opt"} || return 3
fi
}
@@ -617,38 +650,20 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only be
# used in case of trouble. So use the long version:
- if ! pick_one -n $sha1
- then
- git rev-parse --verify HEAD >"$amend"
- die_failed_squash $sha1 "Could not apply $sha1... $rest"
- fi
- do_with_author output git commit --amend --no-verify -F "$squash_msg" \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
- die_failed_squash $sha1 "$rest"
+ do_with_author do_pick --amend -F "$squash_msg" $sha1 \
+ || die_failed_squash $sha1 "Could not apply $sha1... $rest"
;;
*)
# This is the final command of this squash/fixup group
if test -f "$fixup_msg"
then
- if ! pick_one -n $sha1
- then
- git rev-parse --verify HEAD >"$amend"
- die_failed_squash $sha1 "Could not apply $sha1... $rest"
- fi
- do_with_author git commit --amend --no-verify -F "$fixup_msg" \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
- die_failed_squash $sha1 "$rest"
+ do_with_author do_pick --amend -F "$fixup_msg" $sha1 \
+ || die_failed_squash $sha1 "Could not apply $sha1... $rest"
else
cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
rm -f "$GIT_DIR"/MERGE_MSG
- if ! pick_one -n $sha1
- then
- git rev-parse --verify HEAD >"$amend"
- die_failed_squash $sha1 "Could not apply $sha1... $rest"
- fi
- do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e \
- ${gpg_sign_opt:+"$gpg_sign_opt"} ||
- die_failed_squash $sha1 "$rest"
+ do_with_author do_pick --amend -F "$GIT_DIR"/SQUASH_MSG -e $sha1 \
+ || die_failed_squash $sha1 "Could not apply $sha1... $rest"
fi
rm -f "$squash_msg" "$fixup_msg"
;;
--
2.0.0
prev parent reply other threads:[~2014-06-19 3:28 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1403146774.git.bafain@gmail.com>
2014-06-19 3:28 ` [RFC PATCH 1/7] rebase -i: Make option handling in pick_one more flexible Fabian Ruch
2014-06-20 13:40 ` Michael Haggerty
2014-06-20 19:53 ` Junio C Hamano
2014-06-23 0:04 ` Fabian Ruch
2014-06-21 23:21 ` Fabian Ruch
2014-06-23 16:09 ` Johannes Schindelin
2014-06-19 3:28 ` [RFC PATCH 2/7] rebase -i: Teach do_pick the option --edit Fabian Ruch
2014-06-20 13:41 ` Michael Haggerty
2014-06-22 0:09 ` Fabian Ruch
2014-06-19 3:28 ` [RFC PATCH 3/7] rebase -i: Stop on root commits with empty log messages Fabian Ruch
2014-06-21 0:33 ` Eric Sunshine
2014-06-22 0:32 ` Fabian Ruch
2014-06-19 3:28 ` [RFC PATCH 4/7] rebase -i: Commit only once when rewriting picks Fabian Ruch
2014-06-19 3:28 ` [RFC PATCH 5/7] rebase -i: Do not die in do_pick Fabian Ruch
2014-06-19 3:28 ` [RFC PATCH 6/7] rebase -i: Prepare for squash in terms of do_pick --amend Fabian Ruch
2014-06-19 3:28 ` Fabian Ruch [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53A258F2.8050300@gmail.com \
--to=bafain@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.