git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 5/6] hook: remove prior hook with '---'

From
Emily Shaffer <emilyshaffer@google.com>
Date
Dec 10, 2019, 02:33 UTC
Message-ID
<20191210023335.49987-6-emilyshaffer@google.com>
In-Reply-To
<20191210023335.49987-1-emilyshaffer@google.com>

It's possible a user may want to run a hook for nearly every repo, except for one. Rather than requiring the user to specify the hook locally in all but one repo, teach 'git hook' how to interpret config lines intended to remove hooks specified earlier during the config parse. This means a user can specify such a hook at the system or global level and override it at the local level.

For example:
$ grep -A2 "\[hook\]" ~/.gitconfig
[hook]
        pre-commit = 001:~/test.sh
        pre-commit = 999:~/baz.sh
$ grep -A2 "\[hook\]" ~/git/.git/config
[hook]
        pre-commit = 900:~/bar.sh
        pre-commit = ---:~/baz.sh
$ ./bin-wrappers/git hook --list pre-commit
001     global  ~/test.sh
900     repo    ~/bar.sh
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-hook.txt    |  8 ++++++++
 hook.c                        | 15 ++++++++++-----
 t/t1360-config-based-hooks.sh | 13 +++++++++++++
 3 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index 0f7115f826..b4a992d43f 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -28,6 +28,14 @@ The order number of a hook can be changed at a more local scope, e.g.:
 When the order number is respecified this way, the previously specified hook
 configuration is overridden.
 
+A hook specified at a more global scope can be removed by specifying "---"
+instead of an order number, e.g.:
+
+  git config --add --global hook.pre-commit "001:/foo.sh"
+  git config --add --local hook.pre-commit "---:/foo.sh"
+
+When the hook is removed in this way, `/foo.sh` will not be run at all.
+
 OPTIONS
 -------
 
diff --git a/hook.c b/hook.c
index a7dcd18a2e..e7afa140c8 100644
--- a/hook.c
+++ b/hook.c
@@ -49,9 +49,14 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook
 		// TODO this is bad - open to overflows
 		char command[256];
 		int added = 0;
-		if (!sscanf(value, "%d:%s", &order, command))
-			die(_("hook config '%s' doesn't match expected format"),
-			    value);
+		int remove = 0;
+		if (!sscanf(value, "%d:%s", &order, command)) {
+			if (sscanf(value, "---:%s", command))
+				remove = 1;
+			else
+				die(_("hook config '%s' doesn't match expected format"),
+				    value);
+		}
 
 		list_for_each_safe(pos, p, &hook_head) {
 			item = list_entry(pos, struct hook, list);
@@ -60,7 +65,7 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook
 			 * the new entry should go just before the first entry
 			 * which has a higher order number than it.
 			 */
-			if (item->order > order && !added) {
+			if (item->order > order && !added && !remove) {
 				emplace_hook(pos, order, command);
 				added = 1;
 			}
@@ -73,7 +78,7 @@ static int check_config_for_hooks(const char *var, const char *value, void *hook
 				remove_hook(pos);
 		}
 
-		if (!added)
+		if (!added && !remove)
 			emplace_hook(pos, order, command);
 	}
 
diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh
index 1af43ef18d..66e70ae222 100755
--- a/t/t1360-config-based-hooks.sh
+++ b/t/t1360-config-based-hooks.sh
@@ -61,4 +61,17 @@ test_expect_success 'adding a command with a different number reorders list' '
 	test_cmp expected actual
 '
 
+test_expect_success 'remove a command with "---:/path/to/cmd"' '
+	cat >expected <<-\EOF &&
+	010	repo	/path/abc
+	050	repo	/path/def
+	100	repo	/path/ghi
+	990	repo	/path/rst
+	EOF
+
+	git config --add --local hook.pre-commit "---:/path/uvw" &&
+	git hook --list pre-commit >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.24.0.393.g34dc348eaf-goog
Previous: Junio C HamanoNext: Emily Shaffer
Message 13 of 19 in “configuration-based hook management”
  1. 0/6 configuration-based hook managementEmily Shaffer, Dec 10, 2019
  2. 1/6 hook: scaffolding for git-hook subcommandEmily Shaffer, Dec 10, 2019
  3. Bert WesargDec 12, 2019
  4. SZEDER GáborDec 12, 2019
  5. 2/6 config: add string mapping for enum config_scopeEmily Shaffer, Dec 10, 2019
  6. Philip OakleyDec 10, 2019
  7. Philip OakleyDec 10, 2019
  8. 3/6 hook: add --list modeEmily Shaffer, Dec 10, 2019
  9. Bert WesargDec 12, 2019
  10. SZEDER GáborDec 12, 2019
  11. 4/6 hook: support reordering of hook listEmily Shaffer, Dec 10, 2019
  12. Junio C HamanoDec 11, 2019
  13. 5/6 hook: remove prior hook with '---'Emily Shaffer, Dec 10, 2019
  14. 6/6 hook: teach --porcelain modeEmily Shaffer, Dec 10, 2019
  15. Junio C HamanoDec 11, 2019
  16. Emily ShafferDec 11, 2019
  17. Junio C HamanoDec 11, 2019
  18. Emily ShafferDec 11, 2019
  19. Junio C HamanoDec 11, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.