summaryrefslogtreecommitdiffstats
path: root/Documentation/git-hook.adoc
blob: 46ea52db55f268f75b6585448e71796c7b980df5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
git-hook(1)
===========

NAME
----
git-hook - Run git hooks

SYNOPSIS
--------
[verse]
'git hook' run [--allow-unknown-hook-name] [--ignore-missing] [--to-stdin=<path>] [(-j|--jobs) <n>]
	<hook-name> [-- <hook-args>]
'git hook' list [--allow-unknown-hook-name] [-z] [--show-scope] <hook-name>

DESCRIPTION
-----------

A command interface for running git hooks (see linkgit:githooks[5]),
for use by other scripted git commands.

This command parses the default configuration files for sets of configs like
so:

  [hook "linter"]
    event = pre-commit
    command = ~/bin/linter --cpp20

In this example, `[hook "linter"]` represents one script - `~/bin/linter
--cpp20` - which can be shared by many repos, and even by many hook events, if
appropriate.

To add an unrelated hook which runs on a different event, for example a
spell-checker for your commit messages, you would write a configuration like so:

  [hook "linter"]
    event = pre-commit
    command = ~/bin/linter --cpp20
  [hook "spellcheck"]
    event = commit-msg
    command = ~/bin/spellchecker

With this config, when you run 'git commit', first `~/bin/linter --cpp20` will
have a chance to check your files to be committed (during the `pre-commit` hook
event`), and then `~/bin/spellchecker` will have a chance to check your commit
message (during the `commit-msg` hook event).

Commands are run in the order Git encounters their associated
`hook.<friendly-name>.event` configs during the configuration parse (see
linkgit:git-config[1]). Although multiple `hook.linter.event` configs can be
added, only one `hook.linter.command` event is valid - Git uses "last-one-wins"
to determine which command to run.

So if you wanted your linter to run when you commit as well as when you push,
you would configure it like so:

  [hook "linter"]
    event = pre-commit
    event = pre-push
    command = ~/bin/linter --cpp20

With this config, `~/bin/linter --cpp20` would be run by Git before a commit is
generated (during `pre-commit`) as well as before a push is performed (during
`pre-push`).

And if you wanted to run your linter as well as a secret-leak detector during
only the "pre-commit" hook event, you would configure it instead like so:

  [hook "linter"]
    event = pre-commit
    command = ~/bin/linter --cpp20
  [hook "no-leaks"]
    event = pre-commit
    command = ~/bin/leak-detector

With this config, before a commit is generated (during `pre-commit`), Git would
first start `~/bin/linter --cpp20` and second start `~/bin/leak-detector`. It
would evaluate the output of each when deciding whether to proceed with the
commit.

For a full list of hook events which you can set your `hook.<friendly-name>.event` to,
and how hooks are invoked during those events, see linkgit:githooks[5].

Git will ignore any `hook.<friendly-name>.event` that specifies an event it doesn't
recognize. This is intended so that tools which wrap Git can use the hook
infrastructure to run their own hooks; see "WRAPPERS" for more guidance.

In general, when instructions suggest adding a script to
`.git/hooks/<hook-event>`, you can specify it in the config instead by running:

----
git config set hook.<some-name>.command <path-to-script>
git config set --append hook.<some-name>.event <hook-event>
----

This way you can share the script between multiple repos. That is, `cp
~/my-script.sh ~/project/.git/hooks/pre-commit` would become:

----
git config set hook.my-script.command ~/my-script.sh
git config set --append hook.my-script.event pre-commit
----

SUBCOMMANDS
-----------

run::
	Runs hooks configured for `<hook-name>`, in the order they are
	discovered during the config parse. The default `<hook-name>` from
	the hookdir is run last. See linkgit:githooks[5] for supported
	hook names.
+

Any positional arguments to the hook should be passed after a
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
linkgit:githooks[5] for arguments hooks might expect (if any).

list [-z] [--show-scope]::
	Print a list of hooks which will be run on `<hook-name>` event. If no
	hooks are configured for that event, print a warning and return 1.
	Use `-z` to terminate output lines with NUL instead of newlines.

OPTIONS
-------

--allow-unknown-hook-name::
	By default `git hook run` and `git hook list` will bail out when
	`<hook-name>` is not a hook event known to Git (see linkgit:githooks[5]
	for the list of known hooks). This is meant to help catch typos
	such as `prereceive` when `pre-receive` was intended. Pass this
	flag to allow unknown hook names.

--to-stdin::
	For "run"; specify a file which will be streamed into the
	hook's stdin. The hook will receive the entire file from
	beginning to EOF.

--ignore-missing::
	Ignore any missing hook by quietly returning zero. Used for
	tools that want to do a blind one-shot run of a hook that may
	or may not be present.

-z::
	Terminate "list" output lines with NUL instead of newlines.

--show-scope::
	For "list"; prefix each configured hook's friendly name with a
	tab-separated config scope (e.g. `local`, `global`, `system`),
	mirroring the output style of `git config --show-scope`. Traditional
	hooks from the hookdir are unaffected.

-j::
--jobs::
	Only valid for `run`.
+
Specify how many hooks to run simultaneously. If this flag is not specified,
the value of the `hook.jobs` config is used, see linkgit:git-config[1]. If
neither is specified, defaults to 1 (serial execution).
+
When greater than 1, it overrides the per-hook `hook.<friendly-name>.parallel`
setting, allowing all hooks for the event to run concurrently, even if they
are not individually marked as parallel.
+
Some hooks always run sequentially regardless of this flag or the
`hook.jobs` config, because git knows they cannot safely run in parallel:
`applypatch-msg`, `pre-commit`, `prepare-commit-msg`, `commit-msg`,
`post-commit`, `post-checkout`, and `push-to-checkout`.

WRAPPERS
--------

`git hook run` has been designed to make it easy for tools which wrap Git to
configure and execute hooks using the Git hook infrastructure. It is possible to
provide arguments and stdin via the command line, as well as specifying parallel
or series execution if the user has provided multiple hooks.

Assuming your wrapper wants to support a hook named "mywrapper-start-tests", you
can have your users specify their hooks like so:

  [hook "setup-test-dashboard"]
    event = mywrapper-start-tests
    command = ~/mywrapper/setup-dashboard.py --tap

Then, in your 'mywrapper' tool, you can invoke any users' configured hooks by
running:

----
git hook run --allow-unknown-hook-name mywrapper-start-tests \
  # providing something to stdin
  --stdin some-tempfile-123 \
  # execute multiple hooks in parallel
  --jobs 3 \
  # plus some arguments of your own...
  -- \
  --testname bar \
  baz
----

Take care to name your wrapper's hook events in a way which is unlikely to
overlap with Git's native hooks (see linkgit:githooks[5]) - a hook event named
`mywrappertool-validate-commit` is much less likely to be added to native Git
than a hook event named `validate-commit`. If Git begins to use a hook event
named the same thing as your wrapper hook, it may invoke your users' hooks in
unintended and unsupported ways.

CONFIGURATION
-------------
include::config/hook.adoc[]

SEE ALSO
--------
linkgit:githooks[5]

GIT
---
Part of the linkgit:git[1] suite