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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).