[PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. This happens in two
steps. Firstly, the named commit is cherry-picked. Secondly, the
commit created in the first step is amended using an unchanged index
to edit the log message. The pre-commit hook is meant to verify the
changes introduced by a commit (for instance, catching inserted
trailing white space). Since the committed tree is not changed
between the two steps and we do not verify rebased patches, do not
execute the pre-commit hook in the second step.

Specify the git-commit option `--no-verify` to disable the pre-commit
hook when editing the log message. Because `--no-verify` also skips
the commit-msg hook, execute the hook from within
git-rebase--interactive after the commit is created. Fortunately, the
commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after
git-commit terminates. Caveat: In case the commit-msg hook finds the
new log message ill-formatted, the user is only notified of the
failed commit-msg hook but the log message is used for the commit
anyway. git-commit ought to offer more fine-grained control over
which hooks are executed.

Teach `test_commit` the `--no-verify` option and add test.

Signed-off-by: Fabian Ruch <bafain@xxxxxxxxx>
---
 git-rebase--interactive.sh    | 17 +++++++++++++----
 t/t3404-rebase-interactive.sh | 38 ++++++++++++++++++++++++++++++++++++++
 t/test-lib-functions.sh       |  6 +++++-
 3 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 689400e..b50770d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,10 +504,19 @@ do_next () {
 
 		mark_action_done
 		do_pick $sha1 "$rest"
-		git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
-			warn "Could not amend commit after successfully picking $sha1... $rest"
-			exit_with_patch $sha1 1
-		}
+		# TODO: Work around the fact that git-commit lets us
+		# disable either both the pre-commit and the commit-msg
+		# hook or none. Disable the pre-commit hook because the
+		# tree is left unchanged but run the commit-msg hook
+		# from here because the log message is altered.
+		git commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+"$gpg_sign_opt"} &&
+			if test -x "$GIT_DIR"/hooks/commit-msg
+			then
+				"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG
+			fi || {
+				warn "Could not amend commit after successfully picking $sha1... $rest"
+				exit_with_patch $sha1 1
+			}
 		record_in_rewritten $sha1
 		;;
 	edit|e)
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9931143..2da4b9c 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -577,6 +577,44 @@ test_expect_success 'rebase a commit violating pre-commit' '
 
 '
 
+test_expect_success 'reword a commit violating pre-commit' '
+	test_when_finished rm -r .git/hooks &&
+	mkdir -p .git/hooks &&
+	PRE_COMMIT=.git/hooks/pre-commit &&
+	cat >"$PRE_COMMIT" <<EOF
+#!/bin/sh
+echo running pre-commit: exit 1
+exit 1
+EOF
+	chmod +x "$PRE_COMMIT" &&
+	test_must_fail test_commit pre-commit-violated &&
+	test_commit --no-verify pre-commit-violated &&
+	test_when_finished reset_rebase &&
+	set_fake_editor &&
+	FAKE_LINES="pick 1" git rebase -i HEAD^ &&
+	FAKE_LINES="pick 1" git rebase -i --no-ff HEAD^ &&
+	FAKE_LINES="reword 1" git rebase -i HEAD^
+'
+
+test_expect_success 'reword a commit violating commit-msg' '
+	test_when_finished rm -r .git/hooks &&
+	mkdir -p .git/hooks &&
+	COMMIT_MSG=.git/hooks/commit-msg &&
+	cat >"$COMMIT_MSG" <<EOF
+#!/bin/sh
+echo running commit-msg: exit 1
+exit 1
+EOF
+	chmod +x "$COMMIT_MSG" &&
+	test_must_fail test_commit commit-msg-violated &&
+	test_commit --no-verify commit-msg-violated &&
+	test_when_finished reset_rebase &&
+	set_fake_editor &&
+	FAKE_LINES="pick 1" git rebase -i HEAD^ &&
+	FAKE_LINES="pick 1" git rebase -i --no-ff HEAD^ &&
+	test_must_fail env FAKE_LINES="reword 1" git rebase -i HEAD^
+'
+
 test_expect_success 'rebase with a file named HEAD in worktree' '
 
 	rm -fr .git/hooks &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 0377d3e..db65653 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -155,6 +155,7 @@ test_pause () {
 test_commit () {
 	notick= &&
 	signoff= &&
+	noverify= &&
 	while test $# != 0
 	do
 		case "$1" in
@@ -164,6 +165,9 @@ test_commit () {
 		--signoff)
 			signoff="$1"
 			;;
+		--no-verify)
+			noverify="$1"
+			;;
 		*)
 			break
 			;;
@@ -177,7 +181,7 @@ test_commit () {
 	then
 		test_tick
 	fi &&
-	git commit $signoff -m "$1" &&
+	git commit $signoff $noverify -m "$1" &&
 	git tag "${4:-$1}"
 }
 
-- 
2.0.1

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]