threads / patch / 58818

v2am: Allow passing --no-verify flag

Subject: [PATCH v2] am: Allow passing --no-verify flag

## tl;dr

4 messages between Nov 19, 2022 and Nov 27, 2022. Diffs are folded; open one to read it.

replies: 3people: 2as markdown or json

Thierry Reding· Nov 19, 2022, 00:50 UTC · lore
From: Thierry Reding <treding@nvidia.com>

The git-am --no-verify flag is analogous to the same flag passed to git-commit. It bypasses the pre-applypatch and applypatch-msg hooks if they are enabled.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v2:
- add test to verify that the new option works
 Documentation/git-am.txt |  8 +++++-
 builtin/am.c             | 11 ++++++--
 t/t4154-am-noverify.sh   | 60 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 4 deletions(-)
 create mode 100755 t/t4154-am-noverify.sh
Show changes to 3 files +75 −4

Documentation/git-am.txt, builtin/am.c, t/t4154-am-noverify.sh

diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 326276e51ce5..0c1dfb3c98b4 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -9,7 +9,7 @@ git-am - Apply a series of patches from a mailbox
 SYNOPSIS
 --------
 [verse]
-'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
+'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
 	 [--[no-]3way] [--interactive] [--committer-date-is-author-date]
 	 [--ignore-date] [--ignore-space-change | --ignore-whitespace]
 	 [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
@@ -138,6 +138,12 @@ include::rerere-options.txt[]
 --interactive::
 	Run interactively.
 
+-n::
+--no-verify::
+	By default, the pre-applypatch and applypatch-msg hooks are run.
+	When any of `--no-verify` or `-n` is given, these are bypassed.
+	See also linkgit:githooks[5].
+
 --committer-date-is-author-date::
 	By default the command records the date from the e-mail
 	message as the commit author date, and uses the time of
diff --git a/builtin/am.c b/builtin/am.c
index 20aea0d2487b..26ad8a468dc4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -117,6 +117,7 @@ struct am_state {
 
 	/* various operating modes and command line options */
 	int interactive;
+	int no_verify;
 	int threeway;
 	int quiet;
 	int signoff; /* enum signoff_type */
@@ -472,10 +473,12 @@ static void am_destroy(const struct am_state *state)
  */
 static int run_applypatch_msg_hook(struct am_state *state)
 {
-	int ret;
+	int ret = 0;
 
 	assert(state->msg);
-	ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+
+	if (!state->no_verify)
+		ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
 
 	if (!ret) {
 		FREE_AND_NULL(state->msg);
@@ -1640,7 +1643,7 @@ static void do_commit(const struct am_state *state)
 	const char *reflog_msg, *author, *committer = NULL;
 	struct strbuf sb = STRBUF_INIT;
 
-	if (run_hooks("pre-applypatch"))
+	if (!state->no_verify && run_hooks("pre-applypatch"))
 		exit(1);
 
 	if (write_cache_as_tree(&tree, 0, NULL))
@@ -2329,6 +2332,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_BOOL('i', "interactive", &state.interactive,
 			N_("run interactively")),
+		OPT_BOOL('n', "no-verify", &state.no_verify,
+			N_("bypass pre-applypatch and applypatch-msg hooks")),
 		OPT_HIDDEN_BOOL('b', "binary", &binary,
 			N_("historical option -- no-op")),
 		OPT_BOOL('3', "3way", &state.threeway,
diff --git a/t/t4154-am-noverify.sh b/t/t4154-am-noverify.sh
new file mode 100755
index 000000000000..fbf45998243f
--- /dev/null
+++ b/t/t4154-am-noverify.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='git am --no-verify'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	echo "root" >file &&
+	git add file &&
+	git commit -m "zeroth" &&
+	git branch side-success &&
+	git branch side-failure &&
+	echo "foo" >>file &&
+	git add file &&
+	git commit -m "first" &&
+	git format-patch --stdout HEAD^ >patch1
+'
+
+setup_success_hook () {
+	test_when_finished "rm -f actual_hooks expected_hooks" &&
+	echo "$1" >expected_hooks &&
+	test_hook "$1" <<-EOF
+	echo $1 >>actual_hooks
+	EOF
+}
+
+test_expect_success '--no-verify with succeeding hook' '
+	setup_success_hook "pre-applypatch" &&
+	setup_success_hook "applypatch-msg" &&
+	git checkout side-success &&
+	git am --no-verify patch1
+'
+
+setup_failing_hook () {
+	test_when_finished "rm -f actual_hooks" &&
+	test_hook "$1" <<-EOF
+	echo $1-failing-hook >>actual_hooks
+	exit 1
+	EOF
+}
+
+test_expect_failure 'with failing hook' '
+	test_when_finished "git am --abort" &&
+	setup_failing_hook "pre-applypatch" &&
+	setup_failing_hook "applypatch-msg" &&
+	git checkout side-failure &&
+	git am patch1
+'
+
+test_expect_success '--no-verify with failing hook' '
+	setup_success_hook "pre-applypatch" &&
+	setup_success_hook "applypatch-msg" &&
+	git checkout side-failure &&
+	git am --no-verify patch1
+'
+
+test_done
-- 
2.38.1
Junio C Hamano· Nov 21, 2022, 05:33 UTC · re: Thierry Reding · lore

Re: [PATCH v2] am: Allow passing --no-verify flag

Thierry Reding <thierry.reding@gmail.com> writes:
Show 10 quoted lines
> From: Thierry Reding <treding@nvidia.com>
>
> The git-am --no-verify flag is analogous to the same flag passed to
> git-commit. It bypasses the pre-applypatch and applypatch-msg hooks
> if they are enabled.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
> Changes in v2:
> - add test to verify that the new option works
Show 5 quoted lines
> +-n::
> +--no-verify::
> +	By default, the pre-applypatch and applypatch-msg hooks are run.
> +	When any of `--no-verify` or `-n` is given, these are bypassed.
> +	See also linkgit:githooks[5].

I think the goal of this topic is to allow bypassing the checks made by these two hooks (and possibly future ones that validate the input to "am"), and there are at least two possible implementations to achieve that goal. You can still run the hook and ignore its failure exit, or you can skip running the hook and pretend as if hook succeeded.

As it is documented that applypatch-msg is allowed to edit the message file to normalize the message, between the two, running the hook (to allow the hook to automatically edit the message) but ignoring its failure would be a more intuitive approach to "bypass" the check. If the option were called --no-hook or --bypass-hooks then it would be a different story, though.

Show 5 quoted lines
>  	assert(state->msg);
> -	ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
> +
> +	if (!state->no_verify)
> +		ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);

And it seems that this took a less intuitive avenue of bypassing the hook completely. I am not 100% convinced that this is the better choice (but I am not convinced it is the worse one, either).

Show 8 quoted lines
> diff --git a/t/t4154-am-noverify.sh b/t/t4154-am-noverify.sh
> new file mode 100755
> index 000000000000..fbf45998243f
> --- /dev/null
> +++ b/t/t4154-am-noverify.sh
> @@ -0,0 +1,60 @@
> +#!/bin/sh
> +

It is surprising, and I am not enthused to see, that this needs an entirely new script.

Don't we already have a script or two to test "am", among which the invocation of hooks is already tested?

Thierry Reding· Nov 25, 2022, 17:41 UTC · re: Junio C Hamano · lore

Re: [PATCH v2] am: Allow passing --no-verify flag

On Mon, Nov 21, 2022 at 02:33:06PM +0900, Junio C Hamano wrote:
Show 42 quoted lines
> Thierry Reding <thierry.reding@gmail.com> writes:
> 
> > From: Thierry Reding <treding@nvidia.com>
> >
> > The git-am --no-verify flag is analogous to the same flag passed to
> > git-commit. It bypasses the pre-applypatch and applypatch-msg hooks
> > if they are enabled.
> >
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > ---
> > Changes in v2:
> > - add test to verify that the new option works
> 
> > +-n::
> > +--no-verify::
> > +	By default, the pre-applypatch and applypatch-msg hooks are run.
> > +	When any of `--no-verify` or `-n` is given, these are bypassed.
> > +	See also linkgit:githooks[5].
> 
> I think the goal of this topic is to allow bypassing the checks made
> by these two hooks (and possibly future ones that validate the input
> to "am"), and there are at least two possible implementations to
> achieve that goal.  You can still run the hook and ignore its
> failure exit, or you can skip running the hook and pretend as if
> hook succeeded.
> 
> As it is documented that applypatch-msg is allowed to edit the
> message file to normalize the message, between the two, running the
> hook (to allow the hook to automatically edit the message) but
> ignoring its failure would be a more intuitive approach to "bypass"
> the check.  If the option were called --no-hook or --bypass-hooks
> then it would be a different story, though.
> 
> >  	assert(state->msg);
> > -	ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
> > +
> > +	if (!state->no_verify)
> > +		ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
> 
> And it seems that this took a less intuitive avenue of bypassing the
> hook completely.  I am not 100% convinced that this is the better
> choice (but I am not convinced it is the worse one, either).

Thinking a bit more about this, if we let applypatch-msg run but ignore failures and continue on to commit the result, wouldn't that potentially allow committing garbage? I'm thinking about cases where applypatch-msg may attempt to normalize the message and fails badly, leaving a partial commit message or none at all.

The primary use-case where I'd like to use this new option for git am is when the pre-applypatch hook fails and that has less of the risks associated with applypatch-msg, so perhaps --no-verify should only apply to pre-applypatch?

Show 15 quoted lines
> 
> > diff --git a/t/t4154-am-noverify.sh b/t/t4154-am-noverify.sh
> > new file mode 100755
> > index 000000000000..fbf45998243f
> > --- /dev/null
> > +++ b/t/t4154-am-noverify.sh
> > @@ -0,0 +1,60 @@
> > +#!/bin/sh
> > +
> 
> It is surprising, and I am not enthused to see, that this needs an
> entirely new script.
> 
> Don't we already have a script or two to test "am", among which the
> invocation of hooks is already tested?
I can move the tests to the corresponding sections in t/t4150-am.sh.
Thierry
Junio C Hamano· Nov 27, 2022, 01:27 UTC · re: Thierry Reding · lore

Re: [PATCH v2] am: Allow passing --no-verify flag

Thierry Reding <thierry.reding@gmail.com> writes:
Show 5 quoted lines
> Thinking a bit more about this, if we let applypatch-msg run but ignore
> failures and continue on to commit the result, wouldn't that potentially
> allow committing garbage? I'm thinking about cases where applypatch-msg
> may attempt to normalize the message and fails badly, leaving a partial
> commit message or none at all.

That is a very reasonable way to think about this. So I am sold on your approach of not running the hook at all.

Thanks.

← back to recent threads