aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Ratiu <adrian.ratiu@collabora.com>2026-02-19 00:23:52 +0200
committerJunio C Hamano <gitster@pobox.com>2026-02-19 13:24:57 -0800
commit4b12cd3ae3acbc819189758d09f9c983bde16040 (patch)
tree7bbe9a0500548f5285e87329c27298bc10b4218b
parentb51e238ddf896439d2746b883d892f8f9bba649f (diff)
downloadgit-4b12cd3ae3acbc819189758d09f9c983bde16040.tar.xz
hook: add -z option to "git hook list"
Add a NUL-terminate mode to git hook list, just in case hooks are configured with weird characters like newlines in their names. 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>
-rw-r--r--Documentation/git-hook.adoc8
-rw-r--r--builtin/hook.c9
-rwxr-xr-xt/t1800-hook.sh13
3 files changed, 25 insertions, 5 deletions
diff --git a/Documentation/git-hook.adoc b/Documentation/git-hook.adoc
index 7e4259e4f0..12d2701b52 100644
--- a/Documentation/git-hook.adoc
+++ b/Documentation/git-hook.adoc
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git hook' run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
-'git hook' list <hook-name>
+'git hook' list [-z] <hook-name>
DESCRIPTION
-----------
@@ -113,9 +113,10 @@ Any positional arguments to the hook should be passed after a
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
linkgit:githooks[5] for arguments hooks might expect (if any).
-list::
+list [-z]::
Print a list of hooks which will be run on `<hook-name>` event. If no
hooks are configured for that event, print a warning and return 1.
+ Use `-z` to terminate output lines with NUL instead of newlines.
OPTIONS
-------
@@ -130,6 +131,9 @@ OPTIONS
tools that want to do a blind one-shot run of a hook that may
or may not be present.
+-z::
+ Terminate "list" output lines with NUL instead of newlines.
+
WRAPPERS
--------
diff --git a/builtin/hook.c b/builtin/hook.c
index e151bb2cd1..83020dfb4f 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -11,7 +11,7 @@
#define BUILTIN_HOOK_RUN_USAGE \
N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
#define BUILTIN_HOOK_LIST_USAGE \
- N_("git hook list <hook-name>")
+ N_("git hook list [-z] <hook-name>")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -34,9 +34,12 @@ static int list(int argc, const char **argv, const char *prefix,
struct string_list *head;
struct string_list_item *item;
const char *hookname = NULL;
+ int line_terminator = '\n';
int ret = 0;
struct option list_options[] = {
+ OPT_SET_INT('z', NULL, &line_terminator,
+ N_("use NUL as line terminator"), '\0'),
OPT_END(),
};
@@ -66,10 +69,10 @@ static int list(int argc, const char **argv, const char *prefix,
switch (h->kind) {
case HOOK_TRADITIONAL:
- printf("%s\n", _("hook from hookdir"));
+ printf("%s%c", _("hook from hookdir"), line_terminator);
break;
case HOOK_CONFIGURED:
- printf("%s\n", h->u.configured.friendly_name);
+ printf("%s%c", h->u.configured.friendly_name, line_terminator);
break;
default:
BUG("unknown hook kind");
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index e58151e8f8..b1583e9ef9 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -61,6 +61,19 @@ test_expect_success 'git hook list: configured hook' '
test_cmp expect actual
'
+test_expect_success 'git hook list: -z shows NUL-terminated output' '
+ test_hook test-hook <<-EOF &&
+ echo Test hook
+ EOF
+ test_config hook.myhook.command "echo Hello" &&
+ test_config hook.myhook.event test-hook --add &&
+
+ printf "myhookQhook from hookdirQ" >expect &&
+ git hook list -z test-hook >actual.raw &&
+ nul_to_q <actual.raw >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'git hook run: nonexistent hook' '
cat >stderr.expect <<-\EOF &&
error: cannot find a hook named test-hook