@@ -16,6 +16,7 @@ static int list(int argc, const char **argv, const char *prefix)
struct list_head *head, *pos;
struct hook *item;
struct strbuf hookname = STRBUF_INIT;
+ struct strbuf hookdir_annotation = STRBUF_INIT;
struct option list_options[] = {
OPT_END(),
@@ -42,10 +43,17 @@ static int list(int argc, const char **argv, const char *prefix)
list_for_each(pos, head) {
item = list_entry(pos, struct hook, list);
- if (item)
- printf("%s: %s\n",
- config_scope_name(item->origin),
- item->command.buf);
+ if (item) {
+ /* Don't translate 'hookdir' - it matches the config */
+ printf("%s: %s%s\n",
+ (item->from_hookdir
+ ? "hookdir"
+ : config_scope_name(item->origin)),
+ item->command.buf,
+ (item->from_hookdir
+ ? hookdir_annotation.buf
+ : ""));
+ }
}
clear_hook_list(head);
@@ -2,6 +2,7 @@
#include "hook.h"
#include "config.h"
+#include "run-command.h"
void free_hook(struct hook *ptr)
{
@@ -34,6 +35,7 @@ static void append_or_move_hook(struct list_head *head, const char *command)
to_add = xmalloc(sizeof(struct hook));
strbuf_init(&to_add->command, 0);
strbuf_addstr(&to_add->command, command);
+ to_add->from_hookdir = 0;
}
/* re-set the scope so we show where an override was specified */
@@ -100,6 +102,7 @@ struct list_head* hook_list(const struct strbuf* hookname)
struct strbuf hook_key = STRBUF_INIT;
struct list_head *hook_head = xmalloc(sizeof(struct list_head));
struct hook_config_cb cb_data = { &hook_key, hook_head };
+ const char *legacy_hook_path = NULL;
INIT_LIST_HEAD(hook_head);
@@ -110,6 +113,18 @@ struct list_head* hook_list(const struct strbuf* hookname)
git_config(hook_config_lookup, (void*)&cb_data);
+ if (have_git_dir())
+ legacy_hook_path = find_hook(hookname->buf);
+
+ /* Unconditionally add legacy hook, but annotate it. */
+ if (legacy_hook_path) {
+ struct hook *legacy_hook;
+
+ append_or_move_hook(hook_head, absolute_path(legacy_hook_path));
+ legacy_hook = list_entry(hook_head->prev, struct hook, list);
+ legacy_hook->from_hookdir = 1;
+ }
+
strbuf_release(&hook_key);
return hook_head;
}
@@ -12,6 +12,7 @@ struct hook
enum config_scope origin;
/* The literal command to run. */
struct strbuf command;
+ int from_hookdir;
};
/*
@@ -23,6 +23,14 @@ setup_hookcmd () {
test_config_global hookcmd.abc.command "/path/abc" --add
}
+setup_hookdir () {
+ mkdir .git/hooks
+ write_script .git/hooks/pre-commit <<-EOF
+ echo \"Legacy Hook\"
+ EOF
+ test_when_finished rm -rf .git/hooks
+}
+
test_expect_success 'git hook rejects commands without a mode' '
test_must_fail git hook pre-commit
'
@@ -85,4 +93,15 @@ test_expect_success 'git hook list reorders on duplicate commands' '
test_cmp expected actual
'
+test_expect_success 'git hook list shows hooks from the hookdir' '
+ setup_hookdir &&
+
+ cat >expected <<-EOF &&
+ hookdir: $(pwd)/.git/hooks/pre-commit
+ EOF
+
+ git hook list pre-commit >actual &&
+ test_cmp expected actual
+'
+
test_done
Historically, hooks are declared by placing an executable into $GIT_DIR/hooks/$HOOKNAME (or $HOOKDIR/$HOOKNAME). Although hooks taken from the config are more featureful than hooks placed in the $HOOKDIR, those hooks should not stop working for users who already have them. Legacy hooks should be run directly, not in shell. We know that they are a path to an executable, not a oneliner script - and running them directly takes care of path quoting concerns for us for free. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> --- Notes: Newly split into its own commit since v4, and taking place much sooner. An unfortunate side effect of adding this support *before* the hook.runHookDir support is that the labels on the list are not clear - because we aren't yet flagging which hooks are from the hookdir versus the config. I suppose we could move the addition of that field to the struct hook up to this patch, but it didn't make a lot of sense to me to do it just for cosmetic purposes. builtin/hook.c | 16 ++++++++++++---- hook.c | 15 +++++++++++++++ hook.h | 1 + t/t1360-config-based-hooks.sh | 19 +++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-)