{"thread":{"id":"42150","subject":"[PATCH v4 0/4] githooks.txt improvements + core.hooksDirectory","startedAt":"2016-04-26T18:13:18Z","lastAt":"2016-05-04T23:26:48Z","messageCount":20,"participants":["Ævar Arnfjörð Bjarmason","Junio C Hamano"],"isPatch":true,"patchVersion":4,"patchTotal":4},"messages":[{"id":"284558","messageId":"1461694402-9629-1-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":null,"subject":"[PATCH v4 0/4] githooks.txt improvements + core.hooksDirectory","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-04-26T18:13:18Z","receivedAt":"2016-04-26T18:13:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In this version of the series I've hopefully addressed all the\ncomments that came up on the list after the last one, and a few fixes\nI noticed myself, e.g. a couple of grammar errors and a broken\nasciidoc syntax.\n\nI've combined both the githooks.txt documentation improvements and the\ncore.hooksDirectory patch into one series. Although they're logically\ndifferent things I think it makes more sense to combine them for ease\nof reading, since the core.hooksDirectory documentation refers to some\ndocumentation I fixed earlier in the series.\n\nÆvar Arnfjörð Bjarmason (4):\n  githooks.txt: Improve the intro section\n  githooks.txt: Amend dangerous advice about 'update' hook ACL\n  githooks.txt: Minor improvements to the grammar & phrasing\n  hooks: Add ability to specify where the hook directory is\n\n Documentation/config.txt     | 18 +++++++++++\n Documentation/git-init.txt   |  7 ++++-\n Documentation/githooks.txt   | 74 ++++++++++++++++++++++++++------------------\n cache.h                      |  1 +\n config.c                     |  3 ++\n environment.c                |  1 +\n run-command.c                |  5 ++-\n t/t1350-config-hooks-path.sh | 31 +++++++++++++++++++\n 8 files changed, 108 insertions(+), 32 deletions(-)\n create mode 100755 t/t1350-config-hooks-path.sh\n\n-- \n2.1.3\n"},{"id":"284560","messageId":"1461694402-9629-2-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1461694402-9629-1-git-send-email-avarab@gmail.com","subject":"[PATCH v4 1/4] githooks.txt: Improve the intro section","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-04-26T18:13:19Z","receivedAt":"2016-04-26T18:13:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the documentation so that:\n\n * We don't talk about \"little scripts\". Hooks can be as big as you\n   want, and don't have to be scripts, just call them \"programs\".\n\n * We note what happens with chdir() before a hook is called, nothing\n   documented this explicitly, but the current behavior is\n   predictable. It helps a lot to know what directory these hooks will\n   be executed from.\n\n * We don't make claims about the example hooks which may not be true\n   depending on the configuration of 'init.templateDir'. Clarify that\n   we're talking about the default settings of git-init in those cases,\n   and move some of this documentation into git-init's documentation\n   about the default templates.\n\n * We briefly note in the intro that hooks can get their arguments in\n   various different ways, and that how exactly is described below for\n   each hook.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-init.txt |  7 ++++++-\n Documentation/githooks.txt | 32 ++++++++++++++++++++------------\n 2 files changed, 26 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-init.txt b/Documentation/git-init.txt\nindex 8174d27..6364e5d 100644\n--- a/Documentation/git-init.txt\n+++ b/Documentation/git-init.txt\n@@ -130,7 +130,12 @@ The template directory will be one of the following (in order):\n  - the default template directory: `/usr/share/git-core/templates`.\n \n The default template directory includes some directory structure, suggested\n-\"exclude patterns\" (see linkgit:gitignore[5]), and sample hook files (see linkgit:githooks[5]).\n+\"exclude patterns\" (see linkgit:gitignore[5]), and sample hook files.\n+\n+The sample hooks are all disabled by default, To enable one of the\n+sample hooks rename it by removing its `.sample` suffix.\n+\n+See linkgit:githooks[5] for more general info on hook execution.\n \n EXAMPLES\n --------\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex a2f59b1..7660b95 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -13,18 +13,26 @@ $GIT_DIR/hooks/*\n DESCRIPTION\n -----------\n \n-Hooks are little scripts you can place in `$GIT_DIR/hooks`\n-directory to trigger action at certain points.  When\n-'git init' is run, a handful of example hooks are copied into the\n-`hooks` directory of the new repository, but by default they are\n-all disabled.  To enable a hook, rename it by removing its `.sample`\n-suffix.\n-\n-NOTE: It is also a requirement for a given hook to be executable.\n-However - in a freshly initialized repository - the `.sample` files are\n-executable by default.\n-\n-This document describes the currently defined hooks.\n+Hooks are programs you can place in the `$GIT_DIR/hooks` directory to\n+trigger actions at certain points in git's execution. Hooks that don't\n+have the executable bit set are ignored.\n+\n+When a hook is invoked, it is run at the root of the working tree in a\n+non-bare repository, or in the $GIT_DIR in a bare\n+repository. I.e. hooks don't need to worry about the user's current\n+working directory.\n+\n+Hooks can get their arguments via the environment, command-line\n+arguments, and stdin. See the documentation for each hook below for\n+details.\n+\n+When 'git init' is run it may, depending on its configuration, copy\n+hooks to the new repository, see the the \"TEMPLATE DIRECTORY\" section\n+in linkgit:git-init[1] for details. When the rest of this document\n+refers to \"default hooks\" it's talking about the default template\n+shipped with Git.\n+\n+The currently supported hooks are described below.\n \n HOOKS\n -----\n-- \n2.1.3\n"},{"id":"284559","messageId":"1461694402-9629-3-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1461694402-9629-1-git-send-email-avarab@gmail.com","subject":"[PATCH v4 2/4] githooks.txt: Amend dangerous advice about 'update' hook ACL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-04-26T18:13:20Z","receivedAt":"2016-04-26T18:13:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Any ACL you implement via an 'update' hook isn't actual access control\nif the user has login access to the machine running git, because they\ncan trivially just built their own git version which doesn't run the\nhook.\n\nChange the documentation to take this dangerous edge case into account,\nand remove the mention of the advice originating on the mailing list,\nthe users reading this don't care where the idea came up.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/githooks.txt | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 7660b95..9051584 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -275,9 +275,11 @@ does not know the entire set of branches, so it would end up\n firing one e-mail per ref when used naively, though.  The\n <<post-receive,'post-receive'>> hook is more suited to that.\n \n-Another use suggested on the mailing list is to use this hook to\n-implement access control which is finer grained than the one\n-based on filesystem group.\n+In an environment that restricts the users' access only to git\n+commands over the wire, this hook can be used to implement access\n+control without relying on filesystem ownership and group\n+membership. See linkgit:git-shell[1] for how you might use the login\n+shell to restrict the user's access to only git commands.\n \n Both standard output and standard error output are forwarded to\n 'git send-pack' on the other end, so you can simply `echo` messages\n-- \n2.1.3\n"},{"id":"284561","messageId":"1461694402-9629-4-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1461694402-9629-1-git-send-email-avarab@gmail.com","subject":"[PATCH v4 3/4] githooks.txt: Minor improvements to the grammar & phrasing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-04-26T18:13:21Z","receivedAt":"2016-04-26T18:13:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change:\n\n * Sentences that needed \"the\" or \"a\" to either add those or change them\n   so they don't need them.\n\n * The little tangent about \"You can use this to do X (if your project\n   wants to do X)\" can just be shortened to \"e.g. if you want to do X\".\n\n * s/parameter/parameters/ when the plural made more sense.\n\nMost of this goes all the way back to the initial introduction of\nhooks.txt in v0.99.5-76-g6d35cc7 by Junio.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/githooks.txt | 32 ++++++++++++++++----------------\n 1 file changed, 16 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 9051584..a214284 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -40,15 +40,15 @@ HOOKS\n applypatch-msg\n ~~~~~~~~~~~~~~\n \n-This hook is invoked by 'git am' script.  It takes a single\n+This hook is invoked by 'git am'.  It takes a single\n parameter, the name of the file that holds the proposed commit\n-log message.  Exiting with non-zero status causes\n-'git am' to abort before applying the patch.\n+log message.  Exiting with a non-zero status causes 'git am' to abort\n+before applying the patch.\n \n The hook is allowed to edit the message file in place, and can\n be used to normalize the message into some project standard\n-format (if the project has one). It can also be used to refuse\n-the commit after inspecting the message file.\n+format. It can also be used to refuse the commit after inspecting\n+the message file.\n \n The default 'applypatch-msg' hook, when enabled, runs the\n 'commit-msg' hook, if the latter is enabled.\n@@ -81,10 +81,10 @@ pre-commit\n ~~~~~~~~~~\n \n This hook is invoked by 'git commit', and can be bypassed\n-with `--no-verify` option.  It takes no parameter, and is\n+with the `--no-verify` option.  It takes no parameters, and is\n invoked before obtaining the proposed commit log message and\n-making a commit.  Exiting with non-zero status from this script\n-causes the 'git commit' to abort.\n+making a commit.  Exiting with a non-zero status from this script\n+causes the 'git commit' command to abort before creating a commit.\n \n The default 'pre-commit' hook, when enabled, catches introduction\n of lines with trailing whitespaces and aborts the commit when\n@@ -123,15 +123,15 @@ commit-msg\n ~~~~~~~~~~\n \n This hook is invoked by 'git commit', and can be bypassed\n-with `--no-verify` option.  It takes a single parameter, the\n+with the `--no-verify` option.  It takes a single parameter, the\n name of the file that holds the proposed commit log message.\n-Exiting with non-zero status causes the 'git commit' to\n+Exiting with a non-zero status causes the 'git commit' to\n abort.\n \n-The hook is allowed to edit the message file in place, and can\n-be used to normalize the message into some project standard\n-format (if the project has one). It can also be used to refuse\n-the commit after inspecting the message file.\n+The hook is allowed to edit the message file in place, and can be used\n+to normalize the message into some project standard format. It\n+can also be used to refuse the commit after inspecting the message\n+file.\n \n The default 'commit-msg' hook, when enabled, detects duplicate\n \"Signed-off-by\" lines, and aborts the commit if one is found.\n@@ -139,8 +139,8 @@ The default 'commit-msg' hook, when enabled, detects duplicate\n post-commit\n ~~~~~~~~~~~\n \n-This hook is invoked by 'git commit'.  It takes no\n-parameter, and is invoked after a commit is made.\n+This hook is invoked by 'git commit'. It takes no parameters, and is\n+invoked after a commit is made.\n \n This hook is meant primarily for notification, and cannot affect\n the outcome of 'git commit'.\n-- \n2.1.3\n"},{"id":"284562","messageId":"1461694402-9629-5-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1461694402-9629-1-git-send-email-avarab@gmail.com","subject":"[PATCH v4 4/4] hooks: Add ability to specify where the hook directory is","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-04-26T18:13:22Z","receivedAt":"2016-04-26T18:13:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the hardcoded lookup for .git/hooks/* to optionally lookup in\n$(git config core.hooksPath)/* instead.\n\nThis is essentially a more intrusive version of the git-init ability to\nspecify hooks on init time via init templates.\n\nThe difference between that facility and this feature is that this can\nbe set up after the fact via e.g. ~/.gitconfig or /etc/gitconfig to\napply for all your personal repositories, or all repositories on the\nsystem.\n\nI plan on using this on a centralized Git server where users can create\narbitrary repositories under /gitroot, but I'd like to manage all the\nhooks that should be run centrally via a unified dispatch mechanism.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt     | 18 ++++++++++++++++++\n Documentation/githooks.txt   | 12 ++++++++----\n cache.h                      |  1 +\n config.c                     |  3 +++\n environment.c                |  1 +\n run-command.c                |  5 ++++-\n t/t1350-config-hooks-path.sh | 31 +++++++++++++++++++++++++++++++\n 7 files changed, 66 insertions(+), 5 deletions(-)\n create mode 100755 t/t1350-config-hooks-path.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 42d2b50..c007b12 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -618,6 +618,24 @@ core.attributesFile::\n \t$XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not\n \tset or empty, $HOME/.config/git/attributes is used instead.\n \n+core.hooksPath::\n+\tBy default Git will look for your hooks in the\n+\t'$GIT_DIR/hooks' directory. Set this to different path,\n+\te.g. '/etc/git/hooks', and Git will try to find your hooks in\n+\tthat directory, e.g. '/etc/git/hooks/pre-receive' instead of\n+\tin '$GIT_DIR/hooks/pre-receive'.\n++\n+The path can either be absolute or relative. When specifying a\n+relative path see the discussion in the \"DESCRIPTION\" section of\n+linkgit:githooks[5] for what the relative relative path will be\n+relative to.\n++\n+This configuration is useful in cases where you'd like to\n+e.g. centrally configure your Git hooks instead of configuring them on\n+a per-repository basis, or as a more flexible and centralized\n+alterantive to having an `init.templateDir` where you've changed the\n+'hooks' directory.\n+\n core.editor::\n \tCommands such as `commit` and `tag` that lets you edit\n \tmessages by launching an editor uses the value of this\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex a214284..97ae78d 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -7,15 +7,19 @@ githooks - Hooks used by Git\n \n SYNOPSIS\n --------\n-$GIT_DIR/hooks/*\n+$GIT_DIR/hooks/* (or \\`git config core.hooksPath`/*)\n \n \n DESCRIPTION\n -----------\n \n-Hooks are programs you can place in the `$GIT_DIR/hooks` directory to\n-trigger actions at certain points in git's execution. Hooks that don't\n-have the executable bit set are ignored.\n+Hooks are programs you can place in a hooks directory to trigger\n+actions at certain points in git's execution. Hooks that don't have\n+the executable bit set are ignored.\n+\n+By default the hooks directory is `$GIT_DIR/hooks`, but that can be\n+changed via the `core.hooksPath` configuration variable (see\n+linkgit:git-config[1]).\n \n When a hook is invoked, it is run at the root of the working tree in a\n non-bare repository, or in the $GIT_DIR in a bare\ndiff --git a/cache.h b/cache.h\nindex 2711048..4f7d222 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -654,6 +654,7 @@ extern int warn_on_object_refname_ambiguity;\n extern const char *apply_default_whitespace;\n extern const char *apply_default_ignorewhitespace;\n extern const char *git_attributes_file;\n+extern const char *git_hooks_path;\n extern int zlib_compression_level;\n extern int core_compression_level;\n extern int core_compression_seen;\ndiff --git a/config.c b/config.c\nindex 10b5c95..51f80e4 100644\n--- a/config.c\n+++ b/config.c\n@@ -717,6 +717,9 @@ static int git_default_core_config(const char *var, const char *value)\n \tif (!strcmp(var, \"core.attributesfile\"))\n \t\treturn git_config_pathname(&git_attributes_file, var, value);\n \n+\tif (!strcmp(var, \"core.hookspath\"))\n+\t\treturn git_config_pathname(&git_hooks_path, var, value);\n+\n \tif (!strcmp(var, \"core.bare\")) {\n \t\tis_bare_repository_cfg = git_config_bool(var, value);\n \t\treturn 0;\ndiff --git a/environment.c b/environment.c\nindex 57acb2f..2857e3f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -31,6 +31,7 @@ const char *git_log_output_encoding;\n const char *apply_default_whitespace;\n const char *apply_default_ignorewhitespace;\n const char *git_attributes_file;\n+const char *git_hooks_path;\n int zlib_compression_level = Z_BEST_SPEED;\n int core_compression_level;\n int core_compression_seen;\ndiff --git a/run-command.c b/run-command.c\nindex 8c7115a..39d7237 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -815,7 +815,10 @@ const char *find_hook(const char *name)\n \tstatic struct strbuf path = STRBUF_INIT;\n \n \tstrbuf_reset(&path);\n-\tstrbuf_git_path(&path, \"hooks/%s\", name);\n+\tif (git_hooks_path)\n+\t\tstrbuf_addf(&path, \"%s/%s\", git_hooks_path, name);\n+\telse\n+\t\tstrbuf_git_path(&path, \"hooks/%s\", name);\n \tif (access(path.buf, X_OK) < 0)\n \t\treturn NULL;\n \treturn path.buf;\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nnew file mode 100755\nindex 0000000..f2f0aa9\n--- /dev/null\n+++ b/t/t1350-config-hooks-path.sh\n@@ -0,0 +1,31 @@\n+#!/bin/sh\n+\n+test_description='Test the core.hooksPath configuration variable'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n+\tmkdir -p .git/custom-hooks .git/hooks &&\n+\twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n+printf \"%s\" \"CUST\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n+EOF\n+\twrite_script .git/hooks/pre-commit <<-\\EOF\n+printf \"%s\" \"NORM\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n+EOF\n+'\n+\n+test_expect_success 'Check that various forms of specifying core.hooksPath work' '\n+\ttest_commit no_custom_hook &&\n+\tgit config core.hooksPath .git/custom-hooks &&\n+\ttest_commit have_custom_hook &&\n+\tgit config core.hooksPath .git/custom-hooks/ &&\n+\ttest_commit have_custom_hook_trailing_slash &&\n+\tgit config core.hooksPath \"$PWD/.git/custom-hooks\" &&\n+\ttest_commit have_custom_hook_abs_path &&\n+\tgit config core.hooksPath \"$PWD/.git/custom-hooks/\" &&\n+\ttest_commit have_custom_hook_abs_path_trailing_slash &&\n+\tprintf \"%s\" \"NORMCUSTCUSTCUSTCUST\" >.git/PRE-COMMIT-HOOK-WAS-CALLED.expect &&\n+\ttest_cmp .git/PRE-COMMIT-HOOK-WAS-CALLED.expect .git/PRE-COMMIT-HOOK-WAS-CALLED\n+'\n+\n+test_done\n-- \n2.1.3\n"},{"id":"284577","messageId":"xmqqr3dsf8xg.fsf@gitster.mtv.corp.google.com","threadId":"42150","inReplyTo":"1461694402-9629-2-git-send-email-avarab@gmail.com","subject":"Re: [PATCH v4 1/4] githooks.txt: Improve the intro section","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T19:48:27Z","receivedAt":"2016-04-26T19:48:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n>  * We note what happens with chdir() before a hook is called, nothing\n>    documented this explicitly, but the current behavior is\n>    predictable. It helps a lot to know what directory these hooks will\n>    be executed from.\n\nI _think_ this item is what you meant by \"changed the wording for\nall of this to hopefully be more clear in my v4.\", but I do not\nthink it addresses \"find it somehow and then chdir()\" confusion.\n\nIt does say \"it is run at\", meaning that chdir() happens before it\nis run.  That is not sufficient to let the reader guess taht chdir()\nhappens before the hooks directory is checked relative to that\ndirectory to find the hook to run.\n\n> +When 'git init' is run it may, depending on its configuration, copy\n> +hooks to the new repository, see the the \"TEMPLATE DIRECTORY\" section\n\n\"... is run, it may, depending on its configuration, copy hooks...\"\n\nIf that is too much sentence fragments, you could reorder them, e.g.\n\n\t'git init' may copy hooks to the new repository, depending\n\ton its configuration.  See the \"TEMPLATE DIRECTORY\" section\n\nThat would fix \"the the\" as a side effect ;-).\n\n> +in linkgit:git-init[1] for details. When the rest of this document\n> +refers to \"default hooks\" it's talking about the default template\n> +shipped with Git.\n> +\n> +The currently supported hooks are described below.\n>  \n>  HOOKS\n>  -----\n"},{"id":"284578","messageId":"xmqqmvogf8w7.fsf@gitster.mtv.corp.google.com","threadId":"42150","inReplyTo":"1461694402-9629-3-git-send-email-avarab@gmail.com","subject":"Re: [PATCH v4 2/4] githooks.txt: Amend dangerous advice about 'update' hook ACL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T19:49:12Z","receivedAt":"2016-04-26T19:49:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Any ACL you implement via an 'update' hook isn't actual access control\n> if the user has login access to the machine running git, because they\n> can trivially just built their own git version which doesn't run the\n\ns/built their own git version/build their own version of git/;\n\n> hook.\n>\n> Change the documentation to take this dangerous edge case into account,\n> and remove the mention of the advice originating on the mailing list,\n> the users reading this don't care where the idea came up.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Documentation/githooks.txt | 8 +++++---\n>  1 file changed, 5 insertions(+), 3 deletions(-)\n>\n> diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\n> index 7660b95..9051584 100644\n> --- a/Documentation/githooks.txt\n> +++ b/Documentation/githooks.txt\n> @@ -275,9 +275,11 @@ does not know the entire set of branches, so it would end up\n>  firing one e-mail per ref when used naively, though.  The\n>  <<post-receive,'post-receive'>> hook is more suited to that.\n>  \n> -Another use suggested on the mailing list is to use this hook to\n> -implement access control which is finer grained than the one\n> -based on filesystem group.\n> +In an environment that restricts the users' access only to git\n> +commands over the wire, this hook can be used to implement access\n> +control without relying on filesystem ownership and group\n> +membership. See linkgit:git-shell[1] for how you might use the login\n> +shell to restrict the user's access to only git commands.\n>  \n>  Both standard output and standard error output are forwarded to\n>  'git send-pack' on the other end, so you can simply `echo` messages\n"},{"id":"284579","messageId":"xmqqinz4f8mg.fsf@gitster.mtv.corp.google.com","threadId":"42150","inReplyTo":"1461694402-9629-5-git-send-email-avarab@gmail.com","subject":"Re: [PATCH v4 4/4] hooks: Add ability to specify where the hook directory is","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T19:55:03Z","receivedAt":"2016-04-26T19:55:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +core.hooksPath::\n> +\tBy default Git will look for your hooks in the\n> +\t'$GIT_DIR/hooks' directory. Set this to different path,\n> +\te.g. '/etc/git/hooks', and Git will try to find your hooks in\n> +\tthat directory, e.g. '/etc/git/hooks/pre-receive' instead of\n> +\tin '$GIT_DIR/hooks/pre-receive'.\n> ++\n> +The path can either be absolute or relative. When specifying a\n> +relative path see the discussion in the \"DESCRIPTION\" section of\n> +linkgit:githooks[5] for what the relative relative path will be\n> +relative to.\n\n    The path can be either absolute or relative.  A relative path is\n    taken as relative to the directory where the hooks are run (see\n    linkgit:githooks[5]).\n\nperhaps?\n\n> +This configuration is useful in cases where you'd like to\n> +e.g. centrally configure your Git hooks instead of configuring them on\n\ns/e.g. //;\n\nI thought \"you can do X (if you want to do X)\" were getting\nrewritten to \"you can do X\", not \"you can do e.g. X\".\n\n> diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\n> new file mode 100755\n> index 0000000..f2f0aa9\n> --- /dev/null\n> +++ b/t/t1350-config-hooks-path.sh\n> @@ -0,0 +1,31 @@\n> +#!/bin/sh\n> +\n> +test_description='Test the core.hooksPath configuration variable'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n> +\tmkdir -p .git/custom-hooks .git/hooks &&\n> +\twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n> +printf \"%s\" \"CUST\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n> +EOF\n\n\twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n\tprintf \"%s\" \"CUST\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n\tEOF\n\nI however wonder why this is not \"echo CUST\" (or even \"echo\nCUSTOM\").\n\n> +\twrite_script .git/hooks/pre-commit <<-\\EOF\n> +printf \"%s\" \"NORM\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n> +EOF\n> +'\n\nLikewise.\n\n> +test_expect_success 'Check that various forms of specifying core.hooksPath work' '\n> +\ttest_commit no_custom_hook &&\n> +\tgit config core.hooksPath .git/custom-hooks &&\n> +\ttest_commit have_custom_hook &&\n> +\tgit config core.hooksPath .git/custom-hooks/ &&\n> +\ttest_commit have_custom_hook_trailing_slash &&\n> +\tgit config core.hooksPath \"$PWD/.git/custom-hooks\" &&\n> +\ttest_commit have_custom_hook_abs_path &&\n> +\tgit config core.hooksPath \"$PWD/.git/custom-hooks/\" &&\n> +\ttest_commit have_custom_hook_abs_path_trailing_slash &&\n> +\tprintf \"%s\" \"NORMCUSTCUSTCUSTCUST\" >.git/PRE-COMMIT-HOOK-WAS-CALLED.expect &&\n\nAnd this will become\n\n\ttest_write_lines NORM CUST CUST CUST CUST >expect &&\n\n> +\ttest_cmp .git/PRE-COMMIT-HOOK-WAS-CALLED.expect .git/PRE-COMMIT-HOOK-WAS-CALLED\n\nIf you did one-line-at-a-time with 'echo', test_cmp would show\nline-wise diff, which may make spotting the difference easier.\n\n> +'\n> +\n> +test_done\n"},{"id":"285505","messageId":"1462393128-26762-1-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"xmqqinz4f8mg.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v5 0/4] githooks.txt improvements + core.hooksDirectory","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T20:18:44Z","receivedAt":"2016-05-04T20:18:44Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This is hopefully the last version of this series. I've hopefully\naddressed the comments that came up and fixed a couple of other minor\nthings.\n\nChanges since v4:\n\n * Changed wording to config.txt's core.hooksPath documentation as\n   suggested.\n\n * Ditto for githooks.txt, and I tried to make the whole \"how we\n   chdir()\" bit less confusing.\n\n * Use more obvious test idioms, e.g. indent when using <<-\\EOF, use a\n   multi-line test_cmp file, and use \"expect\" and \"actual\" like other\n   test files instead of needlessly verbose alternatives.\n\n * Fixed a grammar error in a commit message.\n\nFor convenience & ease of review a diff between the bits of v4 and v5\nthat I changed follows below.\n\nÆvar Arnfjörð Bjarmason (4):\n  githooks.txt: Improve the intro section\n  githooks.txt: Amend dangerous advice about 'update' hook ACL\n  githooks.txt: Minor improvements to the grammar & phrasing\n  hooks: Add ability to specify where the hook directory is\n\n Documentation/config.txt     | 17 ++++++++++\n Documentation/git-init.txt   |  7 ++++-\n Documentation/githooks.txt   | 75 ++++++++++++++++++++++++++------------------\n cache.h                      |  1 +\n config.c                     |  3 ++\n environment.c                |  1 +\n run-command.c                |  5 ++-\n t/t1350-config-hooks-path.sh | 37 ++++++++++++++++++++++\n 8 files changed, 114 insertions(+), 32 deletions(-)\n create mode 100755 t/t1350-config-hooks-path.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex c007b12..9a74acd 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -625,16 +625,15 @@ core.hooksPath::\n \tthat directory, e.g. '/etc/git/hooks/pre-receive' instead of\n \tin '$GIT_DIR/hooks/pre-receive'.\n +\n-The path can either be absolute or relative. When specifying a\n-relative path see the discussion in the \"DESCRIPTION\" section of\n-linkgit:githooks[5] for what the relative relative path will be\n-relative to.\n-+\n-This configuration is useful in cases where you'd like to\n-e.g. centrally configure your Git hooks instead of configuring them on\n-a per-repository basis, or as a more flexible and centralized\n-alterantive to having an `init.templateDir` where you've changed the\n-'hooks' directory.\n+The path can be either absolute or relative. A relative path is\n+taken as relative to the directory where the hooks are run (see\n+the \"DESCRIPTION\" section of linkgit:githooks[5]).\n++\n+This configuration variable is useful in cases where you'd like to\n+centrally configure your Git hooks instead of configuring them on a\n+per-repository basis, or as a more flexible and centralized\n+alterantive to having an `init.templateDir` where you've changed\n+default hooks.\n \n core.editor::\n \tCommands such as `commit` and `tag` that lets you edit\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 97ae78d..6f562cd 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -21,20 +21,21 @@ By default the hooks directory is `$GIT_DIR/hooks`, but that can be\n changed via the `core.hooksPath` configuration variable (see\n linkgit:git-config[1]).\n \n-When a hook is invoked, it is run at the root of the working tree in a\n-non-bare repository, or in the $GIT_DIR in a bare\n-repository. I.e. hooks don't need to worry about the user's current\n-working directory.\n+Hooks don't need to worry about the user's current working\n+directory. Before Git invokes a hook it changes its working\n+directory. The working directory will be the root of the working tree\n+in a non-bare repository, or in the $GIT_DIR directory in a bare\n+repository.\n \n Hooks can get their arguments via the environment, command-line\n arguments, and stdin. See the documentation for each hook below for\n details.\n \n-When 'git init' is run it may, depending on its configuration, copy\n-hooks to the new repository, see the the \"TEMPLATE DIRECTORY\" section\n-in linkgit:git-init[1] for details. When the rest of this document\n-refers to \"default hooks\" it's talking about the default template\n-shipped with Git.\n+'git init' may copy hooks to the new repository, depending on its\n+configuration. See the \"TEMPLATE DIRECTORY\" section in\n+linkgit:git-init[1] for details. When the rest of this document refers\n+to \"default hooks\" it's talking about the default template shipped\n+with Git.\n \n The currently supported hooks are described below.\n \ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nindex f2f0aa9..6e4586a 100755\n--- a/t/t1350-config-hooks-path.sh\n+++ b/t/t1350-config-hooks-path.sh\n@@ -7,10 +7,10 @@ test_description='Test the core.hooksPath configuration variable'\n test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n \tmkdir -p .git/custom-hooks .git/hooks &&\n \twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n-printf \"%s\" \"CUST\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n+\techo CUSTOM >>actual\n EOF\n \twrite_script .git/hooks/pre-commit <<-\\EOF\n-printf \"%s\" \"NORM\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n+\techo NORMAL >>actual\n EOF\n '\n \n@@ -24,8 +24,14 @@ test_expect_success 'Check that various forms of specifying core.hooksPath work'\n \ttest_commit have_custom_hook_abs_path &&\n \tgit config core.hooksPath \"$PWD/.git/custom-hooks/\" &&\n \ttest_commit have_custom_hook_abs_path_trailing_slash &&\n-\tprintf \"%s\" \"NORMCUSTCUSTCUSTCUST\" >.git/PRE-COMMIT-HOOK-WAS-CALLED.expect &&\n-\ttest_cmp .git/PRE-COMMIT-HOOK-WAS-CALLED.expect .git/PRE-COMMIT-HOOK-WAS-CALLED\n+\tcat >expect <<-\\EOF &&\n+\tNORMAL\n+\tCUSTOM\n+\tCUSTOM\n+\tCUSTOM\n+\tCUSTOM\n+EOF\n+\ttest_cmp expect actual\n '\n \n test_done\n\n\n-- \n2.1.3\n"},{"id":"285506","messageId":"1462393128-26762-2-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462393128-26762-1-git-send-email-avarab@gmail.com","subject":"[PATCH v5 1/4] githooks.txt: Improve the intro section","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T20:18:45Z","receivedAt":"2016-05-04T20:18:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the documentation so that:\n\n * We don't talk about \"little scripts\". Hooks can be as big as you\n   want, and don't have to be scripts, just call them \"programs\".\n\n * We note that we change the working directory before a hook is called,\n   nothing documented this explicitly, but the current behavior is\n   predictable. It helps a lot to know what directory these hooks will\n   be executed from.\n\n * We don't make claims about the example hooks which may not be true\n   depending on the configuration of 'init.templateDir'. Clarify that\n   we're talking about the default settings of git-init in those cases,\n   and move some of this documentation into git-init's documentation\n   about the default templates.\n\n * We briefly note in the intro that hooks can get their arguments in\n   various different ways, and that how exactly is described below for\n   each hook.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-init.txt |  7 ++++++-\n Documentation/githooks.txt | 33 +++++++++++++++++++++------------\n 2 files changed, 27 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-init.txt b/Documentation/git-init.txt\nindex 8174d27..6364e5d 100644\n--- a/Documentation/git-init.txt\n+++ b/Documentation/git-init.txt\n@@ -130,7 +130,12 @@ The template directory will be one of the following (in order):\n  - the default template directory: `/usr/share/git-core/templates`.\n \n The default template directory includes some directory structure, suggested\n-\"exclude patterns\" (see linkgit:gitignore[5]), and sample hook files (see linkgit:githooks[5]).\n+\"exclude patterns\" (see linkgit:gitignore[5]), and sample hook files.\n+\n+The sample hooks are all disabled by default, To enable one of the\n+sample hooks rename it by removing its `.sample` suffix.\n+\n+See linkgit:githooks[5] for more general info on hook execution.\n \n EXAMPLES\n --------\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex a2f59b1..cc082d2 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -13,18 +13,27 @@ $GIT_DIR/hooks/*\n DESCRIPTION\n -----------\n \n-Hooks are little scripts you can place in `$GIT_DIR/hooks`\n-directory to trigger action at certain points.  When\n-'git init' is run, a handful of example hooks are copied into the\n-`hooks` directory of the new repository, but by default they are\n-all disabled.  To enable a hook, rename it by removing its `.sample`\n-suffix.\n-\n-NOTE: It is also a requirement for a given hook to be executable.\n-However - in a freshly initialized repository - the `.sample` files are\n-executable by default.\n-\n-This document describes the currently defined hooks.\n+Hooks are programs you can place in the `$GIT_DIR/hooks` directory to\n+trigger actions at certain points in git's execution. Hooks that don't\n+have the executable bit set are ignored.\n+\n+Hooks don't need to worry about the user's current working\n+directory. Before Git invokes a hook it changes its working\n+directory. The working directory will be the root of the working tree\n+in a non-bare repository, or in the $GIT_DIR directory in a bare\n+repository.\n+\n+Hooks can get their arguments via the environment, command-line\n+arguments, and stdin. See the documentation for each hook below for\n+details.\n+\n+'git init' may copy hooks to the new repository, depending on its\n+configuration. See the \"TEMPLATE DIRECTORY\" section in\n+linkgit:git-init[1] for details. When the rest of this document refers\n+to \"default hooks\" it's talking about the default template shipped\n+with Git.\n+\n+The currently supported hooks are described below.\n \n HOOKS\n -----\n-- \n2.1.3\n"},{"id":"285507","messageId":"1462393128-26762-3-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462393128-26762-1-git-send-email-avarab@gmail.com","subject":"[PATCH v5 2/4] githooks.txt: Amend dangerous advice about 'update' hook ACL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T20:18:46Z","receivedAt":"2016-05-04T20:18:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Any ACL you implement via an 'update' hook isn't actual access control\nif the user has login access to the machine running git, because they\ncan trivially just build their own git version which doesn't run the\nhook.\n\nChange the documentation to take this dangerous edge case into account,\nand remove the mention of the advice originating on the mailing list,\nthe users reading this don't care where the idea came up.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/githooks.txt | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex cc082d2..d28dc4c 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -276,9 +276,11 @@ does not know the entire set of branches, so it would end up\n firing one e-mail per ref when used naively, though.  The\n <<post-receive,'post-receive'>> hook is more suited to that.\n \n-Another use suggested on the mailing list is to use this hook to\n-implement access control which is finer grained than the one\n-based on filesystem group.\n+In an environment that restricts the users' access only to git\n+commands over the wire, this hook can be used to implement access\n+control without relying on filesystem ownership and group\n+membership. See linkgit:git-shell[1] for how you might use the login\n+shell to restrict the user's access to only git commands.\n \n Both standard output and standard error output are forwarded to\n 'git send-pack' on the other end, so you can simply `echo` messages\n-- \n2.1.3\n"},{"id":"285508","messageId":"1462393128-26762-4-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462393128-26762-1-git-send-email-avarab@gmail.com","subject":"[PATCH v5 3/4] githooks.txt: Minor improvements to the grammar & phrasing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T20:18:47Z","receivedAt":"2016-05-04T20:18:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change:\n\n * Sentences that needed \"the\" or \"a\" to either add those or change them\n   so they don't need them.\n\n * The little tangent about \"You can use this to do X (if your project\n   wants to do X)\" can just be shortened to \"e.g. if you want to do X\".\n\n * s/parameter/parameters/ when the plural made more sense.\n\nMost of this goes all the way back to the initial introduction of\nhooks.txt in v0.99.5-76-g6d35cc7 by Junio.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/githooks.txt | 32 ++++++++++++++++----------------\n 1 file changed, 16 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex d28dc4c..13f9a18 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -41,15 +41,15 @@ HOOKS\n applypatch-msg\n ~~~~~~~~~~~~~~\n \n-This hook is invoked by 'git am' script.  It takes a single\n+This hook is invoked by 'git am'.  It takes a single\n parameter, the name of the file that holds the proposed commit\n-log message.  Exiting with non-zero status causes\n-'git am' to abort before applying the patch.\n+log message.  Exiting with a non-zero status causes 'git am' to abort\n+before applying the patch.\n \n The hook is allowed to edit the message file in place, and can\n be used to normalize the message into some project standard\n-format (if the project has one). It can also be used to refuse\n-the commit after inspecting the message file.\n+format. It can also be used to refuse the commit after inspecting\n+the message file.\n \n The default 'applypatch-msg' hook, when enabled, runs the\n 'commit-msg' hook, if the latter is enabled.\n@@ -82,10 +82,10 @@ pre-commit\n ~~~~~~~~~~\n \n This hook is invoked by 'git commit', and can be bypassed\n-with `--no-verify` option.  It takes no parameter, and is\n+with the `--no-verify` option.  It takes no parameters, and is\n invoked before obtaining the proposed commit log message and\n-making a commit.  Exiting with non-zero status from this script\n-causes the 'git commit' to abort.\n+making a commit.  Exiting with a non-zero status from this script\n+causes the 'git commit' command to abort before creating a commit.\n \n The default 'pre-commit' hook, when enabled, catches introduction\n of lines with trailing whitespaces and aborts the commit when\n@@ -124,15 +124,15 @@ commit-msg\n ~~~~~~~~~~\n \n This hook is invoked by 'git commit', and can be bypassed\n-with `--no-verify` option.  It takes a single parameter, the\n+with the `--no-verify` option.  It takes a single parameter, the\n name of the file that holds the proposed commit log message.\n-Exiting with non-zero status causes the 'git commit' to\n+Exiting with a non-zero status causes the 'git commit' to\n abort.\n \n-The hook is allowed to edit the message file in place, and can\n-be used to normalize the message into some project standard\n-format (if the project has one). It can also be used to refuse\n-the commit after inspecting the message file.\n+The hook is allowed to edit the message file in place, and can be used\n+to normalize the message into some project standard format. It\n+can also be used to refuse the commit after inspecting the message\n+file.\n \n The default 'commit-msg' hook, when enabled, detects duplicate\n \"Signed-off-by\" lines, and aborts the commit if one is found.\n@@ -140,8 +140,8 @@ The default 'commit-msg' hook, when enabled, detects duplicate\n post-commit\n ~~~~~~~~~~~\n \n-This hook is invoked by 'git commit'.  It takes no\n-parameter, and is invoked after a commit is made.\n+This hook is invoked by 'git commit'. It takes no parameters, and is\n+invoked after a commit is made.\n \n This hook is meant primarily for notification, and cannot affect\n the outcome of 'git commit'.\n-- \n2.1.3\n"},{"id":"285509","messageId":"1462393128-26762-5-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462393128-26762-1-git-send-email-avarab@gmail.com","subject":"[PATCH v5 4/4] hooks: Add ability to specify where the hook directory is","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T20:18:48Z","receivedAt":"2016-05-04T20:18:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the hardcoded lookup for .git/hooks/* to optionally lookup in\n$(git config core.hooksPath)/* instead.\n\nThis is essentially a more intrusive version of the git-init ability to\nspecify hooks on init time via init templates.\n\nThe difference between that facility and this feature is that this can\nbe set up after the fact via e.g. ~/.gitconfig or /etc/gitconfig to\napply for all your personal repositories, or all repositories on the\nsystem.\n\nI plan on using this on a centralized Git server where users can create\narbitrary repositories under /gitroot, but I'd like to manage all the\nhooks that should be run centrally via a unified dispatch mechanism.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt     | 17 +++++++++++++++++\n Documentation/githooks.txt   | 12 ++++++++----\n cache.h                      |  1 +\n config.c                     |  3 +++\n environment.c                |  1 +\n run-command.c                |  5 ++++-\n t/t1350-config-hooks-path.sh | 37 +++++++++++++++++++++++++++++++++++++\n 7 files changed, 71 insertions(+), 5 deletions(-)\n create mode 100755 t/t1350-config-hooks-path.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 42d2b50..9a74acd 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -618,6 +618,23 @@ core.attributesFile::\n \t$XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not\n \tset or empty, $HOME/.config/git/attributes is used instead.\n \n+core.hooksPath::\n+\tBy default Git will look for your hooks in the\n+\t'$GIT_DIR/hooks' directory. Set this to different path,\n+\te.g. '/etc/git/hooks', and Git will try to find your hooks in\n+\tthat directory, e.g. '/etc/git/hooks/pre-receive' instead of\n+\tin '$GIT_DIR/hooks/pre-receive'.\n++\n+The path can be either absolute or relative. A relative path is\n+taken as relative to the directory where the hooks are run (see\n+the \"DESCRIPTION\" section of linkgit:githooks[5]).\n++\n+This configuration variable is useful in cases where you'd like to\n+centrally configure your Git hooks instead of configuring them on a\n+per-repository basis, or as a more flexible and centralized\n+alterantive to having an `init.templateDir` where you've changed\n+default hooks.\n+\n core.editor::\n \tCommands such as `commit` and `tag` that lets you edit\n \tmessages by launching an editor uses the value of this\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 13f9a18..6f562cd 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -7,15 +7,19 @@ githooks - Hooks used by Git\n \n SYNOPSIS\n --------\n-$GIT_DIR/hooks/*\n+$GIT_DIR/hooks/* (or \\`git config core.hooksPath`/*)\n \n \n DESCRIPTION\n -----------\n \n-Hooks are programs you can place in the `$GIT_DIR/hooks` directory to\n-trigger actions at certain points in git's execution. Hooks that don't\n-have the executable bit set are ignored.\n+Hooks are programs you can place in a hooks directory to trigger\n+actions at certain points in git's execution. Hooks that don't have\n+the executable bit set are ignored.\n+\n+By default the hooks directory is `$GIT_DIR/hooks`, but that can be\n+changed via the `core.hooksPath` configuration variable (see\n+linkgit:git-config[1]).\n \n Hooks don't need to worry about the user's current working\n directory. Before Git invokes a hook it changes its working\ndiff --git a/cache.h b/cache.h\nindex fd728f0..c071f5d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -654,6 +654,7 @@ extern int warn_on_object_refname_ambiguity;\n extern const char *apply_default_whitespace;\n extern const char *apply_default_ignorewhitespace;\n extern const char *git_attributes_file;\n+extern const char *git_hooks_path;\n extern int zlib_compression_level;\n extern int core_compression_level;\n extern int core_compression_seen;\ndiff --git a/config.c b/config.c\nindex 10b5c95..51f80e4 100644\n--- a/config.c\n+++ b/config.c\n@@ -717,6 +717,9 @@ static int git_default_core_config(const char *var, const char *value)\n \tif (!strcmp(var, \"core.attributesfile\"))\n \t\treturn git_config_pathname(&git_attributes_file, var, value);\n \n+\tif (!strcmp(var, \"core.hookspath\"))\n+\t\treturn git_config_pathname(&git_hooks_path, var, value);\n+\n \tif (!strcmp(var, \"core.bare\")) {\n \t\tis_bare_repository_cfg = git_config_bool(var, value);\n \t\treturn 0;\ndiff --git a/environment.c b/environment.c\nindex 57acb2f..2857e3f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -31,6 +31,7 @@ const char *git_log_output_encoding;\n const char *apply_default_whitespace;\n const char *apply_default_ignorewhitespace;\n const char *git_attributes_file;\n+const char *git_hooks_path;\n int zlib_compression_level = Z_BEST_SPEED;\n int core_compression_level;\n int core_compression_seen;\ndiff --git a/run-command.c b/run-command.c\nindex e4593cd..f5c57a5 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -825,7 +825,10 @@ const char *find_hook(const char *name)\n \tstatic struct strbuf path = STRBUF_INIT;\n \n \tstrbuf_reset(&path);\n-\tstrbuf_git_path(&path, \"hooks/%s\", name);\n+\tif (git_hooks_path)\n+\t\tstrbuf_addf(&path, \"%s/%s\", git_hooks_path, name);\n+\telse\n+\t\tstrbuf_git_path(&path, \"hooks/%s\", name);\n \tif (access(path.buf, X_OK) < 0)\n \t\treturn NULL;\n \treturn path.buf;\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nnew file mode 100755\nindex 0000000..6e4586a\n--- /dev/null\n+++ b/t/t1350-config-hooks-path.sh\n@@ -0,0 +1,37 @@\n+#!/bin/sh\n+\n+test_description='Test the core.hooksPath configuration variable'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n+\tmkdir -p .git/custom-hooks .git/hooks &&\n+\twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n+\techo CUSTOM >>actual\n+EOF\n+\twrite_script .git/hooks/pre-commit <<-\\EOF\n+\techo NORMAL >>actual\n+EOF\n+'\n+\n+test_expect_success 'Check that various forms of specifying core.hooksPath work' '\n+\ttest_commit no_custom_hook &&\n+\tgit config core.hooksPath .git/custom-hooks &&\n+\ttest_commit have_custom_hook &&\n+\tgit config core.hooksPath .git/custom-hooks/ &&\n+\ttest_commit have_custom_hook_trailing_slash &&\n+\tgit config core.hooksPath \"$PWD/.git/custom-hooks\" &&\n+\ttest_commit have_custom_hook_abs_path &&\n+\tgit config core.hooksPath \"$PWD/.git/custom-hooks/\" &&\n+\ttest_commit have_custom_hook_abs_path_trailing_slash &&\n+\tcat >expect <<-\\EOF &&\n+\tNORMAL\n+\tCUSTOM\n+\tCUSTOM\n+\tCUSTOM\n+\tCUSTOM\n+EOF\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.1.3\n"},{"id":"285531","messageId":"xmqqa8k5eakb.fsf@gitster.mtv.corp.google.com","threadId":"42150","inReplyTo":"1462393128-26762-1-git-send-email-avarab@gmail.com","subject":"Re: [PATCH v5 0/4] githooks.txt improvements + core.hooksDirectory","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-04T22:13:24Z","receivedAt":"2016-05-04T22:13:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> For convenience & ease of review a diff between the bits of v4 and v5\n> that I changed follows below.\n\nThanks.\n\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> ...\n> +This configuration variable is useful in cases where you'd like to\n> +centrally configure your Git hooks instead of configuring them on a\n> +per-repository basis, or as a more flexible and centralized\n> +alterantive to having an `init.templateDir` where you've changed\n\n\"alternative\" (can be locally amended).\n\n> diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\n> ...\n> +Hooks don't need to worry about the user's current working\n> +directory. Before Git invokes a hook it changes its working\n> +directory. The working directory will be the root of the working tree\n> +in a non-bare repository, or in the $GIT_DIR directory in a bare\n> +repository.\n\nI suspect that the first sentence does more harm than good.  When\nyou say \"don't need to worry about\", somebody is bound to ask \"that\nis good that I do not need to, but what if I _want_ to know?\", and\nyou do not have a good answer to that question.\n\n\tBefore Git invokes a hook, it changes its working directory\n\tto either the root of the working tree in a non-bare\n\trepository, or to the $GIT_DIR in a bare repository.\n\nperhaps?\n\n> diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\n> index f2f0aa9..6e4586a 100755\n> --- a/t/t1350-config-hooks-path.sh\n> +++ b/t/t1350-config-hooks-path.sh\n> @@ -7,10 +7,10 @@ test_description='Test the core.hooksPath configuration variable'\n>  test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n>  \tmkdir -p .git/custom-hooks .git/hooks &&\n>  \twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n> -printf \"%s\" \"CUST\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n> +\techo CUSTOM >>actual\n>  EOF\n>  \twrite_script .git/hooks/pre-commit <<-\\EOF\n> -printf \"%s\" \"NORM\" >>.git/PRE-COMMIT-HOOK-WAS-CALLED\n> +\techo NORMAL >>actual\n>  EOF\n>  '\n\nThese closing EOF can and should be indented like the body of the\nhere-text, i.e.\n\n\tcmd <<-\\EOF &&\n        ...\n        EOF\n\n> @@ -24,8 +24,14 @@ test_expect_success 'Check that various forms of specifying core.hooksPath work'\n>  \ttest_commit have_custom_hook_abs_path &&\n>  \tgit config core.hooksPath \"$PWD/.git/custom-hooks/\" &&\n>  \ttest_commit have_custom_hook_abs_path_trailing_slash &&\n> -\tprintf \"%s\" \"NORMCUSTCUSTCUSTCUST\" >.git/PRE-COMMIT-HOOK-WAS-CALLED.expect &&\n> -\ttest_cmp .git/PRE-COMMIT-HOOK-WAS-CALLED.expect .git/PRE-COMMIT-HOOK-WAS-CALLED\n> +\tcat >expect <<-\\EOF &&\n> +\tNORMAL\n> +\tCUSTOM\n> +\tCUSTOM\n> +\tCUSTOM\n> +\tCUSTOM\n> +EOF\n\nLikewise.\n"},{"id":"285536","messageId":"1462402692-24712-1-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"xmqqa8k5eakb.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 0/4] githooks.txt improvements + core.hooksDirectory","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T22:58:08Z","receivedAt":"2016-05-04T22:58:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Changed to reflect Junio's latest comment, diff between the whole\nseries and the last one here at the end (made with -U0).\n\nÆvar Arnfjörð Bjarmason (4):\n  githooks.txt: Improve the intro section\n  githooks.txt: Amend dangerous advice about 'update' hook ACL\n  githooks.txt: Minor improvements to the grammar & phrasing\n  hooks: Add ability to specify where the hook directory is\n\n Documentation/config.txt     | 17 +++++++++++\n Documentation/git-init.txt   |  7 ++++-\n Documentation/githooks.txt   | 73 ++++++++++++++++++++++++++------------------\n cache.h                      |  1 +\n config.c                     |  3 ++\n environment.c                |  1 +\n run-command.c                |  5 ++-\n t/t1350-config-hooks-path.sh | 37 ++++++++++++++++++++++\n 8 files changed, 112 insertions(+), 32 deletions(-)\n create mode 100755 t/t1350-config-hooks-path.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 9a74acd..6cc069f 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -635 +635 @@ per-repository basis, or as a more flexible and centralized\n-alterantive to having an `init.templateDir` where you've changed\n+alternative to having an `init.templateDir` where you've changed\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 6f562cd..d82e912 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -24,5 +24,3 @@ linkgit:git-config[1]).\n-Hooks don't need to worry about the user's current working\n-directory. Before Git invokes a hook it changes its working\n-directory. The working directory will be the root of the working tree\n-in a non-bare repository, or in the $GIT_DIR directory in a bare\n-repository.\n+Before Git invokes a hook, it changes its working directory to either\n+the root of the working tree in a non-bare repository, or to the\n+$GIT_DIR in a bare repository.\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nindex 6e4586a..5e3fb3a 100755\n--- a/t/t1350-config-hooks-path.sh\n+++ b/t/t1350-config-hooks-path.sh\n@@ -11 +11 @@ test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n-EOF\n+\tEOF\n@@ -14 +14 @@ EOF\n-EOF\n+\tEOF\n@@ -33 +33 @@ test_expect_success 'Check that various forms of specifying core.hooksPath work'\n-EOF\n+\tEOF\n\n\n-- \n2.1.3\n"},{"id":"285537","messageId":"1462402692-24712-2-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462402692-24712-1-git-send-email-avarab@gmail.com","subject":"[PATCH v6 1/4] githooks.txt: Improve the intro section","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T22:58:09Z","receivedAt":"2016-05-04T22:58:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the documentation so that:\n\n * We don't talk about \"little scripts\". Hooks can be as big as you\n   want, and don't have to be scripts, just call them \"programs\".\n\n * We note that we change the working directory before a hook is called,\n   nothing documented this explicitly, but the current behavior is\n   predictable. It helps a lot to know what directory these hooks will\n   be executed from.\n\n * We don't make claims about the example hooks which may not be true\n   depending on the configuration of 'init.templateDir'. Clarify that\n   we're talking about the default settings of git-init in those cases,\n   and move some of this documentation into git-init's documentation\n   about the default templates.\n\n * We briefly note in the intro that hooks can get their arguments in\n   various different ways, and that how exactly is described below for\n   each hook.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-init.txt |  7 ++++++-\n Documentation/githooks.txt | 31 +++++++++++++++++++------------\n 2 files changed, 25 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-init.txt b/Documentation/git-init.txt\nindex 8174d27..6364e5d 100644\n--- a/Documentation/git-init.txt\n+++ b/Documentation/git-init.txt\n@@ -130,7 +130,12 @@ The template directory will be one of the following (in order):\n  - the default template directory: `/usr/share/git-core/templates`.\n \n The default template directory includes some directory structure, suggested\n-\"exclude patterns\" (see linkgit:gitignore[5]), and sample hook files (see linkgit:githooks[5]).\n+\"exclude patterns\" (see linkgit:gitignore[5]), and sample hook files.\n+\n+The sample hooks are all disabled by default, To enable one of the\n+sample hooks rename it by removing its `.sample` suffix.\n+\n+See linkgit:githooks[5] for more general info on hook execution.\n \n EXAMPLES\n --------\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex a2f59b1..0d94337 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -13,18 +13,25 @@ $GIT_DIR/hooks/*\n DESCRIPTION\n -----------\n \n-Hooks are little scripts you can place in `$GIT_DIR/hooks`\n-directory to trigger action at certain points.  When\n-'git init' is run, a handful of example hooks are copied into the\n-`hooks` directory of the new repository, but by default they are\n-all disabled.  To enable a hook, rename it by removing its `.sample`\n-suffix.\n-\n-NOTE: It is also a requirement for a given hook to be executable.\n-However - in a freshly initialized repository - the `.sample` files are\n-executable by default.\n-\n-This document describes the currently defined hooks.\n+Hooks are programs you can place in the `$GIT_DIR/hooks` directory to\n+trigger actions at certain points in git's execution. Hooks that don't\n+have the executable bit set are ignored.\n+\n+Before Git invokes a hook, it changes its working directory to either\n+the root of the working tree in a non-bare repository, or to the\n+$GIT_DIR in a bare repository.\n+\n+Hooks can get their arguments via the environment, command-line\n+arguments, and stdin. See the documentation for each hook below for\n+details.\n+\n+'git init' may copy hooks to the new repository, depending on its\n+configuration. See the \"TEMPLATE DIRECTORY\" section in\n+linkgit:git-init[1] for details. When the rest of this document refers\n+to \"default hooks\" it's talking about the default template shipped\n+with Git.\n+\n+The currently supported hooks are described below.\n \n HOOKS\n -----\n-- \n2.1.3\n"},{"id":"285539","messageId":"1462402692-24712-3-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462402692-24712-1-git-send-email-avarab@gmail.com","subject":"[PATCH v6 2/4] githooks.txt: Amend dangerous advice about 'update' hook ACL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T22:58:10Z","receivedAt":"2016-05-04T22:58:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Any ACL you implement via an 'update' hook isn't actual access control\nif the user has login access to the machine running git, because they\ncan trivially just build their own git version which doesn't run the\nhook.\n\nChange the documentation to take this dangerous edge case into account,\nand remove the mention of the advice originating on the mailing list,\nthe users reading this don't care where the idea came up.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/githooks.txt | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 0d94337..0dd618a 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -274,9 +274,11 @@ does not know the entire set of branches, so it would end up\n firing one e-mail per ref when used naively, though.  The\n <<post-receive,'post-receive'>> hook is more suited to that.\n \n-Another use suggested on the mailing list is to use this hook to\n-implement access control which is finer grained than the one\n-based on filesystem group.\n+In an environment that restricts the users' access only to git\n+commands over the wire, this hook can be used to implement access\n+control without relying on filesystem ownership and group\n+membership. See linkgit:git-shell[1] for how you might use the login\n+shell to restrict the user's access to only git commands.\n \n Both standard output and standard error output are forwarded to\n 'git send-pack' on the other end, so you can simply `echo` messages\n-- \n2.1.3\n"},{"id":"285538","messageId":"1462402692-24712-4-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462402692-24712-1-git-send-email-avarab@gmail.com","subject":"[PATCH v6 3/4] githooks.txt: Minor improvements to the grammar & phrasing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T22:58:11Z","receivedAt":"2016-05-04T22:58:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change:\n\n * Sentences that needed \"the\" or \"a\" to either add those or change them\n   so they don't need them.\n\n * The little tangent about \"You can use this to do X (if your project\n   wants to do X)\" can just be shortened to \"e.g. if you want to do X\".\n\n * s/parameter/parameters/ when the plural made more sense.\n\nMost of this goes all the way back to the initial introduction of\nhooks.txt in v0.99.5-76-g6d35cc7 by Junio.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/githooks.txt | 32 ++++++++++++++++----------------\n 1 file changed, 16 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 0dd618a..3049574 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -39,15 +39,15 @@ HOOKS\n applypatch-msg\n ~~~~~~~~~~~~~~\n \n-This hook is invoked by 'git am' script.  It takes a single\n+This hook is invoked by 'git am'.  It takes a single\n parameter, the name of the file that holds the proposed commit\n-log message.  Exiting with non-zero status causes\n-'git am' to abort before applying the patch.\n+log message.  Exiting with a non-zero status causes 'git am' to abort\n+before applying the patch.\n \n The hook is allowed to edit the message file in place, and can\n be used to normalize the message into some project standard\n-format (if the project has one). It can also be used to refuse\n-the commit after inspecting the message file.\n+format. It can also be used to refuse the commit after inspecting\n+the message file.\n \n The default 'applypatch-msg' hook, when enabled, runs the\n 'commit-msg' hook, if the latter is enabled.\n@@ -80,10 +80,10 @@ pre-commit\n ~~~~~~~~~~\n \n This hook is invoked by 'git commit', and can be bypassed\n-with `--no-verify` option.  It takes no parameter, and is\n+with the `--no-verify` option.  It takes no parameters, and is\n invoked before obtaining the proposed commit log message and\n-making a commit.  Exiting with non-zero status from this script\n-causes the 'git commit' to abort.\n+making a commit.  Exiting with a non-zero status from this script\n+causes the 'git commit' command to abort before creating a commit.\n \n The default 'pre-commit' hook, when enabled, catches introduction\n of lines with trailing whitespaces and aborts the commit when\n@@ -122,15 +122,15 @@ commit-msg\n ~~~~~~~~~~\n \n This hook is invoked by 'git commit', and can be bypassed\n-with `--no-verify` option.  It takes a single parameter, the\n+with the `--no-verify` option.  It takes a single parameter, the\n name of the file that holds the proposed commit log message.\n-Exiting with non-zero status causes the 'git commit' to\n+Exiting with a non-zero status causes the 'git commit' to\n abort.\n \n-The hook is allowed to edit the message file in place, and can\n-be used to normalize the message into some project standard\n-format (if the project has one). It can also be used to refuse\n-the commit after inspecting the message file.\n+The hook is allowed to edit the message file in place, and can be used\n+to normalize the message into some project standard format. It\n+can also be used to refuse the commit after inspecting the message\n+file.\n \n The default 'commit-msg' hook, when enabled, detects duplicate\n \"Signed-off-by\" lines, and aborts the commit if one is found.\n@@ -138,8 +138,8 @@ The default 'commit-msg' hook, when enabled, detects duplicate\n post-commit\n ~~~~~~~~~~~\n \n-This hook is invoked by 'git commit'.  It takes no\n-parameter, and is invoked after a commit is made.\n+This hook is invoked by 'git commit'. It takes no parameters, and is\n+invoked after a commit is made.\n \n This hook is meant primarily for notification, and cannot affect\n the outcome of 'git commit'.\n-- \n2.1.3\n"},{"id":"285540","messageId":"1462402692-24712-5-git-send-email-avarab@gmail.com","threadId":"42150","inReplyTo":"1462402692-24712-1-git-send-email-avarab@gmail.com","subject":"[PATCH v6 4/4] hooks: Add ability to specify where the hook directory is","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2016-05-04T22:58:12Z","receivedAt":"2016-05-04T22:58:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the hardcoded lookup for .git/hooks/* to optionally lookup in\n$(git config core.hooksPath)/* instead.\n\nThis is essentially a more intrusive version of the git-init ability to\nspecify hooks on init time via init templates.\n\nThe difference between that facility and this feature is that this can\nbe set up after the fact via e.g. ~/.gitconfig or /etc/gitconfig to\napply for all your personal repositories, or all repositories on the\nsystem.\n\nI plan on using this on a centralized Git server where users can create\narbitrary repositories under /gitroot, but I'd like to manage all the\nhooks that should be run centrally via a unified dispatch mechanism.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt     | 17 +++++++++++++++++\n Documentation/githooks.txt   | 12 ++++++++----\n cache.h                      |  1 +\n config.c                     |  3 +++\n environment.c                |  1 +\n run-command.c                |  5 ++++-\n t/t1350-config-hooks-path.sh | 37 +++++++++++++++++++++++++++++++++++++\n 7 files changed, 71 insertions(+), 5 deletions(-)\n create mode 100755 t/t1350-config-hooks-path.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 42d2b50..6cc069f 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -618,6 +618,23 @@ core.attributesFile::\n \t$XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not\n \tset or empty, $HOME/.config/git/attributes is used instead.\n \n+core.hooksPath::\n+\tBy default Git will look for your hooks in the\n+\t'$GIT_DIR/hooks' directory. Set this to different path,\n+\te.g. '/etc/git/hooks', and Git will try to find your hooks in\n+\tthat directory, e.g. '/etc/git/hooks/pre-receive' instead of\n+\tin '$GIT_DIR/hooks/pre-receive'.\n++\n+The path can be either absolute or relative. A relative path is\n+taken as relative to the directory where the hooks are run (see\n+the \"DESCRIPTION\" section of linkgit:githooks[5]).\n++\n+This configuration variable is useful in cases where you'd like to\n+centrally configure your Git hooks instead of configuring them on a\n+per-repository basis, or as a more flexible and centralized\n+alternative to having an `init.templateDir` where you've changed\n+default hooks.\n+\n core.editor::\n \tCommands such as `commit` and `tag` that lets you edit\n \tmessages by launching an editor uses the value of this\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 3049574..d82e912 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -7,15 +7,19 @@ githooks - Hooks used by Git\n \n SYNOPSIS\n --------\n-$GIT_DIR/hooks/*\n+$GIT_DIR/hooks/* (or \\`git config core.hooksPath`/*)\n \n \n DESCRIPTION\n -----------\n \n-Hooks are programs you can place in the `$GIT_DIR/hooks` directory to\n-trigger actions at certain points in git's execution. Hooks that don't\n-have the executable bit set are ignored.\n+Hooks are programs you can place in a hooks directory to trigger\n+actions at certain points in git's execution. Hooks that don't have\n+the executable bit set are ignored.\n+\n+By default the hooks directory is `$GIT_DIR/hooks`, but that can be\n+changed via the `core.hooksPath` configuration variable (see\n+linkgit:git-config[1]).\n \n Before Git invokes a hook, it changes its working directory to either\n the root of the working tree in a non-bare repository, or to the\ndiff --git a/cache.h b/cache.h\nindex fd728f0..c071f5d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -654,6 +654,7 @@ extern int warn_on_object_refname_ambiguity;\n extern const char *apply_default_whitespace;\n extern const char *apply_default_ignorewhitespace;\n extern const char *git_attributes_file;\n+extern const char *git_hooks_path;\n extern int zlib_compression_level;\n extern int core_compression_level;\n extern int core_compression_seen;\ndiff --git a/config.c b/config.c\nindex 10b5c95..51f80e4 100644\n--- a/config.c\n+++ b/config.c\n@@ -717,6 +717,9 @@ static int git_default_core_config(const char *var, const char *value)\n \tif (!strcmp(var, \"core.attributesfile\"))\n \t\treturn git_config_pathname(&git_attributes_file, var, value);\n \n+\tif (!strcmp(var, \"core.hookspath\"))\n+\t\treturn git_config_pathname(&git_hooks_path, var, value);\n+\n \tif (!strcmp(var, \"core.bare\")) {\n \t\tis_bare_repository_cfg = git_config_bool(var, value);\n \t\treturn 0;\ndiff --git a/environment.c b/environment.c\nindex 57acb2f..2857e3f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -31,6 +31,7 @@ const char *git_log_output_encoding;\n const char *apply_default_whitespace;\n const char *apply_default_ignorewhitespace;\n const char *git_attributes_file;\n+const char *git_hooks_path;\n int zlib_compression_level = Z_BEST_SPEED;\n int core_compression_level;\n int core_compression_seen;\ndiff --git a/run-command.c b/run-command.c\nindex e4593cd..f5c57a5 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -825,7 +825,10 @@ const char *find_hook(const char *name)\n \tstatic struct strbuf path = STRBUF_INIT;\n \n \tstrbuf_reset(&path);\n-\tstrbuf_git_path(&path, \"hooks/%s\", name);\n+\tif (git_hooks_path)\n+\t\tstrbuf_addf(&path, \"%s/%s\", git_hooks_path, name);\n+\telse\n+\t\tstrbuf_git_path(&path, \"hooks/%s\", name);\n \tif (access(path.buf, X_OK) < 0)\n \t\treturn NULL;\n \treturn path.buf;\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nnew file mode 100755\nindex 0000000..5e3fb3a\n--- /dev/null\n+++ b/t/t1350-config-hooks-path.sh\n@@ -0,0 +1,37 @@\n+#!/bin/sh\n+\n+test_description='Test the core.hooksPath configuration variable'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n+\tmkdir -p .git/custom-hooks .git/hooks &&\n+\twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n+\techo CUSTOM >>actual\n+\tEOF\n+\twrite_script .git/hooks/pre-commit <<-\\EOF\n+\techo NORMAL >>actual\n+\tEOF\n+'\n+\n+test_expect_success 'Check that various forms of specifying core.hooksPath work' '\n+\ttest_commit no_custom_hook &&\n+\tgit config core.hooksPath .git/custom-hooks &&\n+\ttest_commit have_custom_hook &&\n+\tgit config core.hooksPath .git/custom-hooks/ &&\n+\ttest_commit have_custom_hook_trailing_slash &&\n+\tgit config core.hooksPath \"$PWD/.git/custom-hooks\" &&\n+\ttest_commit have_custom_hook_abs_path &&\n+\tgit config core.hooksPath \"$PWD/.git/custom-hooks/\" &&\n+\ttest_commit have_custom_hook_abs_path_trailing_slash &&\n+\tcat >expect <<-\\EOF &&\n+\tNORMAL\n+\tCUSTOM\n+\tCUSTOM\n+\tCUSTOM\n+\tCUSTOM\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.1.3\n"},{"id":"285546","messageId":"xmqqk2j9cslj.fsf@gitster.mtv.corp.google.com","threadId":"42150","inReplyTo":"1462402692-24712-1-git-send-email-avarab@gmail.com","subject":"Re: [PATCH v6 0/4] githooks.txt improvements + core.hooksDirectory","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-04T23:26:48Z","receivedAt":"2016-05-04T23:26:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks, will replace.  Let's start moving this to 'next'.\n"}]}