{"thread":{"id":"63250","subject":"[PATCH] git: add --no-hooks global option","startedAt":"2025-04-03T22:38:12Z","lastAt":"2025-04-17T16:02:22Z","messageCount":17,"participants":["Derrick Stolee via GitGitGadget","brian m. carlson","Derrick Stolee","Phillip Wood","D. Ben Knoble","Lucas Seiki Oshiro","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"515617","messageId":"pull.1899.git.1743719888430.gitgitgadget@gmail.com","threadId":"63250","inReplyTo":null,"subject":"[PATCH] git: add --no-hooks global option","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-03T22:38:08Z","receivedAt":"2025-04-03T22:38:12Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Derrick Stolee <stolee@gmail.com>\n\nGit has several hooks which are executed during certain events as long\nas those hooks are enabled in the hooks directory (possibly moved from\n.git/hooks via the core.hooksPath config option). These are configured\nby the user, or perhaps by tooling the user has agreed to, and are not\nrequired to operate a Git repository.\n\nIn some situations, these hooks have poor performance and expert users\nmay want to skip the hooks as they don't seem to affect the current\nsituation. One example is a pre-commit hook that checks for certain\nstructures in the local changes, but expert users are likely to have\ndone the right thing in advance.\n\nI have come across users who have disabled hooks themselves either by\ndeleting hooks (supported, safe) or setting 'core.hooksPath' to some\nbogus path (seems unsafe). The supported process is painful to swap\nbetween the hook-enabled scenario and the hook-disabled scenario.\n\nTo that end, add a new --no-hooks global option to allow users to\ndisable hooks quickly. This option is modeled similarly to the\n--no-advice option in b79deeb554 (advice: add --no-advice global option,\n2024-05-03). This uses a GIT_HOOKS environment variable to communicate\nto subprocesses as well as making this a backwards-compatible way for\ntools to signal that they want to disable hooks.\n\nThe critical piece is that all hooks pass through run_hooks_opt() where\na static int will evaluate the environment variable and store that the\nvariable is initialized for faster repeated runs.\n\nSigned-off-by: Derrick Stolee <stolee@gmail.com>\n---\n    git: add --no-hooks global option\n    \n    This is hopefully a helpful feature to more than just the experts I've\n    been hearing from.\n    \n    Thanks,\n    \n     * Stolee\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1899%2Fderrickstolee%2Fno-hooks-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1899/derrickstolee/no-hooks-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1899\n\n Documentation/git.adoc       | 13 ++++++++++++-\n environment.h                |  6 ++++++\n git.c                        |  6 +++++-\n hook.c                       |  7 +++++++\n t/t1350-config-hooks-path.sh | 34 ++++++++++++++++++++++++++++++++++\n 5 files changed, 64 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git.adoc b/Documentation/git.adoc\nindex 743b7b00e4d..a34c8cfbe78 100644\n--- a/Documentation/git.adoc\n+++ b/Documentation/git.adoc\n@@ -14,7 +14,7 @@ SYNOPSIS\n     [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\n     [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n     [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\n-    <command> [<args>]\n+    [--no-hooks] <command> [<args>]\n \n DESCRIPTION\n -----------\n@@ -230,6 +230,12 @@ If you just want to run git as if it was started in `<path>` then use\n \tlinkgit:gitattributes[5]. This is equivalent to setting the\n \t`GIT_ATTR_SOURCE` environment variable.\n \n+--no-hooks::\n+\tSkip running local Git hooks, even if configured locally. Hooks\n+\tare an opt-in feature, so be sure that you know the impact of\n+\tignoring hooks when running with this option. This is equivalent\n+\tto setting `GIT_HOOKS=0` environment variable.\n+\n GIT COMMANDS\n ------------\n \n@@ -771,6 +777,11 @@ for further details.\n \tnot set, Git will choose buffered or record-oriented flushing\n \tbased on whether stdout appears to be redirected to a file or not.\n \n+`GIT_HOOKS`::\n+\tIf this Boolean environment variable is set to false, then commands\n+\twill ignore any configured hooks as if the `--no-hooks` option was\n+\tprovided.\n+\n `GIT_TRACE`::\n \tEnables general trace messages, e.g. alias expansion, built-in\n \tcommand execution and external command execution.\ndiff --git a/environment.h b/environment.h\nindex 45e690f203f..22ddf201144 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -50,6 +50,12 @@\n  */\n #define GIT_ADVICE_ENVIRONMENT \"GIT_ADVICE\"\n \n+/*\n+ * Environment variable used to propagate the --no-hooks global option to\n+ * the hooks layer and to any child processes.\n+ */\n+#define GIT_HOOKS \"GIT_HOOKS\"\n+\n /*\n  * Environment variable used in handshaking the wire protocol.\n  * Contains a colon ':' separated list of keys with optional values\ndiff --git a/git.c b/git.c\nindex 77c43595223..d7ebcf60947 100644\n--- a/git.c\n+++ b/git.c\n@@ -41,7 +41,7 @@ const char git_usage_string[] =\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\\n\"\n \t   \"           [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\\n\"\n \t   \"           [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\\n\"\n-\t   \"           <command> [<args>]\");\n+\t   \"           [--no-hooks] <command> [<args>]\");\n \n const char git_more_info_string[] =\n \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n@@ -349,6 +349,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_ADVICE_ENVIRONMENT, \"0\", 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n+\t\t} else if (!strcmp(cmd, \"--no-hooks\")) {\n+\t\t\tsetenv(GIT_HOOKS, \"0\", 1);\n+\t\t\tif (envchanged)\n+\t\t\t\t*envchanged = 1;\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n \t\t\tusage(git_usage_string);\ndiff --git a/hook.c b/hook.c\nindex b3de1048bf4..b209553d7a8 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -144,6 +144,13 @@ int run_hooks_opt(struct repository *r, const char *hook_name,\n \n \t\t.data = &cb_data,\n \t};\n+\tstatic int do_run_hooks = -1;\n+\n+\tif (do_run_hooks < 0)\n+\t\tdo_run_hooks = git_env_bool(GIT_HOOKS, 1);\n+\n+\tif (!do_run_hooks)\n+\t\tgoto cleanup;\n \n \tif (!options)\n \t\tBUG(\"a struct run_hooks_opt must be provided to run_hooks\");\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nindex 45a04929170..4c6a0eafe4e 100755\n--- a/t/t1350-config-hooks-path.sh\n+++ b/t/t1350-config-hooks-path.sh\n@@ -48,4 +48,38 @@ test_expect_success 'core.hooksPath=/dev/null' '\n \t{ test /dev/null = \"$value\" || test nul = \"$value\"; }\n '\n \n+test_expect_success '--no-hooks' '\n+\trm -f actual &&\n+\ttest_might_fail git config --unset core.hooksPath &&\n+\n+\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n+\techo HOOK >>actual\n+\tEOF\n+\n+\techo HOOK >expect &&\n+\n+\tgit commit --allow-empty -m \"A\" &&\n+\ttest_cmp expect actual &&\n+\n+\tgit --no-hooks commit --allow-empty -m \"B\" &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'GIT_HOOKS' '\n+\trm -f actual &&\n+\ttest_might_fail git config --unset core.hooksPath &&\n+\n+\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n+\techo HOOK >>actual\n+\tEOF\n+\n+\techo HOOK >expect &&\n+\n+\tGIT_HOOKS=1 git commit --allow-empty -m \"A\" &&\n+\ttest_cmp expect actual &&\n+\n+\tGIT_HOOKS=0 git commit --allow-empty -m \"B\" &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n\nbase-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\n-- \ngitgitgadget\n"},{"id":"515620","messageId":"Z-8Rxy4IK5EHKzLW@tapette.crustytoothpaste.net","threadId":"63250","inReplyTo":"pull.1899.git.1743719888430.gitgitgadget@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-04-03T22:55:03Z","receivedAt":"2025-04-03T22:55:05Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-04-03 at 22:38:08, Derrick Stolee via GitGitGadget wrote:\n> From: Derrick Stolee <stolee@gmail.com>\n> \n> Git has several hooks which are executed during certain events as long\n> as those hooks are enabled in the hooks directory (possibly moved from\n> .git/hooks via the core.hooksPath config option). These are configured\n> by the user, or perhaps by tooling the user has agreed to, and are not\n> required to operate a Git repository.\n> \n> In some situations, these hooks have poor performance and expert users\n> may want to skip the hooks as they don't seem to affect the current\n> situation. One example is a pre-commit hook that checks for certain\n> structures in the local changes, but expert users are likely to have\n> done the right thing in advance.\n> \n> I have come across users who have disabled hooks themselves either by\n> deleting hooks (supported, safe) or setting 'core.hooksPath' to some\n> bogus path (seems unsafe). The supported process is painful to swap\n> between the hook-enabled scenario and the hook-disabled scenario.\n> \n> To that end, add a new --no-hooks global option to allow users to\n> disable hooks quickly. This option is modeled similarly to the\n> --no-advice option in b79deeb554 (advice: add --no-advice global option,\n> 2024-05-03). This uses a GIT_HOOKS environment variable to communicate\n> to subprocesses as well as making this a backwards-compatible way for\n> tools to signal that they want to disable hooks.\n> \n> The critical piece is that all hooks pass through run_hooks_opt() where\n> a static int will evaluate the environment variable and store that the\n> variable is initialized for faster repeated runs.\n> \n> Signed-off-by: Derrick Stolee <stolee@gmail.com>\n> ---\n>     git: add --no-hooks global option\n>     \n>     This is hopefully a helpful feature to more than just the experts I've\n>     been hearing from.\n\nI think this is functionality that Jenkins wants because they've\nconfigured `core.hooksPath` to `/dev/null`, allegedly for security\nreasons.  Of course, enabling this feature will also break Git LFS, but\nin a less noticeable and detectable way (currently, Git LFS will fail on\nattempting to install hooks with that setting of `core.hooksPath`, which\nis at least noticeable).\n\nI do think that in general certain types of hooks, such as pre-commit\nhooks, should absolutely be optional.  There are lots of reasons to\ncommit WIP data that doesn't meet whatever standard and we shouldn't\nimpede expert users from expert workflows, even if there are many fewer\nreasons to do things like bypass pushing Git LFS objects (which are\nimportant for integrity).\n\nSo I can see the utility of this feature but I can also see how it can\nbreak lots of things when handled poorly.  Of course, we also have `git\nreset --hard` and there's lots of hand-wringing on Stack Overflow about\nhaving deleted important data, so we have some precedent for expert\nfeatures that could break things badly.\n\nI don't otherwise have a strong opinion either way, although I'd lean\nslightly in favour of this series.  I'd of course welcome other people's\nthoughts here.\n-- \nbrian m. carlson (they/them)\nToronto, Ontario, CA\n"},{"id":"515622","messageId":"c1312cb3-dd2b-4b04-8c6f-2d787125448d@gmail.com","threadId":"63250","inReplyTo":"Z-8Rxy4IK5EHKzLW@tapette.crustytoothpaste.net","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2025-04-04T00:40:07Z","receivedAt":"2025-04-04T00:40:09Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/3/2025 6:55 PM, brian m. carlson wrote:\n> On 2025-04-03 at 22:38:08, Derrick Stolee via GitGitGadget wrote:\n>> From: Derrick Stolee <stolee@gmail.com>\n\n>> To that end, add a new --no-hooks global option to allow users to\n>> disable hooks quickly. This option is modeled similarly to the\n>> --no-advice option in b79deeb554 (advice: add --no-advice global option,\n>> 2024-05-03). This uses a GIT_HOOKS environment variable to communicate\n>> to subprocesses as well as making this a backwards-compatible way for\n>> tools to signal that they want to disable hooks.\n>>\n>> The critical piece is that all hooks pass through run_hooks_opt() where\n>> a static int will evaluate the environment variable and store that the\n>> variable is initialized for faster repeated runs.\n\n>>     This is hopefully a helpful feature to more than just the experts I've\n>>     been hearing from.\n> \n> I think this is functionality that Jenkins wants because they've\n> configured `core.hooksPath` to `/dev/null`, allegedly for security\n> reasons.  Of course, enabling this feature will also break Git LFS, but\n> in a less noticeable and detectable way (currently, Git LFS will fail on\n> attempting to install hooks with that setting of `core.hooksPath`, which\n> is at least noticeable).\n\nI agree that some hooks are necessary for certain repositories to keep\ntheir data consistent. Another example is the pre- and post-command hooks\nthat are in the microsoft/git fork that are necessary to avoid issues with\nthe virtualization layer of VFS for Git. If a user disables those hooks\nduring a command that changes the index, then they are going to have a bad\ntime. But maybe they want to disable hooks because all they need is a\n'git rev-parse HEAD' or similarly read-only operation. \n> I do think that in general certain types of hooks, such as pre-commit\n> hooks, should absolutely be optional.  There are lots of reasons to\n> commit WIP data that doesn't meet whatever standard and we shouldn't\n> impede expert users from expert workflows, even if there are many fewer\n> reasons to do things like bypass pushing Git LFS objects (which are\n> important for integrity).\n\nMy intention is definitely more on the side of these optional hooks. \n> So I can see the utility of this feature but I can also see how it can\n> break lots of things when handled poorly.  Of course, we also have `git\n> reset --hard` and there's lots of hand-wringing on Stack Overflow about\n> having deleted important data, so we have some precedent for expert\n> features that could break things badly.\n> \n> I don't otherwise have a strong opinion either way, although I'd lean\n> slightly in favour of this series.  I'd of course welcome other people's\n> thoughts here.\nThank you for chiming in! I look forward to other thoughts and whetherthe warning in the docs should be strengthened.\n\nThanks,\n-Stolee\n\n"},{"id":"515670","messageId":"2c7994bc-2be0-43a5-9627-0d530746b3ab@gmail.com","threadId":"63250","inReplyTo":"pull.1899.git.1743719888430.gitgitgadget@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-04-04T14:15:22Z","receivedAt":"2025-04-04T14:15:25Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Stolee\n\nOn 03/04/2025 23:38, Derrick Stolee via GitGitGadget wrote:\n> From: Derrick Stolee <stolee@gmail.com>\n> \n> In some situations, these hooks have poor performance and expert users\n> may want to skip the hooks as they don't seem to affect the current\n> situation. One example is a pre-commit hook that checks for certain\n> structures in the local changes, but expert users are likely to have\n> done the right thing in advance.\n\nNext they'll be saying that they never make a mistake when writing a one \nline patch! More seriously I agree there are times when one may want to \nbypass the pre-commit hook but we already have \"git commit --no-verify\" \nto do that. In general hooks that are so slow that the user wants to \nbypass them are self-defeating and I'd argue that the solution is to fix \nthe performance of the hook rather than make it easier to skip it. One \nsolution for speeding up pre-commit hooks is to process files in \nparallel. Unfortunately git does not provide support for that but there \nare hook frameworks that do.\n\n> I have come across users who have disabled hooks themselves either by\n> deleting hooks (supported, safe) or setting 'core.hooksPath' to some\n> bogus path (seems unsafe).\n\nI thought \"git -c core.hooksPath=/dev/null\" was a fairly standard way of \ndisabling hooks on a one-off basis - what makes it unsafe?\n\n> The supported process is painful to swap\n> between the hook-enabled scenario and the hook-disabled scenario.\n> \n> To that end, add a new --no-hooks global option to allow users to\n> disable hooks quickly. This option is modeled similarly to the\n> --no-advice option in b79deeb554 (advice: add --no-advice global option,\n> 2024-05-03). This uses a GIT_HOOKS environment variable to communicate\n> to subprocesses as well as making this a backwards-compatible way for\n> tools to signal that they want to disable hooks.\n> \n> The critical piece is that all hooks pass through run_hooks_opt() where\n> a static int will evaluate the environment variable and store that the\n> variable is initialized for faster repeated runs.\n\nThat certainly makes the implementation much more viable. However I'm \nnot really convinced this is a good idea.\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Derrick Stolee <stolee@gmail.com>\n> ---\n>      git: add --no-hooks global option\n>      \n>      This is hopefully a helpful feature to more than just the experts I've\n>      been hearing from.\n>      \n>      Thanks,\n>      \n>       * Stolee\n> \n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1899%2Fderrickstolee%2Fno-hooks-v1\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1899/derrickstolee/no-hooks-v1\n> Pull-Request: https://github.com/gitgitgadget/git/pull/1899\n> \n>   Documentation/git.adoc       | 13 ++++++++++++-\n>   environment.h                |  6 ++++++\n>   git.c                        |  6 +++++-\n>   hook.c                       |  7 +++++++\n>   t/t1350-config-hooks-path.sh | 34 ++++++++++++++++++++++++++++++++++\n>   5 files changed, 64 insertions(+), 2 deletions(-)\n> \n> diff --git a/Documentation/git.adoc b/Documentation/git.adoc\n> index 743b7b00e4d..a34c8cfbe78 100644\n> --- a/Documentation/git.adoc\n> +++ b/Documentation/git.adoc\n> @@ -14,7 +14,7 @@ SYNOPSIS\n>       [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\n>       [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n>       [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\n> -    <command> [<args>]\n> +    [--no-hooks] <command> [<args>]\n>   \n>   DESCRIPTION\n>   -----------\n> @@ -230,6 +230,12 @@ If you just want to run git as if it was started in `<path>` then use\n>   \tlinkgit:gitattributes[5]. This is equivalent to setting the\n>   \t`GIT_ATTR_SOURCE` environment variable.\n>   \n> +--no-hooks::\n> +\tSkip running local Git hooks, even if configured locally. Hooks\n> +\tare an opt-in feature, so be sure that you know the impact of\n> +\tignoring hooks when running with this option. This is equivalent\n> +\tto setting `GIT_HOOKS=0` environment variable.\n> +\n>   GIT COMMANDS\n>   ------------\n>   \n> @@ -771,6 +777,11 @@ for further details.\n>   \tnot set, Git will choose buffered or record-oriented flushing\n>   \tbased on whether stdout appears to be redirected to a file or not.\n>   \n> +`GIT_HOOKS`::\n> +\tIf this Boolean environment variable is set to false, then commands\n> +\twill ignore any configured hooks as if the `--no-hooks` option was\n> +\tprovided.\n> +\n>   `GIT_TRACE`::\n>   \tEnables general trace messages, e.g. alias expansion, built-in\n>   \tcommand execution and external command execution.\n> diff --git a/environment.h b/environment.h\n> index 45e690f203f..22ddf201144 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -50,6 +50,12 @@\n>    */\n>   #define GIT_ADVICE_ENVIRONMENT \"GIT_ADVICE\"\n>   \n> +/*\n> + * Environment variable used to propagate the --no-hooks global option to\n> + * the hooks layer and to any child processes.\n> + */\n> +#define GIT_HOOKS \"GIT_HOOKS\"\n> +\n>   /*\n>    * Environment variable used in handshaking the wire protocol.\n>    * Contains a colon ':' separated list of keys with optional values\n> diff --git a/git.c b/git.c\n> index 77c43595223..d7ebcf60947 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -41,7 +41,7 @@ const char git_usage_string[] =\n>   \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\\n\"\n>   \t   \"           [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\\n\"\n>   \t   \"           [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\\n\"\n> -\t   \"           <command> [<args>]\");\n> +\t   \"           [--no-hooks] <command> [<args>]\");\n>   \n>   const char git_more_info_string[] =\n>   \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n> @@ -349,6 +349,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n>   \t\t\tsetenv(GIT_ADVICE_ENVIRONMENT, \"0\", 1);\n>   \t\t\tif (envchanged)\n>   \t\t\t\t*envchanged = 1;\n> +\t\t} else if (!strcmp(cmd, \"--no-hooks\")) {\n> +\t\t\tsetenv(GIT_HOOKS, \"0\", 1);\n> +\t\t\tif (envchanged)\n> +\t\t\t\t*envchanged = 1;\n>   \t\t} else {\n>   \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n>   \t\t\tusage(git_usage_string);\n> diff --git a/hook.c b/hook.c\n> index b3de1048bf4..b209553d7a8 100644\n> --- a/hook.c\n> +++ b/hook.c\n> @@ -144,6 +144,13 @@ int run_hooks_opt(struct repository *r, const char *hook_name,\n>   \n>   \t\t.data = &cb_data,\n>   \t};\n> +\tstatic int do_run_hooks = -1;\n> +\n> +\tif (do_run_hooks < 0)\n> +\t\tdo_run_hooks = git_env_bool(GIT_HOOKS, 1);\n> +\n> +\tif (!do_run_hooks)\n> +\t\tgoto cleanup;\n>   \n>   \tif (!options)\n>   \t\tBUG(\"a struct run_hooks_opt must be provided to run_hooks\");\n> diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\n> index 45a04929170..4c6a0eafe4e 100755\n> --- a/t/t1350-config-hooks-path.sh\n> +++ b/t/t1350-config-hooks-path.sh\n> @@ -48,4 +48,38 @@ test_expect_success 'core.hooksPath=/dev/null' '\n>   \t{ test /dev/null = \"$value\" || test nul = \"$value\"; }\n>   '\n>   \n> +test_expect_success '--no-hooks' '\n> +\trm -f actual &&\n> +\ttest_might_fail git config --unset core.hooksPath &&\n> +\n> +\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n> +\techo HOOK >>actual\n> +\tEOF\n> +\n> +\techo HOOK >expect &&\n> +\n> +\tgit commit --allow-empty -m \"A\" &&\n> +\ttest_cmp expect actual &&\n> +\n> +\tgit --no-hooks commit --allow-empty -m \"B\" &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_expect_success 'GIT_HOOKS' '\n> +\trm -f actual &&\n> +\ttest_might_fail git config --unset core.hooksPath &&\n> +\n> +\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n> +\techo HOOK >>actual\n> +\tEOF\n> +\n> +\techo HOOK >expect &&\n> +\n> +\tGIT_HOOKS=1 git commit --allow-empty -m \"A\" &&\n> +\ttest_cmp expect actual &&\n> +\n> +\tGIT_HOOKS=0 git commit --allow-empty -m \"B\" &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>   test_done\n> \n> base-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\n\n"},{"id":"516007","messageId":"CALnO6CD4ApAC_QqP-XCm0yCo=fx2j8v8Z6ByjUHBYiE=JfZA2w@mail.gmail.com","threadId":"63250","inReplyTo":"pull.1899.git.1743719888430.gitgitgadget@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-04-11T18:53:17Z","receivedAt":"2025-04-11T18:53:30Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Thu, Apr 3, 2025 at 6:38 PM Derrick Stolee via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Derrick Stolee <stolee@gmail.com>\n>\n> Git has several hooks which are executed during certain events as long\n> as those hooks are enabled in the hooks directory (possibly moved from\n> .git/hooks via the core.hooksPath config option). These are configured\n> by the user, or perhaps by tooling the user has agreed to, and are not\n> required to operate a Git repository.\n>\n> In some situations, these hooks have poor performance and expert users\n> may want to skip the hooks as they don't seem to affect the current\n> situation. One example is a pre-commit hook that checks for certain\n> structures in the local changes, but expert users are likely to have\n> done the right thing in advance.\n\nOr a pre-push hook that runs tests which, for some reason, are very\nslow to execute but which isn't properly shutdown by a normal SIGINT,\nmessing up my shell.\n\n> I have come across users who have disabled hooks themselves either by\n> deleting hooks (supported, safe) or setting 'core.hooksPath' to some\n> bogus path (seems unsafe). The supported process is painful to swap\n> between the hook-enabled scenario and the hook-disabled scenario.\n\nIn my particular case, the tool being used (husky) sets core.hooksPath\nto a directory in the repo, so I can go back to using my preferred\nhooks simply by unsetting core.hooksPath, which seems safe. But\nswapping is still a bit painful, as mentioned.\n\nWorse, every \"npm install\" in this repo re-enables the hooks, so I\nhave to remember to reset core.hooksPath :/ When I don't, I spend a\nfew frustrating minutes getting back to normal. And then I\naccidentally train myself to use --no-verify often with this project,\nwhich is IMO a worse state of affairs.\n\nObviously, this repo's hooks need fixed, but in the interim something\nlike --no-hooks seems useful to me. Not sure if I count among the\nexperts or not /shrug.\n\n> To that end, add a new --no-hooks global option to allow users to\n> disable hooks quickly. This option is modeled similarly to the\n> --no-advice option in b79deeb554 (advice: add --no-advice global option,\n> 2024-05-03). This uses a GIT_HOOKS environment variable to communicate\n> to subprocesses as well as making this a backwards-compatible way for\n> tools to signal that they want to disable hooks.\n\nOn a related note: with client-side hooks always being considered\noptional, it seems like there ought to be a safe, sane way to turn\nthem off (rather than remember --no-verify for the various commands,\nwhich is probably the safe, sane way to bypass them on a one-off\nbasis).\n\nMaybe with this I'll have more ammo to convince folks that their\nsanity/security/whatever checks belong in server-side hooks and\noptional developer scripts rather than pre-commit hooks.\n\n>\n> The critical piece is that all hooks pass through run_hooks_opt() where\n> a static int will evaluate the environment variable and store that the\n> variable is initialized for faster repeated runs.\n>\n> Signed-off-by: Derrick Stolee <stolee@gmail.com>\n> ---\n>     git: add --no-hooks global option\n>\n>     This is hopefully a helpful feature to more than just the experts I've\n>     been hearing from.\n>\n>     Thanks,\n>\n>      * Stolee\n>\n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1899%2Fderrickstolee%2Fno-hooks-v1\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1899/derrickstolee/no-hooks-v1\n> Pull-Request: https://github.com/gitgitgadget/git/pull/1899\n>\n>  Documentation/git.adoc       | 13 ++++++++++++-\n>  environment.h                |  6 ++++++\n>  git.c                        |  6 +++++-\n>  hook.c                       |  7 +++++++\n>  t/t1350-config-hooks-path.sh | 34 ++++++++++++++++++++++++++++++++++\n>  5 files changed, 64 insertions(+), 2 deletions(-)\n>\n> diff --git a/Documentation/git.adoc b/Documentation/git.adoc\n> index 743b7b00e4d..a34c8cfbe78 100644\n> --- a/Documentation/git.adoc\n> +++ b/Documentation/git.adoc\n> @@ -14,7 +14,7 @@ SYNOPSIS\n>      [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\n>      [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n>      [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\n> -    <command> [<args>]\n> +    [--no-hooks] <command> [<args>]\n>\n>  DESCRIPTION\n>  -----------\n> @@ -230,6 +230,12 @@ If you just want to run git as if it was started in `<path>` then use\n>         linkgit:gitattributes[5]. This is equivalent to setting the\n>         `GIT_ATTR_SOURCE` environment variable.\n>\n> +--no-hooks::\n> +       Skip running local Git hooks, even if configured locally. Hooks\n> +       are an opt-in feature, so be sure that you know the impact of\n> +       ignoring hooks when running with this option. This is equivalent\n> +       to setting `GIT_HOOKS=0` environment variable.\n> +\n>  GIT COMMANDS\n>  ------------\n>\n> @@ -771,6 +777,11 @@ for further details.\n>         not set, Git will choose buffered or record-oriented flushing\n>         based on whether stdout appears to be redirected to a file or not.\n>\n> +`GIT_HOOKS`::\n> +       If this Boolean environment variable is set to false, then commands\n> +       will ignore any configured hooks as if the `--no-hooks` option was\n> +       provided.\n> +\n>  `GIT_TRACE`::\n>         Enables general trace messages, e.g. alias expansion, built-in\n>         command execution and external command execution.\n> diff --git a/environment.h b/environment.h\n> index 45e690f203f..22ddf201144 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -50,6 +50,12 @@\n>   */\n>  #define GIT_ADVICE_ENVIRONMENT \"GIT_ADVICE\"\n>\n> +/*\n> + * Environment variable used to propagate the --no-hooks global option to\n> + * the hooks layer and to any child processes.\n> + */\n> +#define GIT_HOOKS \"GIT_HOOKS\"\n> +\n>  /*\n>   * Environment variable used in handshaking the wire protocol.\n>   * Contains a colon ':' separated list of keys with optional values\n> diff --git a/git.c b/git.c\n> index 77c43595223..d7ebcf60947 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -41,7 +41,7 @@ const char git_usage_string[] =\n>            \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\\n\"\n>            \"           [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\\n\"\n>            \"           [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\\n\"\n> -          \"           <command> [<args>]\");\n> +          \"           [--no-hooks] <command> [<args>]\");\n>\n>  const char git_more_info_string[] =\n>         N_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n> @@ -349,6 +349,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n>                         setenv(GIT_ADVICE_ENVIRONMENT, \"0\", 1);\n>                         if (envchanged)\n>                                 *envchanged = 1;\n> +               } else if (!strcmp(cmd, \"--no-hooks\")) {\n> +                       setenv(GIT_HOOKS, \"0\", 1);\n> +                       if (envchanged)\n> +                               *envchanged = 1;\n>                 } else {\n>                         fprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n>                         usage(git_usage_string);\n> diff --git a/hook.c b/hook.c\n> index b3de1048bf4..b209553d7a8 100644\n> --- a/hook.c\n> +++ b/hook.c\n> @@ -144,6 +144,13 @@ int run_hooks_opt(struct repository *r, const char *hook_name,\n>\n>                 .data = &cb_data,\n>         };\n> +       static int do_run_hooks = -1;\n> +\n> +       if (do_run_hooks < 0)\n> +               do_run_hooks = git_env_bool(GIT_HOOKS, 1);\n> +\n> +       if (!do_run_hooks)\n> +               goto cleanup;\n>\n>         if (!options)\n>                 BUG(\"a struct run_hooks_opt must be provided to run_hooks\");\n> diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\n> index 45a04929170..4c6a0eafe4e 100755\n> --- a/t/t1350-config-hooks-path.sh\n> +++ b/t/t1350-config-hooks-path.sh\n> @@ -48,4 +48,38 @@ test_expect_success 'core.hooksPath=/dev/null' '\n>         { test /dev/null = \"$value\" || test nul = \"$value\"; }\n>  '\n>\n> +test_expect_success '--no-hooks' '\n> +       rm -f actual &&\n> +       test_might_fail git config --unset core.hooksPath &&\n> +\n> +       write_script .git/hooks/pre-commit <<-\\EOF &&\n> +       echo HOOK >>actual\n> +       EOF\n> +\n> +       echo HOOK >expect &&\n> +\n> +       git commit --allow-empty -m \"A\" &&\n> +       test_cmp expect actual &&\n> +\n> +       git --no-hooks commit --allow-empty -m \"B\" &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'GIT_HOOKS' '\n> +       rm -f actual &&\n> +       test_might_fail git config --unset core.hooksPath &&\n> +\n> +       write_script .git/hooks/pre-commit <<-\\EOF &&\n> +       echo HOOK >>actual\n> +       EOF\n> +\n> +       echo HOOK >expect &&\n> +\n> +       GIT_HOOKS=1 git commit --allow-empty -m \"A\" &&\n> +       test_cmp expect actual &&\n> +\n> +       GIT_HOOKS=0 git commit --allow-empty -m \"B\" &&\n> +       test_cmp expect actual\n> +'\n> +\n>  test_done\n>\n> base-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\n> --\n> gitgitgadget\n>\n\n\n-- \nD. Ben Knoble\n"},{"id":"516089","messageId":"cb3d080b-51a3-4096-9650-34ec4ed68f1d@gmail.com","threadId":"63250","inReplyTo":"2c7994bc-2be0-43a5-9627-0d530746b3ab@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2025-04-14T10:59:34Z","receivedAt":"2025-04-14T10:59:37Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/4/2025 10:15 AM, Phillip Wood wrote:\n> Hi Stolee\n> \n> On 03/04/2025 23:38, Derrick Stolee via GitGitGadget wrote:\n>> From: Derrick Stolee <stolee@gmail.com>\n>>\n>> In some situations, these hooks have poor performance and expert users\n>> may want to skip the hooks as they don't seem to affect the current\n>> situation. One example is a pre-commit hook that checks for certain\n>> structures in the local changes, but expert users are likely to have\n>> done the right thing in advance.\n> \n> Next they'll be saying that they never make a mistake when writing a\n> one line patch! More seriously I agree there are times when one may\n> want to bypass the pre-commit hook but we already have \"git commit\n> --no-verify\" to do that. In general hooks that are so slow that the\n> user wants to bypass them are self-defeating and I'd argue that the\n> solution is to fix the performance of the hook rather than make it\n> easier to skip it.\n\nBoth can also be an option.\n\n> One solution for speeding up pre-commit hooks is\n> to process files in parallel. Unfortunately git does not provide\n> support for that but there are hook frameworks that do.\n\n>> I have come across users who have disabled hooks themselves either by\n>> deleting hooks (supported, safe) or setting 'core.hooksPath' to some\n>> bogus path (seems unsafe).\n> \n> I thought \"git -c core.hooksPath=/dev/null\" was a fairly standard\n> way of disabling hooks on a one-off basis - what makes it unsafe?\n\nYou're right. I was thinking about setting it to a \"directory that\ndoesn't exist\" (but actually could be a path that exists accidentally\nlike \"/bogus\") but I forgot that we could use /dev/null.\n\nI'll remove this \"(seems unsafe)\" wording. \n>> The supported process is painful to swap\n>> between the hook-enabled scenario and the hook-disabled scenario.\n>>\n>> To that end, add a new --no-hooks global option to allow users to\n>> disable hooks quickly. This option is modeled similarly to the\n>> --no-advice option in b79deeb554 (advice: add --no-advice global option,\n>> 2024-05-03). This uses a GIT_HOOKS environment variable to communicate\n>> to subprocesses as well as making this a backwards-compatible way for\n>> tools to signal that they want to disable hooks.\n>>\n>> The critical piece is that all hooks pass through run_hooks_opt() where\n>> a static int will evaluate the environment variable and store that the\n>> variable is initialized for faster repeated runs.\n> \n> That certainly makes the implementation much more viable. However I'm\n> not really convinced this is a good idea.\n\nI don't read a strong reason in your message that this is a _bad_\nidea either. As in, there's nothing that hints that this will cause\nsignificant harm to users other than providing a new footgun (and we\nhave plenty of those for folks willing to look, including the\n_existence_ of hooks).\n\nThanks,\n-Stolee\n\n\n"},{"id":"516107","messageId":"1602379A-B5FB-410D-9622-F31333461E74@gmail.com","threadId":"63250","inReplyTo":"2c7994bc-2be0-43a5-9627-0d530746b3ab@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Lucas Seiki Oshiro","fromEmail":"lucasseikioshiro@gmail.com","sentAt":"2025-04-14T15:25:42Z","receivedAt":"2025-04-14T15:25:57Z","isPatch":true,"sender":{"key":"lucasseikioshiro@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12701580?v=4"},"body":"Hi!\n\n> I thought \"git -c core.hooksPath=/dev/null\" was a fairly standard way of disabling hooks\n\nGiven that, wouldn't it be a case to turn this into a documentation patch?\n\nI just searched here I found that we even have a test for it (introduced\nin c8f6478), but I couldn't find that as a recommendation in our docs."},{"id":"516141","messageId":"Z_14rtSaqdoNDsfa@tapette.crustytoothpaste.net","threadId":"63250","inReplyTo":"1602379A-B5FB-410D-9622-F31333461E74@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-04-14T21:05:50Z","receivedAt":"2025-04-14T21:05:53Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-04-14 at 15:25:42, Lucas Seiki Oshiro wrote:\n> Hi!\n> \n> > I thought \"git -c core.hooksPath=/dev/null\" was a fairly standard way of disabling hooks\n> \n> Given that, wouldn't it be a case to turn this into a documentation patch?\n> \n> I just searched here I found that we even have a test for it (introduced\n> in c8f6478), but I couldn't find that as a recommendation in our docs.\n\nI think if we decide to keep this series, then we should probably keep\nthe documentation in this series, since it will be clearer and more\nstraightforward as a way to disable hooks, and if we don't, then a new\ndocumentation patch would be a good idea.\n-- \nbrian m. carlson (they/them)\nToronto, Ontario, CA\n"},{"id":"516276","messageId":"a5632198-9e04-4302-a3c9-1cbf0f0cad65@gmail.com","threadId":"63250","inReplyTo":"cb3d080b-51a3-4096-9650-34ec4ed68f1d@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-04-16T10:29:13Z","receivedAt":"2025-04-16T10:29:17Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Stolee\n\nOn 14/04/2025 11:59, Derrick Stolee wrote:\n> On 4/4/2025 10:15 AM, Phillip Wood wrote:\n>> On 03/04/2025 23:38, Derrick Stolee via GitGitGadget wrote:\n>>> From: Derrick Stolee <stolee@gmail.com>\n>>>\n>>> To that end, add a new --no-hooks global option to allow users to\n>>> disable hooks quickly. This option is modeled similarly to the\n>>> --no-advice option in b79deeb554 (advice: add --no-advice global option,\n>>> 2024-05-03). This uses a GIT_HOOKS environment variable to communicate\n>>> to subprocesses as well as making this a backwards-compatible way for\n>>> tools to signal that they want to disable hooks.\n>>>\n>>> The critical piece is that all hooks pass through run_hooks_opt() where\n>>> a static int will evaluate the environment variable and store that the\n>>> variable is initialized for faster repeated runs.\n>>\n>> That certainly makes the implementation much more viable. However I'm\n>> not really convinced this is a good idea.\n> \n> I don't read a strong reason in your message that this is a _bad_\n> idea either. As in, there's nothing that hints that this will cause\n> significant harm to users other than providing a new footgun (and we\n> have plenty of those for folks willing to look, including the\n> _existence_ of hooks).\n\nIt is certainly not a terrible idea given that it is possible to disable \nhooks already but I'm not clear what the motivation is. I don't find the \nexample of a skipping a pre-commit hook persuasive as we already provide \na convenient way for users to skip that hook. Elsewhere in this thread \nyou mention the \"pre-command\" and \"post-command\" hooks but they are not \npart of git - if a fork is running its own hooks and that is causing \nproblems for users I'm not sure we want to change the upstream project \nto address that. If there was a clearer motivation it would be easier to \nunderstand the benefits of this change.\n\nBest Wishes\n\nPhillip\n\n"},{"id":"516289","messageId":"xmqqh62oi3k7.fsf@gitster.g","threadId":"63250","inReplyTo":"a5632198-9e04-4302-a3c9-1cbf0f0cad65@gmail.com","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-04-16T14:28:08Z","receivedAt":"2025-04-16T14:28:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n>> I don't read a strong reason in your message that this is a _bad_\n>> idea either. As in, there's nothing that hints that this will cause\n>> significant harm to users other than providing a new footgun (and we\n>> have plenty of those for folks willing to look, including the\n>> _existence_ of hooks).\n>\n> It is certainly not a terrible idea given that it is possible to\n> disable hooks already but I'm not clear what the motivation is. I\n> don't find the example of a skipping a pre-commit hook persuasive as\n> we already provide a convenient way for users to skip that\n> hook. Elsewhere in this thread you mention the \"pre-command\" and\n> \"post-command\" hooks but they are not part of git - if a fork is\n> running its own hooks and that is causing problems for users I'm not\n> sure we want to change the upstream project to address that. If there\n> was a clearer motivation it would be easier to understand the benefits\n> of this change.\n\nThanks for pushing back.  The default for any new changes is not to\napply unless there is a compelling reason why it is a good idea,\nsaying that this is not a bad thing does not serve as an effective\njustification.\n\nIf we want to give scripters a more stable foundation to build on,\nthe answer should not be to pile more and more \"no hooks, no\nconfigurations, just a vanilla mode of operation\" options to\nend-user facing porcelain commands, but to clean up the internal\nimplementation of such porcelain commands to refactor into stable\nplumbing commands that scripters can rely on.\n"},{"id":"516296","messageId":"baa62f25-faa4-418f-8100-0a75cb803267@gmail.com","threadId":"63250","inReplyTo":"xmqqh62oi3k7.fsf@gitster.g","subject":"Re: [PATCH] git: add --no-hooks global option","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2025-04-16T15:30:51Z","receivedAt":"2025-04-16T15:30:53Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/16/2025 10:28 AM, Junio C Hamano wrote:\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n> \n>>> I don't read a strong reason in your message that this is a _bad_\n>>> idea either. As in, there's nothing that hints that this will cause\n>>> significant harm to users other than providing a new footgun (and we\n>>> have plenty of those for folks willing to look, including the\n>>> _existence_ of hooks).\n>>\n>> It is certainly not a terrible idea given that it is possible to\n>> disable hooks already but I'm not clear what the motivation is. I\n>> don't find the example of a skipping a pre-commit hook persuasive as\n>> we already provide a convenient way for users to skip that\n>> hook. Elsewhere in this thread you mention the \"pre-command\" and\n>> \"post-command\" hooks but they are not part of git - if a fork is\n>> running its own hooks and that is causing problems for users I'm not\n>> sure we want to change the upstream project to address that. If there\n>> was a clearer motivation it would be easier to understand the benefits\n>> of this change.\n> \n> Thanks for pushing back.  The default for any new changes is not to\n> apply unless there is a compelling reason why it is a good idea,\n> saying that this is not a bad thing does not serve as an effective\n> justification.\n> \n> If we want to give scripters a more stable foundation to build on,\n> the answer should not be to pile more and more \"no hooks, no\n> configurations, just a vanilla mode of operation\" options to\n> end-user facing porcelain commands, but to clean up the internal\n> implementation of such porcelain commands to refactor into stable\n> plumbing commands that scripters can rely on.\n\nThank you for a decisive answer. I'll move forward with a v2 that\nis a doc-only change, documenting the /dev/null value as a supported\nmechanism for disabling hooks.\n\nThanks,\n-Stolee\n\n"},{"id":"516297","messageId":"pull.1899.v2.git.1744818135435.gitgitgadget@gmail.com","threadId":"63250","inReplyTo":"pull.1899.git.1743719888430.gitgitgadget@gmail.com","subject":"[PATCH v2] docs: document core.hooksPath=/dev/null","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-04-16T15:42:15Z","receivedAt":"2025-04-16T15:42:18Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Derrick Stolee <stolee@gmail.com>\n\nIf a user wishes to disable hooks, then they can do so using the\nestablished pattern of setting 'core.hooksPath' to /dev/null. This is\nalready tested in t1350-config-hooks-path.sh, but has not previously\nbeen visible in the documentation.\n\nUpdate the documentation to include this as an option.\n\nSigned-off-by: Derrick Stolee <stolee@gmail.com>\n---\n    docs: document core.hooksPath=/dev/null\n    \n    Based on the discussion of the proposed --no-hooks option in v1, that\n    code change is dropped in favor of this documentation of\n    core.hooksPath=/dev/null.\n    \n    Thanks,\n    \n     * Stolee\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1899%2Fderrickstolee%2Fno-hooks-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1899/derrickstolee/no-hooks-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1899\n\nRange-diff vs v1:\n\n 1:  91e82850e7d < -:  ----------- git: add --no-hooks global option\n -:  ----------- > 1:  a9cd4bd5100 docs: document core.hooksPath=/dev/null\n\n\n Documentation/config/core.adoc | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 8f6d8e77541..9fde1ab63a7 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -512,6 +512,11 @@ centrally configure your Git hooks instead of configuring them on a\n per-repository basis, or as a more flexible and centralized\n alternative to having an `init.templateDir` where you've changed\n default hooks.\n++\n+You can also disable all hooks entirely by setting `core.hooksPath`\n+to `/dev/null`. This is usually only advisable for expert users and\n+on a per-command basis using configuration parameters of the form\n+`git -c core.hooksPath=/dev/null ...`.\n \n core.editor::\n \tCommands such as `commit` and `tag` that let you edit\n\nbase-commit: 5b97a56fa0e7d580dc8865b73107407c9b3f0eff\n-- \ngitgitgadget\n"},{"id":"516304","messageId":"BD8FCCB1-C97D-4057-982E-93A7F8B01AB9@gmail.com","threadId":"63250","inReplyTo":"pull.1899.v2.git.1744818135435.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] docs: document core.hooksPath=/dev/null","fromName":"Lucas Seiki Oshiro","fromEmail":"lucasseikioshiro@gmail.com","sentAt":"2025-04-16T16:53:18Z","receivedAt":"2025-04-16T16:53:33Z","isPatch":true,"sender":{"key":"lucasseikioshiro@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12701580?v=4"},"body":"Hi!\n\n> +You can also disable all hooks entirely by setting `core.hooksPath`\n> +to `/dev/null`.\n\nPersonally I think it would be better to focus on the non-expert user,\nsomething like:\n\n\"\"\"\nYou can also use this variable to disable all hooks entirely by setting\nit to `/dev/null`. For non-expert users in a per-command basis it is\nadvisable to use configuration parameters of the form\n`git -c core.hooksPath=/dev/null ...`.\n\"\"\"\n\n\n"},{"id":"516328","messageId":"9e14443c-e549-46e1-9fbf-ee72800e6944@gmail.com","threadId":"63250","inReplyTo":"BD8FCCB1-C97D-4057-982E-93A7F8B01AB9@gmail.com","subject":"Re: [PATCH v2] docs: document core.hooksPath=/dev/null","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2025-04-17T00:25:28Z","receivedAt":"2025-04-17T00:25:30Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/16/2025 12:53 PM, Lucas Seiki Oshiro wrote:\n> Hi!\n> \n>> +You can also disable all hooks entirely by setting `core.hooksPath`\n>> +to `/dev/null`.\n> \n> Personally I think it would be better to focus on the non-expert user,\n\nI absolutely want this to be targeted for expert users, so users self-\nselect themselves into the risk of what happens when disabling hooks.\nThis is a \"there be dragons here\" kind of warning, implying that you\nbetter know what you're doing if you are messing with hook paths.\n\nThanks,\n-Stolee\n\n"},{"id":"516329","messageId":"aABNzj66xq5HA6gA@tapette.crustytoothpaste.net","threadId":"63250","inReplyTo":"9e14443c-e549-46e1-9fbf-ee72800e6944@gmail.com","subject":"Re: [PATCH v2] docs: document core.hooksPath=/dev/null","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-04-17T00:39:42Z","receivedAt":"2025-04-17T00:39:50Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-04-17 at 00:25:28, Derrick Stolee wrote:\n> On 4/16/2025 12:53 PM, Lucas Seiki Oshiro wrote:\n> > Hi!\n> > \n> >> +You can also disable all hooks entirely by setting `core.hooksPath`\n> >> +to `/dev/null`.\n> > \n> > Personally I think it would be better to focus on the non-expert user,\n> \n> I absolutely want this to be targeted for expert users, so users self-\n> select themselves into the risk of what happens when disabling hooks.\n> This is a \"there be dragons here\" kind of warning, implying that you\n> better know what you're doing if you are messing with hook paths.\n\nYes, I think that's the right choice.  As we've established elsewhere,\nit's easy to break things or cause data loss (e.g., by not pushing Git\nLFS objects) by disabling hooks and the user should be confident of what\nthey're doing before doing so.\n\nThat being said, I agree that in the general case we should make our\ndocumentation accessible to non-expert users because nobody is born\nknowing how to use Git and that will benefit the most people.  This just\nhappens to be an exception.\n\nI thought the text in the patch looked good to me.  I appreciate you\ngraciously pivoting approaches and documenting this, both for the\nbenefit of users and as an approach to help make sure we don't break\nthis functionality.\n-- \nbrian m. carlson (they/them)\nToronto, Ontario, CA\n"},{"id":"516330","messageId":"xmqqecxrfo8e.fsf@gitster.g","threadId":"63250","inReplyTo":"aABNzj66xq5HA6gA@tapette.crustytoothpaste.net","subject":"Re: [PATCH v2] docs: document core.hooksPath=/dev/null","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-04-17T03:42:09Z","receivedAt":"2025-04-17T03:42:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"brian m. carlson\" <sandals@crustytoothpaste.net> writes:\n\n> I thought the text in the patch looked good to me.  I appreciate you\n> graciously pivoting approaches and documenting this, both for the\n> benefit of users and as an approach to help make sure we don't break\n> this functionality.\n\nThanks, all.  I too appreciate that Derrick left no loose ends\nuntied after changing direction.\n\n"},{"id":"516347","messageId":"B60E6A23-05F6-4391-8CAC-1CAEB509E32A@gmail.com","threadId":"63250","inReplyTo":"9e14443c-e549-46e1-9fbf-ee72800e6944@gmail.com","subject":"Re: [PATCH v2] docs: document core.hooksPath=/dev/null","fromName":"Lucas Seiki Oshiro","fromEmail":"lucasseikioshiro@gmail.com","sentAt":"2025-04-17T16:02:05Z","receivedAt":"2025-04-17T16:02:22Z","isPatch":true,"sender":{"key":"lucasseikioshiro@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12701580?v=4"},"body":"\n> This is a \"there be dragons here\" kind of warning, implying that you\n> better know what you're doing if you are messing with hook paths.\n\nFair, I understand your point. The paragraph itself looks very\nclear to me!\n\nThanks!\n\n"}]}