Skip to content

Commit b66efad

Browse files
10ne1gitster
authored andcommitted
hook: show config scope in git hook list
Users running "git hook list" can see which hooks are configured but have no way to tell at which config scope (local, global, system...) each hook was defined. Store the scope from ctx->kvi->scope in the single-pass config callback, then carry it through the cache to the hook structs, so we can expose it to users via the "git hook list --show-scope" flag, which mirrors the existing git config --show-scope convention. Without the flag the output is unchanged. The scope is printed as a tab-separated prefix (like "git config --show-scope"), making it unambiguously machine-parseable even when the friendly name contains spaces. Example usage: $ git hook list --show-scope pre-commit global linter local no-leaks hook from hookdir Traditional hooks from the hookdir are unaffected by --show-scope since the config scope concept does not apply to them. Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent d8513bc commit b66efad

5 files changed

Lines changed: 63 additions & 8 deletions

File tree

Documentation/git-hook.adoc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'git hook' run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
12-
'git hook' list [-z] <hook-name>
12+
'git hook' list [-z] [--show-scope] <hook-name>
1313

1414
DESCRIPTION
1515
-----------
@@ -113,7 +113,7 @@ Any positional arguments to the hook should be passed after a
113113
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
114114
linkgit:githooks[5] for arguments hooks might expect (if any).
115115
116-
list [-z]::
116+
list [-z] [--show-scope]::
117117
Print a list of hooks which will be run on `<hook-name>` event. If no
118118
hooks are configured for that event, print a warning and return 1.
119119
Use `-z` to terminate output lines with NUL instead of newlines.
@@ -134,6 +134,12 @@ OPTIONS
134134
-z::
135135
Terminate "list" output lines with NUL instead of newlines.
136136

137+
--show-scope::
138+
For "list"; prefix each configured hook's friendly name with a
139+
tab-separated config scope (e.g. `local`, `global`, `system`),
140+
mirroring the output style of `git config --show-scope`. Traditional
141+
hooks from the hookdir are unaffected.
142+
137143
WRAPPERS
138144
--------
139145

builtin/hook.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#define BUILTIN_HOOK_RUN_USAGE \
1010
N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
1111
#define BUILTIN_HOOK_LIST_USAGE \
12-
N_("git hook list [-z] <hook-name>")
12+
N_("git hook list [-z] [--show-scope] <hook-name>")
1313

1414
static const char * const builtin_hook_usage[] = {
1515
BUILTIN_HOOK_RUN_USAGE,
@@ -33,11 +33,14 @@ static int list(int argc, const char **argv, const char *prefix,
3333
struct string_list_item *item;
3434
const char *hookname = NULL;
3535
int line_terminator = '\n';
36+
int show_scope = 0;
3637
int ret = 0;
3738

3839
struct option list_options[] = {
3940
OPT_SET_INT('z', NULL, &line_terminator,
4041
N_("use NUL as line terminator"), '\0'),
42+
OPT_BOOL(0, "show-scope", &show_scope,
43+
N_("show the config scope that defined each hook")),
4144
OPT_END(),
4245
};
4346

@@ -70,7 +73,14 @@ static int list(int argc, const char **argv, const char *prefix,
7073
printf("%s%c", _("hook from hookdir"), line_terminator);
7174
break;
7275
case HOOK_CONFIGURED:
73-
printf("%s%c", h->u.configured.friendly_name, line_terminator);
76+
if (show_scope)
77+
printf("%s\t%s%c",
78+
config_scope_name(h->u.configured.scope),
79+
h->u.configured.friendly_name,
80+
line_terminator);
81+
else
82+
printf("%s%c", h->u.configured.friendly_name,
83+
line_terminator);
7484
break;
7585
default:
7686
BUG("unknown hook kind");

hook.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,11 @@ static void list_hooks_add_default(struct repository *r, const char *hookname,
110110

111111
/*
112112
* Cache entry stored as the .util pointer of string_list items inside the
113-
* hook config cache. For now carries only the command for the hook. Next
114-
* commits will add more data.
113+
* hook config cache.
115114
*/
116115
struct hook_config_cache_entry {
117116
char *command;
117+
enum config_scope scope;
118118
};
119119

120120
/*
@@ -131,7 +131,7 @@ struct hook_all_config_cb {
131131

132132
/* repo_config() callback that collects all hook.* configuration in one pass. */
133133
static int hook_config_lookup_all(const char *key, const char *value,
134-
const struct config_context *ctx UNUSED,
134+
const struct config_context *ctx,
135135
void *cb_data)
136136
{
137137
struct hook_all_config_cb *data = cb_data;
@@ -168,7 +168,19 @@ static int hook_config_lookup_all(const char *key, const char *value,
168168

169169
/* Re-insert if necessary to preserve last-seen order. */
170170
unsorted_string_list_remove(hooks, hook_name, 0);
171-
string_list_append(hooks, hook_name);
171+
172+
if (!ctx->kvi)
173+
BUG("hook config callback called without key-value info");
174+
175+
/*
176+
* Stash the config scope in the util pointer for
177+
* later retrieval in build_hook_config_map(). This
178+
* intermediate struct is transient and never leaves
179+
* that function, so we pack the enum value into the
180+
* pointer rather than heap-allocating a wrapper.
181+
*/
182+
string_list_append(hooks, hook_name)->util =
183+
(void *)(uintptr_t)ctx->kvi->scope;
172184
}
173185
} else if (!strcmp(subkey, "command")) {
174186
/* Store command overwriting the old value */
@@ -246,6 +258,8 @@ static void build_hook_config_map(struct repository *r, struct strmap *cache)
246258

247259
for (size_t i = 0; i < hook_names->nr; i++) {
248260
const char *hname = hook_names->items[i].string;
261+
enum config_scope scope =
262+
(enum config_scope)(uintptr_t)hook_names->items[i].util;
249263
struct hook_config_cache_entry *entry;
250264
char *command;
251265

@@ -263,6 +277,7 @@ static void build_hook_config_map(struct repository *r, struct strmap *cache)
263277
/* util stores a cache entry; owned by the cache. */
264278
CALLOC_ARRAY(entry, 1);
265279
entry->command = xstrdup(command);
280+
entry->scope = scope;
266281
string_list_append(hooks, hname)->util = entry;
267282
}
268283

@@ -344,6 +359,7 @@ static void list_hooks_add_configured(struct repository *r,
344359
hook->kind = HOOK_CONFIGURED;
345360
hook->u.configured.friendly_name = xstrdup(friendly_name);
346361
hook->u.configured.command = xstrdup(entry->command);
362+
hook->u.configured.scope = entry->scope;
347363

348364
string_list_append(list, friendly_name)->util = hook;
349365
}

hook.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#ifndef HOOK_H
22
#define HOOK_H
3+
#include "config.h"
34
#include "run-command.h"
45
#include "string-list.h"
56
#include "strmap.h"
@@ -29,6 +30,7 @@ struct hook {
2930
struct {
3031
const char *friendly_name;
3132
const char *command;
33+
enum config_scope scope;
3234
} configured;
3335
} u;
3436

t/t1800-hook.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,27 @@ test_expect_success 'configured hooks run before hookdir hook' '
408408
test_cmp expected actual
409409
'
410410

411+
test_expect_success 'git hook list --show-scope shows config scope' '
412+
setup_hookdir &&
413+
test_config_global hook.global-hook.command "echo global" &&
414+
test_config_global hook.global-hook.event pre-commit --add &&
415+
test_config hook.local-hook.command "echo local" &&
416+
test_config hook.local-hook.event pre-commit --add &&
417+
418+
cat >expected <<-\EOF &&
419+
global global-hook
420+
local local-hook
421+
hook from hookdir
422+
EOF
423+
git hook list --show-scope pre-commit >actual &&
424+
test_cmp expected actual &&
425+
426+
# without --show-scope the scope must not appear
427+
git hook list pre-commit >actual &&
428+
test_grep ! "^global " actual &&
429+
test_grep ! "^local " actual
430+
'
431+
411432
test_expect_success 'git hook run a hook with a bad shebang' '
412433
test_when_finished "rm -rf bad-hooks" &&
413434
mkdir bad-hooks &&

0 commit comments

Comments
 (0)