@@ -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
-------
@@ -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);
}
@@ -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
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(-)