hook: allow event = "" to overwrite previous values

Add the ability for empty events to clear previously set multivalue
variables, so the newly added "hook.*.event" behave like the other
multivalued keys.

Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Adrian Ratiu
2026-02-19 00:23:50 +02:00
committed by Junio C Hamano
parent 1ecce722cd
commit d084fa2a91
3 changed files with 34 additions and 11 deletions

View File

@@ -12,7 +12,9 @@ hook.<name>.event::
linkgit:githooks[5] for a complete list of hook events.) On the
specified event, the associated `hook.<name>.command` is executed.
This is a multi-valued key. To run `hook.<name>` on multiple
events, specify the key more than once. See linkgit:git-hook[1].
events, specify the key more than once. An empty value resets
the list of events, clearing any previously defined events for
`hook.<name>`. See linkgit:git-hook[1].
hook.<name>.enabled::
Whether the hook `hook.<name>` is enabled. Defaults to `true`.

29
hook.c
View File

@@ -147,18 +147,27 @@ static int hook_config_lookup_all(const char *key, const char *value,
hook_name = xmemdupz(name, name_len);
if (!strcmp(subkey, "event")) {
struct string_list *hooks =
strmap_get(&data->event_hooks, value);
if (!*value) {
/* Empty values reset previous events for this hook. */
struct hashmap_iter iter;
struct strmap_entry *e;
if (!hooks) {
hooks = xcalloc(1, sizeof(*hooks));
string_list_init_dup(hooks);
strmap_put(&data->event_hooks, value, hooks);
strmap_for_each_entry(&data->event_hooks, &iter, e)
unsorted_string_list_remove(e->value, hook_name);
} else {
struct string_list *hooks =
strmap_get(&data->event_hooks, value);
if (!hooks) {
hooks = xcalloc(1, sizeof(*hooks));
string_list_init_dup(hooks);
strmap_put(&data->event_hooks, value, hooks);
}
/* Re-insert if necessary to preserve last-seen order. */
unsorted_string_list_remove(hooks, hook_name);
string_list_append(hooks, hook_name);
}
/* Re-insert if necessary to preserve last-seen order. */
unsorted_string_list_remove(hooks, hook_name);
string_list_append(hooks, hook_name);
} else if (!strcmp(subkey, "command")) {
/* Store command overwriting the old value */
char *old = strmap_put(&data->commands, hook_name,

View File

@@ -226,6 +226,18 @@ test_expect_success 'git hook list reorders on duplicate event declarations' '
test_cmp expected actual
'
test_expect_success 'git hook list: empty event value resets events' '
setup_hooks &&
# ghi is configured for pre-commit; reset it with an empty value
test_config hook.ghi.event "" --add &&
# only def should remain for pre-commit
echo "def" >expected &&
git hook list pre-commit >actual &&
test_cmp expected actual
'
test_expect_success 'hook can be configured for multiple events' '
setup_hooks &&