Merge branch 'ab/hooks'

A new configuration variable core.hooksPath allows customizing
where the hook directory is.

* ab/hooks:
  hooks: allow customizing where the hook directory is
  githooks.txt: minor improvements to the grammar & phrasing
  githooks.txt: amend dangerous advice about 'update' hook ACL
  githooks.txt: improve the intro section
This commit is contained in:
Junio C Hamano 2016-05-17 14:38:17 -07:00
commit 6675f501f6
8 changed files with 112 additions and 32 deletions

View File

@ -618,6 +618,23 @@ core.attributesFile::
$XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
set or empty, $HOME/.config/git/attributes is used instead. set or empty, $HOME/.config/git/attributes is used instead.
core.hooksPath::
By default Git will look for your hooks in the
'$GIT_DIR/hooks' directory. Set this to different path,
e.g. '/etc/git/hooks', and Git will try to find your hooks in
that directory, e.g. '/etc/git/hooks/pre-receive' instead of
in '$GIT_DIR/hooks/pre-receive'.
+
The path can be either absolute or relative. A relative path is
taken as relative to the directory where the hooks are run (see
the "DESCRIPTION" section of linkgit:githooks[5]).
+
This configuration variable is useful in cases where you'd like to
centrally configure your Git hooks instead of configuring them on a
per-repository basis, or as a more flexible and centralized
alternative to having an `init.templateDir` where you've changed
default hooks.
core.editor:: core.editor::
Commands such as `commit` and `tag` that lets you edit Commands such as `commit` and `tag` that lets you edit
messages by launching an editor uses the value of this messages by launching an editor uses the value of this

View File

@ -130,7 +130,12 @@ The template directory will be one of the following (in order):
- the default template directory: `/usr/share/git-core/templates`. - the default template directory: `/usr/share/git-core/templates`.
The default template directory includes some directory structure, suggested The default template directory includes some directory structure, suggested
"exclude patterns" (see linkgit:gitignore[5]), and sample hook files (see linkgit:githooks[5]). "exclude patterns" (see linkgit:gitignore[5]), and sample hook files.
The sample hooks are all disabled by default, To enable one of the
sample hooks rename it by removing its `.sample` suffix.
See linkgit:githooks[5] for more general info on hook execution.
EXAMPLES EXAMPLES
-------- --------

View File

@ -7,24 +7,35 @@ githooks - Hooks used by Git
SYNOPSIS SYNOPSIS
-------- --------
$GIT_DIR/hooks/* $GIT_DIR/hooks/* (or \`git config core.hooksPath`/*)
DESCRIPTION DESCRIPTION
----------- -----------
Hooks are little scripts you can place in `$GIT_DIR/hooks` Hooks are programs you can place in a hooks directory to trigger
directory to trigger action at certain points. When actions at certain points in git's execution. Hooks that don't have
'git init' is run, a handful of example hooks are copied into the the executable bit set are ignored.
`hooks` directory of the new repository, but by default they are
all disabled. To enable a hook, rename it by removing its `.sample`
suffix.
NOTE: It is also a requirement for a given hook to be executable. By default the hooks directory is `$GIT_DIR/hooks`, but that can be
However - in a freshly initialized repository - the `.sample` files are changed via the `core.hooksPath` configuration variable (see
executable by default. linkgit:git-config[1]).
This document describes the currently defined hooks. Before Git invokes a hook, it changes its working directory to either
the root of the working tree in a non-bare repository, or to the
$GIT_DIR in a bare repository.
Hooks can get their arguments via the environment, command-line
arguments, and stdin. See the documentation for each hook below for
details.
'git init' may copy hooks to the new repository, depending on its
configuration. See the "TEMPLATE DIRECTORY" section in
linkgit:git-init[1] for details. When the rest of this document refers
to "default hooks" it's talking about the default template shipped
with Git.
The currently supported hooks are described below.
HOOKS HOOKS
----- -----
@ -32,15 +43,15 @@ HOOKS
applypatch-msg applypatch-msg
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
This hook is invoked by 'git am' script. It takes a single This hook is invoked by 'git am'. It takes a single
parameter, the name of the file that holds the proposed commit parameter, the name of the file that holds the proposed commit
log message. Exiting with non-zero status causes log message. Exiting with a non-zero status causes 'git am' to abort
'git am' to abort before applying the patch. before applying the patch.
The hook is allowed to edit the message file in place, and can The hook is allowed to edit the message file in place, and can
be used to normalize the message into some project standard be used to normalize the message into some project standard
format (if the project has one). It can also be used to refuse format. It can also be used to refuse the commit after inspecting
the commit after inspecting the message file. the message file.
The default 'applypatch-msg' hook, when enabled, runs the The default 'applypatch-msg' hook, when enabled, runs the
'commit-msg' hook, if the latter is enabled. 'commit-msg' hook, if the latter is enabled.
@ -73,10 +84,10 @@ pre-commit
~~~~~~~~~~ ~~~~~~~~~~
This hook is invoked by 'git commit', and can be bypassed This hook is invoked by 'git commit', and can be bypassed
with `--no-verify` option. It takes no parameter, and is with the `--no-verify` option. It takes no parameters, and is
invoked before obtaining the proposed commit log message and invoked before obtaining the proposed commit log message and
making a commit. Exiting with non-zero status from this script making a commit. Exiting with a non-zero status from this script
causes the 'git commit' to abort. causes the 'git commit' command to abort before creating a commit.
The default 'pre-commit' hook, when enabled, catches introduction The default 'pre-commit' hook, when enabled, catches introduction
of lines with trailing whitespaces and aborts the commit when of lines with trailing whitespaces and aborts the commit when
@ -115,15 +126,15 @@ commit-msg
~~~~~~~~~~ ~~~~~~~~~~
This hook is invoked by 'git commit', and can be bypassed This hook is invoked by 'git commit', and can be bypassed
with `--no-verify` option. It takes a single parameter, the with the `--no-verify` option. It takes a single parameter, the
name of the file that holds the proposed commit log message. name of the file that holds the proposed commit log message.
Exiting with non-zero status causes the 'git commit' to Exiting with a non-zero status causes the 'git commit' to
abort. abort.
The hook is allowed to edit the message file in place, and can The hook is allowed to edit the message file in place, and can be used
be used to normalize the message into some project standard to normalize the message into some project standard format. It
format (if the project has one). It can also be used to refuse can also be used to refuse the commit after inspecting the message
the commit after inspecting the message file. file.
The default 'commit-msg' hook, when enabled, detects duplicate The default 'commit-msg' hook, when enabled, detects duplicate
"Signed-off-by" lines, and aborts the commit if one is found. "Signed-off-by" lines, and aborts the commit if one is found.
@ -131,8 +142,8 @@ The default 'commit-msg' hook, when enabled, detects duplicate
post-commit post-commit
~~~~~~~~~~~ ~~~~~~~~~~~
This hook is invoked by 'git commit'. It takes no This hook is invoked by 'git commit'. It takes no parameters, and is
parameter, and is invoked after a commit is made. invoked after a commit is made.
This hook is meant primarily for notification, and cannot affect This hook is meant primarily for notification, and cannot affect
the outcome of 'git commit'. the outcome of 'git commit'.
@ -267,9 +278,11 @@ does not know the entire set of branches, so it would end up
firing one e-mail per ref when used naively, though. The firing one e-mail per ref when used naively, though. The
<<post-receive,'post-receive'>> hook is more suited to that. <<post-receive,'post-receive'>> hook is more suited to that.
Another use suggested on the mailing list is to use this hook to In an environment that restricts the users' access only to git
implement access control which is finer grained than the one commands over the wire, this hook can be used to implement access
based on filesystem group. control without relying on filesystem ownership and group
membership. See linkgit:git-shell[1] for how you might use the login
shell to restrict the user's access to only git commands.
Both standard output and standard error output are forwarded to Both standard output and standard error output are forwarded to
'git send-pack' on the other end, so you can simply `echo` messages 'git send-pack' on the other end, so you can simply `echo` messages

View File

@ -654,6 +654,7 @@ extern int warn_on_object_refname_ambiguity;
extern const char *apply_default_whitespace; extern const char *apply_default_whitespace;
extern const char *apply_default_ignorewhitespace; extern const char *apply_default_ignorewhitespace;
extern const char *git_attributes_file; extern const char *git_attributes_file;
extern const char *git_hooks_path;
extern int zlib_compression_level; extern int zlib_compression_level;
extern int core_compression_level; extern int core_compression_level;
extern int core_compression_seen; extern int core_compression_seen;

View File

@ -717,6 +717,9 @@ static int git_default_core_config(const char *var, const char *value)
if (!strcmp(var, "core.attributesfile")) if (!strcmp(var, "core.attributesfile"))
return git_config_pathname(&git_attributes_file, var, value); return git_config_pathname(&git_attributes_file, var, value);
if (!strcmp(var, "core.hookspath"))
return git_config_pathname(&git_hooks_path, var, value);
if (!strcmp(var, "core.bare")) { if (!strcmp(var, "core.bare")) {
is_bare_repository_cfg = git_config_bool(var, value); is_bare_repository_cfg = git_config_bool(var, value);
return 0; return 0;

View File

@ -31,6 +31,7 @@ const char *git_log_output_encoding;
const char *apply_default_whitespace; const char *apply_default_whitespace;
const char *apply_default_ignorewhitespace; const char *apply_default_ignorewhitespace;
const char *git_attributes_file; const char *git_attributes_file;
const char *git_hooks_path;
int zlib_compression_level = Z_BEST_SPEED; int zlib_compression_level = Z_BEST_SPEED;
int core_compression_level; int core_compression_level;
int core_compression_seen; int core_compression_seen;

View File

@ -825,6 +825,9 @@ const char *find_hook(const char *name)
static struct strbuf path = STRBUF_INIT; static struct strbuf path = STRBUF_INIT;
strbuf_reset(&path); strbuf_reset(&path);
if (git_hooks_path)
strbuf_addf(&path, "%s/%s", git_hooks_path, name);
else
strbuf_git_path(&path, "hooks/%s", name); strbuf_git_path(&path, "hooks/%s", name);
if (access(path.buf, X_OK) < 0) if (access(path.buf, X_OK) < 0)
return NULL; return NULL;

37
t/t1350-config-hooks-path.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/sh
test_description='Test the core.hooksPath configuration variable'
. ./test-lib.sh
test_expect_success 'set up a pre-commit hook in core.hooksPath' '
mkdir -p .git/custom-hooks .git/hooks &&
write_script .git/custom-hooks/pre-commit <<-\EOF &&
echo CUSTOM >>actual
EOF
write_script .git/hooks/pre-commit <<-\EOF
echo NORMAL >>actual
EOF
'
test_expect_success 'Check that various forms of specifying core.hooksPath work' '
test_commit no_custom_hook &&
git config core.hooksPath .git/custom-hooks &&
test_commit have_custom_hook &&
git config core.hooksPath .git/custom-hooks/ &&
test_commit have_custom_hook_trailing_slash &&
git config core.hooksPath "$PWD/.git/custom-hooks" &&
test_commit have_custom_hook_abs_path &&
git config core.hooksPath "$PWD/.git/custom-hooks/" &&
test_commit have_custom_hook_abs_path_trailing_slash &&
cat >expect <<-\EOF &&
NORMAL
CUSTOM
CUSTOM
CUSTOM
CUSTOM
EOF
test_cmp expect actual
'
test_done