'\" t
.\" Title: git-hook
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot
.\" Date: 2026-06-29
.\" Manual: Git Manual
.\" Source: Git 2.55.0
.\" Language: English
.\"
.TH "GIT\-HOOK" "1" "2026\-06\-29" "Git 2\&.55\&.0" "Git Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
git-hook \- Run Git hooks
.SH "SYNOPSIS"
.sp
.nf
\fIgit hook\fR run [\-\-allow\-unknown\-hook\-name] [\-\-ignore\-missing] [\-\-to\-stdin=] [(\-j|\-\-jobs) ]
[\-\- ]
\fIgit hook\fR list [\-\-allow\-unknown\-hook\-name] [\-z] [\-\-show\-scope]
.fi
.sp
.SH "DESCRIPTION"
.sp
A command interface for running Git hooks (see \fBgithooks\fR(5)), for use by other scripted Git commands\&.
.sp
This command parses the default configuration files for sets of configs like so:
.sp
.if n \{\
.RS 4
.\}
.nf
[hook "linter"]
event = pre\-commit
command = ~/bin/linter \-\-cpp20
.fi
.if n \{\
.RE
.\}
.sp
In this example, [\fBhook\fR "linter"] represents one script \- \fB~/bin/linter\fR \fB\-\-cpp20\fR \- which can be shared by many repos, and even by many hook events, if appropriate\&.
.sp
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:
.sp
.if n \{\
.RS 4
.\}
.nf
[hook "linter"]
event = pre\-commit
command = ~/bin/linter \-\-cpp20
[hook "spellcheck"]
event = commit\-msg
command = ~/bin/spellchecker
.fi
.if n \{\
.RE
.\}
.sp
With this config, when you run \fIgit commit\fR, first \fB~/bin/linter\fR \fB\-\-cpp20\fR will have a chance to check your files to be committed (during the \fBpre\-commit\fR hook event), and then \fB~/bin/spellchecker\fR will have a chance to check your commit message (during the \fBcommit\-msg\fR hook event)\&.
.sp
Commands are run in the order Git encounters their associated \fBhook\&.\fR\fI\fR\fB\&.event\fR configs during the configuration parse (see \fBgit-config\fR(1))\&. Although multiple \fBhook\&.linter\&.event\fR configs can be added, only one \fBhook\&.linter\&.command\fR event is valid \- Git uses "last\-one\-wins" to determine which command to run\&.
.sp
So if you wanted your linter to run when you commit as well as when you push, you would configure it like so:
.sp
.if n \{\
.RS 4
.\}
.nf
[hook "linter"]
event = pre\-commit
event = pre\-push
command = ~/bin/linter \-\-cpp20
.fi
.if n \{\
.RE
.\}
.sp
With this config, \fB~/bin/linter\fR \fB\-\-cpp20\fR would be run by Git before a commit is generated (during \fBpre\-commit\fR) as well as before a push is performed (during \fBpre\-push\fR)\&.
.sp
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:
.sp
.if n \{\
.RS 4
.\}
.nf
[hook "linter"]
event = pre\-commit
command = ~/bin/linter \-\-cpp20
[hook "no\-leaks"]
event = pre\-commit
command = ~/bin/leak\-detector
.fi
.if n \{\
.RE
.\}
.sp
With this config, before a commit is generated (during \fBpre\-commit\fR), Git would first start \fB~/bin/linter\fR \fB\-\-cpp20\fR and second start \fB~/bin/leak\-detector\fR\&. It would evaluate the output of each when deciding whether to proceed with the commit\&.
.sp
For a full list of hook events which you can set your \fBhook\&.\fR\fI\fR\fB\&.event\fR to, and how hooks are invoked during those events, see \fBgithooks\fR(5)\&.
.sp
Git will ignore any \fBhook\&.\fR\fI\fR\fB\&.event\fR that specifies an event it doesn\(cqt 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\&.
.sp
In general, when instructions suggest adding a script to \fB\&.git/hooks/\fR\fI\fR, you can specify it in the config instead by running:
.sp
.if n \{\
.RS 4
.\}
.nf
git config set hook\&.\&.command
git config set \-\-append hook\&.\&.event
.fi
.if n \{\
.RE
.\}
.sp
.sp
This way you can share the script between multiple repos\&. That is, \fBcp\fR \fB~/my\-script\&.sh\fR \fB~/project/\&.git/hooks/pre\-commit\fR would become:
.sp
.if n \{\
.RS 4
.\}
.nf
git config set hook\&.my\-script\&.command ~/my\-script\&.sh
git config set \-\-append hook\&.my\-script\&.event pre\-commit
.fi
.if n \{\
.RE
.\}
.sp
.SH "SUBCOMMANDS"
.PP
run
.RS 4
Runs hooks configured for
\fI\fR, in the order they are discovered during the config parse\&. The default
\fI\fR
from the hookdir is run last\&. See
\fBgithooks\fR(5)
for supported hook names\&.
.sp
Any positional arguments to the hook should be passed after a mandatory
\fB\-\-\fR
(or
\fB\-\-end\-of\-options\fR, see
\fBgitcli\fR(7))\&. See
\fBgithooks\fR(5)
for arguments hooks might expect (if any)\&.
.RE
.PP
list [\-z] [\-\-show\-scope]
.RS 4
Print a list of hooks which will be run on
\fI\fR
event\&. If no hooks are configured for that event, print a warning and return 1\&. Use
\fB\-z\fR
to terminate output lines with NUL instead of newlines\&.
.RE
.SH "OPTIONS"
.PP
\-\-allow\-unknown\-hook\-name
.RS 4
By default
\fBgit\fR
\fBhook\fR
\fBrun\fR
and
\fBgit\fR
\fBhook\fR
\fBlist\fR
will bail out when
\fI\fR
is not a hook event known to Git (see
\fBgithooks\fR(5)
for the list of known hooks)\&. This is meant to help catch typos such as
\fBprereceive\fR
when
\fBpre\-receive\fR
was intended\&. Pass this flag to allow unknown hook names\&.
.RE
.PP
\-\-to\-stdin
.RS 4
For "run"; specify a file which will be streamed into the hook\(cqs stdin\&. The hook will receive the entire file from beginning to EOF\&.
.RE
.PP
\-\-ignore\-missing
.RS 4
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\&.
.RE
.PP
\-z
.RS 4
Terminate "list" output lines with NUL instead of newlines\&.
.RE
.PP
\-\-show\-scope
.RS 4
For "list"; prefix each configured hook\(cqs friendly name with a tab\-separated config scope (e\&.g\&.
\fBlocal\fR,
\fBglobal\fR,
\fBsystem\fR), mirroring the output style of
\fBgit\fR
\fBconfig\fR
\fB\-\-show\-scope\fR\&. Traditional hooks from the hookdir are unaffected\&.
.RE
.PP
\-j, \-\-jobs
.RS 4
Only valid for
\fBrun\fR\&.
.sp
Specify how many hooks to run simultaneously\&. If this flag is not specified, the value of the
\fBhook\&.jobs\fR
config is used, see
\fBgit-config\fR(1)\&. If neither is specified, defaults to 1 (serial execution)\&.
.sp
When greater than 1, it overrides the per\-hook
\fBhook\&.\fR\fI\fR\fB\&.parallel\fR
setting, allowing all hooks for the event to run concurrently, even if they are not individually marked as parallel\&.
.sp
Some hooks always run sequentially regardless of this flag or the
\fBhook\&.jobs\fR
config, because Git knows they cannot safely run in parallel:
\fBapplypatch\-msg\fR,
\fBpre\-commit\fR,
\fBprepare\-commit\-msg\fR,
\fBcommit\-msg\fR,
\fBpost\-commit\fR,
\fBpost\-checkout\fR, and
\fBpush\-to\-checkout\fR\&.
.RE
.SH "WRAPPERS"
.sp
\fBgit\fR \fBhook\fR \fBrun\fR 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\&.
.sp
Assuming your wrapper wants to support a hook named "mywrapper\-start\-tests", you can have your users specify their hooks like so:
.sp
.if n \{\
.RS 4
.\}
.nf
[hook "setup\-test\-dashboard"]
event = mywrapper\-start\-tests
command = ~/mywrapper/setup\-dashboard\&.py \-\-tap
.fi
.if n \{\
.RE
.\}
.sp
Then, in your \fImywrapper\fR tool, you can invoke any users\*(Aq configured hooks by running:
.sp
.if n \{\
.RS 4
.\}
.nf
git hook run \-\-allow\-unknown\-hook\-name mywrapper\-start\-tests \e
# providing something to stdin
\-\-stdin some\-tempfile\-123 \e
# execute multiple hooks in parallel
\-\-jobs 3 \e
# plus some arguments of your own\&.\&.\&.
\-\- \e
\-\-testname bar \e
baz
.fi
.if n \{\
.RE
.\}
.sp
.sp
Take care to name your wrapper\(cqs hook events in a way which is unlikely to overlap with Git\(cqs native hooks (see \fBgithooks\fR(5)) \- a hook event named \(oqmywrappertool\-validate\-commit` is much less likely to be added to native Git than a hook event named \fBvalidate\-commit\fR\&. If Git begins to use a hook event named the same thing as your wrapper hook, it may invoke your users\(cq hooks in unintended and unsupported ways\&.
.SH "CONFIGURATION"
.PP
hook\&.\&.command
.RS 4
The command to execute for
\fBhook\&.\fR\fI\fR\&.
\fI\fR
is a unique name that identifies this hook\&. The hook events that trigger the command are configured with
\fBhook\&.\fR\fI\fR\fB\&.event\fR\&. The value can be an executable path or a shell oneliner\&. If more than one value is specified for the same
\fI\fR, only the last value parsed is used\&.
.RE
.PP
hook\&.\&.event
.RS 4
The hook events that trigger
\fBhook\&.\fR\fI\fR\&. The value is the name of a hook event, like "pre\-commit" or "update"\&. (See
\fBgithooks\fR(5)
for a complete list of hook events\&.) On the specified event, the associated
\fBhook\&.\fR\fI\fR\fB\&.command\fR
is executed\&. This is a multi\-valued key\&. To run
\fBhook\&.\fR\fI\fR
on multiple events, specify the key more than once\&. An empty value resets the list of events, clearing any previously defined events for
\fBhook\&.\fR\fI\fR\&.
.sp
The
\fI\fR
must not be the same as a known hook event name (e\&.g\&. do not use
\fBhook\&.pre\-commit\&.event\fR)\&. Using a known event name as a friendly\-name is a fatal error because it creates an ambiguity with
\fBhook\&.\fR\fI\fR\fB\&.enabled\fR
and
\fBhook\&.\fR\fI\fR\fB\&.jobs\fR\&. For unknown event names, a warning is issued when
\fI\fR
matches the event value\&.
.RE
.PP
hook\&.\&.enabled
.RS 4
Whether the hook
\fBhook\&.\fR\fI\fR
is enabled\&. Defaults to
\fBtrue\fR\&. Set to
\fBfalse\fR
to disable the hook without removing its configuration\&. This is particularly useful when a hook is defined in a system or global config file and needs to be disabled for a specific repository\&.
.RE
.PP
hook\&.\&.parallel
.RS 4
Whether the hook
\fBhook\&.\fR\fI\fR
may run in parallel with other hooks for the same event\&. Defaults to
\fBfalse\fR\&. Set to
\fBtrue\fR
only when the hook script is safe to run concurrently with other hooks for the same event\&. If any hook for an event does not have this set to
\fBtrue\fR, all hooks for that event run sequentially regardless of
\fBhook\&.jobs\fR\&. Only configured (named) hooks need to declare this\&. Traditional hooks found in the hooks directory do not need to, and run in parallel when the effective job count is greater than 1\&.
.RE
.PP
hook\&.\&.enabled
.RS 4
Switch to enable or disable all hooks for the
\fI\fR
hook event\&. When set to
\fBfalse\fR, no hooks fire for that event, regardless of any per\-hook
\fBhook\&.\fR\fI\fR\fB\&.enabled\fR
settings\&. Defaults to
\fBtrue\fR\&.
.sp
Note on naming:
\fI\fR
must be the event name (e\&.g\&.
\fBpre\-commit\fR), not a hook friendly\-name\&. Since using a known event name as a friendly\-name is disallowed (see
\fBhook\&.\fR\fI\fR\fB\&.event\fR
above), there is no ambiguity between event\-level and per\-hook
\fB\&.enabled\fR
settings for known events\&. For unknown events, if a friendly\-name matches the event name despite the warning,
\fB\&.enabled\fR
is treated as per\-hook only\&.
.RE
.PP
hook\&.\&.jobs
.RS 4
Specifies how many hooks can be run simultaneously for the
\fI\fR
hook event (e\&.g\&.
\fBhook\&.post\-receive\&.jobs\fR
\fB=\fR
\fB4\fR)\&. Overrides
\fBhook\&.jobs\fR
for this specific event\&. The same parallelism restrictions apply: this setting has no effect unless all configured hooks for the event have
\fBhook\&.\fR\fI\fR\fB\&.parallel\fR
set to
\fBtrue\fR\&. Set to
\fB\-1\fR
to use the number of available CPU cores\&. Must be a positive integer or
\fB\-1\fR; zero is rejected with a warning\&.
.sp
Note on naming: although this key resembles
\fBhook\&.\fR\fI\fR\fB\&.*\fR
(a per\-hook setting),
\fI\fR
must be the event name, not a hook friendly name\&. The key component is stored literally and looked up by event name at runtime with no translation between the two namespaces\&. A key like
\fBhook\&.my\-hook\&.jobs\fR
is stored under "my\-hook" but the lookup at runtime uses the event name (e\&.g\&. "post\-receive"), so
\fBhook\&.my\-hook\&.jobs\fR
is silently ignored even when
\fBmy\-hook\fR
is registered for that event\&. Use
\fBhook\&.post\-receive\&.jobs\fR
or any other valid event name when setting
\fBhook\&.\fR\fI\fR\fB\&.jobs\fR\&.
.RE
.PP
hook\&.jobs
.RS 4
Specifies how many hooks can be run simultaneously during parallelized hook execution\&. If unspecified, defaults to 1 (serial execution)\&. Set to
\fB\-1\fR
to use the number of available CPU cores\&. Can be overridden on a per\-event basis with
\fBhook\&.\fR\fI\fR\fB\&.jobs\fR\&. Some hooks always run sequentially regardless of this setting because they operate on shared data and cannot safely be parallelized:
.PP
\fBapplypatch\-msg\fR, \fBprepare\-commit\-msg\fR, \fBcommit\-msg\fR
.RS 4
Receive a commit message file and may rewrite it in place\&.
.RE
.PP
\fBpre\-commit\fR, \fBpost\-checkout\fR, \fBpush\-to\-checkout\fR, \fBpost\-commit\fR
.RS 4
Access the working tree, index, or repository state\&.
.RE
.sp
This setting has no effect unless all configured hooks for the event have
\fBhook\&.\fR\fI\fR\fB\&.parallel\fR
set to
\fBtrue\fR\&.
.sp
For
\fBpre\-push\fR
hooks, which normally keep stdout and stderr separate, setting this to a value greater than 1 (or passing
\fB\-j\fR) will merge stdout into stderr to allow correct de\-interleaving of parallel output\&.
.RE
.SH "SEE ALSO"
.sp
\fBgithooks\fR(5)
.SH "GIT"
.sp
Part of the \fBgit\fR(1) suite