diff --git a/Documentation/config.txt b/Documentation/config.txt index 1ac0ae6adb..5642defb8c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -351,6 +351,9 @@ advice.*:: addEmbeddedRepo:: Advice on what to do when you've accidentally added one git repo inside of another. + ignoredHook:: + Advice shown if an hook is ignored because the hook is not + set as executable. -- core.fileMode:: diff --git a/advice.c b/advice.c index d81e1cb742..c6169bcb52 100644 --- a/advice.c +++ b/advice.c @@ -17,6 +17,7 @@ int advice_set_upstream_failure = 1; int advice_object_name_warning = 1; int advice_rm_hints = 1; int advice_add_embedded_repo = 1; +int advice_ignored_hook = 1; static struct { const char *name; @@ -38,6 +39,7 @@ static struct { { "objectnamewarning", &advice_object_name_warning }, { "rmhints", &advice_rm_hints }, { "addembeddedrepo", &advice_add_embedded_repo }, + { "ignoredhook", &advice_ignored_hook }, /* make this an alias for backward compatibility */ { "pushnonfastforward", &advice_push_update_rejected } diff --git a/advice.h b/advice.h index c84a44531c..f525d6f89c 100644 --- a/advice.h +++ b/advice.h @@ -19,6 +19,7 @@ extern int advice_set_upstream_failure; extern int advice_object_name_warning; extern int advice_rm_hints; extern int advice_add_embedded_repo; +extern int advice_ignored_hook; int git_default_advice_config(const char *var, const char *value); __attribute__((format (printf, 1, 2))) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d934417475..a331ccc556 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2350,6 +2350,7 @@ _git_config () advice.rmHints advice.statusHints advice.statusUoption + advice.ignoredHook alias. am.keepcr am.threeWay diff --git a/run-command.c b/run-command.c index 014b2165b5..31fc5ea86e 100644 --- a/run-command.c +++ b/run-command.c @@ -5,6 +5,7 @@ #include "argv-array.h" #include "thread-utils.h" #include "strbuf.h" +#include "string-list.h" void child_process_init(struct child_process *child) { @@ -1169,11 +1170,28 @@ const char *find_hook(const char *name) strbuf_reset(&path); strbuf_git_path(&path, "hooks/%s", name); if (access(path.buf, X_OK) < 0) { + int err = errno; + #ifdef STRIP_EXTENSION strbuf_addstr(&path, STRIP_EXTENSION); if (access(path.buf, X_OK) >= 0) return path.buf; + if (errno == EACCES) + err = errno; #endif + + if (err == EACCES && advice_ignored_hook) { + static struct string_list advise_given = STRING_LIST_INIT_DUP; + + if (!string_list_lookup(&advise_given, name)) { + string_list_insert(&advise_given, name); + advise(_("The '%s' hook was ignored because " + "it's not set as executable.\n" + "You can disable this warning with " + "`git config advice.ignoredHook false`."), + path.buf); + } + } return NULL; } return path.buf; diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh new file mode 100755 index 0000000000..634fb7f23a --- /dev/null +++ b/t/t7520-ignored-hook-warning.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +test_description='ignored hook warning' + +. ./test-lib.sh + +test_expect_success setup ' + hookdir="$(git rev-parse --git-dir)/hooks" && + hook="$hookdir/pre-commit" && + mkdir -p "$hookdir" && + write_script "$hook" <<-\EOF + exit 0 + EOF +' + +test_expect_success 'no warning if hook is not ignored' ' + git commit --allow-empty -m "more" 2>message && + test_i18ngrep ! -e "hook was ignored" message +' + +test_expect_success POSIXPERM 'warning if hook is ignored' ' + chmod -x "$hook" && + git commit --allow-empty -m "even more" 2>message && + test_i18ngrep -e "hook was ignored" message +' + +test_expect_success POSIXPERM 'no warning if advice.ignoredHook set to false' ' + test_config advice.ignoredHook false && + chmod -x "$hook" && + git commit --allow-empty -m "even more" 2>message && + test_i18ngrep ! -e "hook was ignored" message +' + +test_expect_success 'no warning if unset advice.ignoredHook and hook removed' ' + rm -f "$hook" && + test_unconfig advice.ignoredHook && + git commit --allow-empty -m "even more" 2>message && + test_i18ngrep ! -e "hook was ignored" message +' + +test_done