简体中文 ▾ 主题 ▾ 最新版本 ▾ githooks 最后更新于 2.54.0

名称

githooks - Git 使用的钩子

概要

$GIT_DIR/hooks/* (或 `git config core.hooksPath`/*)

描述

钩子(Hooks)是您可以放置在钩子目录中,用于在 Git 执行过程中的特定点触发操作的程序。未设置可执行位(executable bit)的钩子将被忽略。

默认情况下,钩子目录是 $GIT_DIR/hooks,但可以通过 core.hooksPath 配置变量进行更改(请参阅 git-config[1])。

在 Git 调用钩子之前,它会将工作目录更改为裸仓库中的 $GIT_DIR,或非裸仓库中工作树的根目录。例外情况是在推送期间触发的钩子(pre-receive, update, post-receive, post-update, push-to-checkout),这些钩子总是在 $GIT_DIR 中执行。

环境变量(如 GIT_DIR, GIT_WORK_TREE 等)会被导出,以便钩子运行的 Git 命令能够正确定位仓库。如果您的钩子需要在外部仓库或同一仓库的不同工作树中调用 Git 命令,则应清除这些环境变量,以免它们干扰外部位置的 Git 操作。例如

local_desc=$(git describe)
foreign_desc=$(unset $(git rev-parse --local-env-vars); git -C ../foreign-repo describe)

钩子可以通过环境变量、命令行参数和标准输入获取参数。详情请参阅下文每个钩子的文档。

git init 可能会根据配置将钩子复制到新仓库。详情请参阅 git-init[1] 中的“模板目录”章节。当本文档后续提到“默认钩子”时,指的是随 Git 发布附带的默认模板。

当前支持的钩子如下所述。

钩子

applypatch-msg

此钩子由 git-am[1] 调用。它接收单个参数:存放建议提交日志消息的文件名。以非零状态退出会导致 git am 在应用补丁前中止。

该钩子允许就地编辑消息文件,可用于将消息规范化为某种项目标准格式。它也可用于在检查消息文件后拒绝提交。

默认的 applypatch-msg 钩子(如果已启用)会运行 commit-msg 钩子(如果后者已启用)。

pre-applypatch

此钩子由 git-am[1] 调用。它不接收任何参数,在应用补丁后、创建提交前被调用。

如果它以非零状态退出,则补丁应用后工作树将不会被提交。

它可用于检查当前工作树,并在无法通过某些测试时拒绝提交。

默认的 pre-applypatch 钩子(如果已启用)会运行 pre-commit 钩子(如果后者已启用)。

post-applypatch

此钩子由 git-am[1] 调用。它不接收任何参数,在补丁被应用且提交已完成后被调用。

此钩子主要用于通知,不会影响 git am 的结果。

pre-commit

此钩子由 git-commit[1] 调用,可通过 --no-verify 选项绕过。它不接收任何参数,在获取建议的提交日志消息和进行提交之前被调用。从此脚本中以非零状态退出会导致 git commit 命令在创建提交之前中止。

所有 git commit 钩子在调用时,如果命令不会调出编辑器来修改提交消息,则会带有环境变量 GIT_EDITOR=:

默认的 pre-commit 钩子(如果已启用)会阻止引入非 ASCII 文件名以及带有行尾空格的行。非 ASCII 检查可以通过将 hooks.allownonascii 配置选项设置为 true 来关闭。

pre-merge-commit

此钩子由 git-merge[1] 调用,可通过 --no-verify 选项绕过。它不接收任何参数,在合并成功执行后、获取建议的提交日志消息以进行提交之前被调用。从此脚本中以非零状态退出会导致 git merge 命令在创建提交之前中止。

默认的 pre-merge-commit 钩子(如果已启用)会运行 pre-commit 钩子(如果后者已启用)。

此钩子调用时带有环境变量 GIT_EDITOR=:,如果命令不会调出编辑器来修改提交消息的话。

如果合并无法自动执行,则需要解决冲突并分别提交结果(请参阅 git-merge[1])。此时,该钩子不会被执行,但如果已启用 pre-commit 钩子,它会被执行。

prepare-commit-msg

此钩子由 git-commit[1] 在准备好默认日志消息后、编辑器启动前被调用。

它接收一到三个参数。第一个是包含提交日志消息的文件名。第二个是提交消息的来源,可以是:message(如果给出了 -m-F 选项);template(如果给出了 -t 选项或设置了配置选项 commit.template);merge(如果提交是合并提交或存在 .git/MERGE_MSG 文件);squash(如果存在 .git/SQUASH_MSG 文件);或 commit 后跟提交对象名称(如果给出了 -c, -C--amend 选项)。

如果退出状态非零,git commit 将中止。

该钩子的目的是就地编辑消息文件,它不会被 --no-verify 选项抑制。非零退出意味着钩子失败并会中止提交。它不应被用作 pre-commit 钩子的替代品。

随 Git 附带的示例 prepare-commit-msg 钩子会移除提交模板注释部分中找到的帮助信息。

commit-msg

此钩子由 git-commit[1]git-merge[1] 调用,可通过 --no-verify 选项绕过。它接收单个参数:存放建议提交日志消息的文件名。以非零状态退出会导致命令中止。

该钩子允许就地编辑消息文件,可用于将消息规范化为某种项目标准格式。它也可用于在检查消息文件后拒绝提交。

默认的 commit-msg 钩子(如果已启用)会检测重复的 Signed-off-by 尾注,如果发现重复则会中止提交。

post-commit

此钩子由 git-commit[1] 调用。它不接收参数,在提交完成后被调用。

此钩子主要用于通知,不会影响 git commit 的结果。

pre-rebase

此钩子由 git-rebase[1] 调用,可用于防止某个分支被变基。该钩子可能接收一个或两个参数。第一个参数是分支从中分叉出来的上游。第二个参数是要变基的分支,当变基当前分支时不会设置该参数。

post-checkout

此钩子在 git-checkout[1]git-switch[1] 更新工作树后被调用。该钩子接收三个参数:上一个 HEAD 的引用、新 HEAD 的引用(可能已更改,也可能未更改),以及一个标志,指示这次检出是分支检出(更改分支,flag=1)还是文件检出(从索引中检索文件,flag=0)。此钩子无法影响 git switchgit checkout 的结果,除了钩子的退出状态会成为这两个命令的退出状态。

它也会在 git-clone[1] 之后运行,除非使用了 --no-checkout (-n) 选项。给钩子的第一个参数是空引用(null-ref),第二个是新 HEAD 的引用,标志始终为 1。对于 git worktree add 也是如此,除非使用了 --no-checkout

此钩子可用于执行仓库有效性检查、自动显示与上一个 HEAD 不同时的差异,或设置工作目录元数据属性。

post-merge

此钩子由 git-merge[1] 调用,当在本地仓库执行 git pull 时会发生这种情况。该钩子接收一个参数,即一个状态标志,指定所执行的合并是否为压缩合并(squash merge)。此钩子无法影响 git merge 的结果,如果合并因冲突而失败,则不会执行此钩子。

此钩子可与相应的 pre-commit 钩子结合使用,以保存和恢复与工作树关联的任何形式的元数据(例如:权限/所有权、ACL 等)。有关如何执行此操作的示例,请参阅 contrib/hooks/setgitperms.perl。

pre-push

此钩子由 git-push[1] 调用,可用于阻止推送发生。该钩子接收两个参数,提供目标远程的名称和位置;如果没有使用命名的远程,这两个值将相同。

关于要推送内容的信息通过钩子的标准输入提供,格式如下行:

<local-ref> SP <local-object-name> SP <remote-ref> SP <remote-object-name> LF

例如,如果运行命令 git push origin master:foreign,钩子将收到如下行:

refs/heads/master 67890 refs/heads/foreign 12345

虽然会提供完整的对象名称。如果远程引用尚不存在,<remote-object-name> 将是全零对象名。如果要删除引用,<local-ref> 将作为 (delete) 提供,而 <local-object-name> 将是全零对象名。如果本地提交是由除可以展开的名称以外的其他内容指定的(例如 HEAD~ 或对象名),它将按原样提供。

如果此钩子以非零状态退出,git push 将在不推送任何内容的情况下中止。关于推送被拒绝原因的信息可以通过写入标准错误发送给用户。

pre-receive

此钩子由 git-receive-pack[1] 在响应 git push 并更新其仓库中的引用时调用。就在开始更新远程仓库上的引用之前,pre-receive 钩子被调用。其退出状态决定了更新的成功或失败。

此钩子为每个接收操作执行一次。它不接收参数,但对于每个要更新的引用,它会在标准输入上收到一行格式为:

<old-oid> SP <new-oid> SP <ref-name> LF

其中 <old-oid> 是存储在引用中的旧对象名,<new-oid> 是要存储在引用中的新对象名,<ref-name> 是引用的全名。创建新引用时,<old-oid> 是全零对象名。

如果钩子以非零状态退出,则没有任何引用会被更新。如果钩子以零状态退出,对单个引用的更新仍然可以被 update 钩子阻止。

标准输出和标准错误输出都会转发到另一端的 git send-pack,因此您可以简单地为用户 echo 消息。

git push --push-option=... 命令行上给出的推送选项数量可以从环境变量 GIT_PUSH_OPTION_COUNT 读取,选项本身可在 GIT_PUSH_OPTION_0, GIT_PUSH_OPTION_1 等中找到。如果协商结果是不使用推送选项阶段,则这些环境变量将不会设置。如果客户端选择使用推送选项但没有传输任何选项,则计数变量将设置为零,GIT_PUSH_OPTION_COUNT=0

请参阅 git-receive-pack[1] 中关于“隔离环境”的章节以了解一些注意事项。

update

此钩子由 git-receive-pack[1] 在响应 git push 并更新其仓库中的引用时调用。就在更新远程仓库上的引用之前,update 钩子被调用。其退出状态决定了引用更新的成功或失败。

此钩子为每个要更新的引用执行一次,并接收三个参数:

  • 正在更新的引用名称,

  • 存储在引用中的旧对象名,

  • 以及要存储在引用中的新对象名。

从 update 钩子零状态退出允许更新该引用。以非零状态退出则会阻止 git receive-pack 更新该引用。

此钩子可用于防止某些引用上的强制更新,通过确保对象名称是一个作为旧对象名所命名的提交对象的后代的提交对象。即,强制执行“仅限快进(fast-forward only)”策略。

它也可以用来记录 old..new 状态。然而,因为它不知道分支的整个集合,所以如果简单地使用,它最终会为每个引用发送一封电子邮件。post-receive 钩子更适合此目的。

在仅限制用户通过网络访问 git 命令的环境中,此钩子可用于实现访问控制,而不依赖于文件系统所有权和组成员资格。有关如何使用登录 shell 将用户访问权限限制为仅限 git 命令,请参阅 git-shell[1]

标准输出和标准错误输出都会转发到另一端的 git send-pack,因此您可以简单地为用户 echo 消息。

默认的 update 钩子(如果已启用,且 hooks.allowunannotated 配置选项未设置或设置为 false)会阻止推送未注释的标签。

proc-receive

此钩子由 git-receive-pack[1] 调用。如果服务器设置了多值配置变量 receive.procReceiveRefs,并且发送给 receive-pack 的命令具有匹配的引用名称,则这些命令将由该钩子执行,而不是由内部的 execute_commands() 函数执行。此钩子负责更新相关的引用并将结果报告回 receive-pack

此钩子为接收操作执行一次。它不接收参数,但使用 pkt-line 格式协议与 receive-pack 通信以读取命令、推送选项并发送结果。在以下协议示例中,字母 S 代表 receive-pack,字母 H 代表此钩子。

# Version and features negotiation.
S: PKT-LINE(version=1\0push-options atomic...)
S: flush-pkt
H: PKT-LINE(version=1\0push-options...)
H: flush-pkt
# Send commands from server to the hook.
S: PKT-LINE(<old-oid> <new-oid> <ref>)
S: ... ...
S: flush-pkt
# Send push-options only if the 'push-options' feature is enabled.
S: PKT-LINE(push-option)
S: ... ...
S: flush-pkt
# Receive results from the hook.
# OK, run this command successfully.
H: PKT-LINE(ok <ref>)
# NO, I reject it.
H: PKT-LINE(ng <ref> <reason>)
# Fall through, let 'receive-pack' execute it.
H: PKT-LINE(ok <ref>)
H: PKT-LINE(option fall-through)
# OK, but has an alternate reference.  The alternate reference name
# and other status can be given in option directives.
H: PKT-LINE(ok <ref>)
H: PKT-LINE(option refname <refname>)
H: PKT-LINE(option old-oid <old-oid>)
H: PKT-LINE(option new-oid <new-oid>)
H: PKT-LINE(option forced-update)
H: ... ...
H: flush-pkt

proc-receive 钩子的每个命令都可能指向伪引用,且旧对象名(old-oid)总是零。而 proc-receive 钩子可以更新备用引用,并且备用引用可能已经存在一个非零的旧对象名。在这种情况下,此钩子将使用“option”指令来报告由领先的“ok”指令给出的引用的扩展属性。

此钩子命令的报告顺序应与输入相同。proc-receive 钩子的退出状态仅决定发送给它的一组命令的成功或失败,除非正在使用原子推送(atomic push)。

post-receive

此钩子由 git-receive-pack[1] 在响应 git push 并更新其仓库中的引用时调用。该钩子在远程仓库上执行一次,在所有建议的引用更新处理完毕且至少有一个引用被成功更新后执行。

该钩子不接收参数。它为每个成功更新的引用在标准输入上接收一行,格式与 pre-receive 钩子相同。

此钩子不会影响 git receive-pack 的结果,因为它是在实际工作完成后调用的。

这取代了 post-update 钩子,因为它不仅获得引用的名称,还获得了所有引用的旧值和新值。

标准输出和标准错误输出都会转发到另一端的 git send-pack,因此您可以简单地为用户 echo 消息。

默认的 post-receive 钩子为空,但在 Git 发行版的 contrib/hooks 目录中提供了一个示例脚本 post-receive-email,它实现了发送提交邮件的功能。

git push --push-option=... 命令行上给出的推送选项数量可以从环境变量 GIT_PUSH_OPTION_COUNT 读取,选项本身可在 GIT_PUSH_OPTION_0, GIT_PUSH_OPTION_1 等中找到。如果协商结果是不使用推送选项阶段,则这些环境变量将不会设置。如果客户端选择使用推送选项但没有传输任何选项,则计数变量将设置为零,GIT_PUSH_OPTION_COUNT=0

有关其他详细信息,请参阅 git-receive-pack[1] 中的“post-receive”章节。

post-update

此钩子由 git-receive-pack[1] 在响应 git push 并更新其仓库中的引用时调用。它在所有引用更新后在远程仓库上执行一次。

它接收可变数量的参数,每个参数都是实际更新的引用名称。

此钩子主要用于通知,不能影响 git receive-pack 的结果。

post-update 钩子可以知道哪些头(heads)被推送了,但它不知道它们的原始值和更新后的值是多少,因此它是记录 old..new 的糟糕位置。post-receive 钩子确实获得了引用的原始值和更新值。如果您需要这些值,可以考虑改用它。

启用时,默认的 post-update 钩子运行 git update-server-info 以保持哑传输(如 HTTP)使用的信息是最新的。如果您发布了可通过 HTTP 访问的 Git 仓库,则可能应该启用此钩子。

标准输出和标准错误输出都会转发到另一端的 git send-pack,因此您可以简单地为用户 echo 消息。

reference-transaction

此钩子由任何执行引用更新的 Git 命令调用。只要引用事务正在准备、已准备、已提交或已中止,它就会执行,因此可能会被调用多次。该钩子还支持符号引用更新。

该钩子接收恰好一个参数,即给定引用事务当前所处的状态:

  • "preparing": 所有引用更新已加入事务队列,但引用尚未在磁盘上锁定。

  • "prepared": 所有引用更新已加入事务队列,并且引用已在磁盘上锁定。

  • "committed": 引用事务已提交,所有引用现在都有各自的新值。

  • "aborted": 引用事务已中止,没有执行任何更改,锁已释放。

对于添加到事务中的每个引用更新,钩子会在标准输入上收到一行格式为:

<old-value> SP <new-value> SP <ref-name> LF

其中 <old-value> 是传递到引用事务中的旧对象名,<new-value> 是要存储在引用中的新对象名,<ref-name> 是引用的全名。当无论当前值如何而强制更新引用或创建新引用时,<old-value> 是全零对象名。为了区分这些情况,您可以通过 git rev-parse 检查 <ref-name> 的当前值。在“preparing”状态期间,符号引用不会被解析:<ref-name> 将反映符号引用本身,而不是它指向的对象。

对于符号引用更新,<old_value><new-value> 字段可以表示引用而不是对象。引用将以 ref: 为前缀表示,如 ref:<ref-target>

除“preparing”和“prepared”状态外,钩子的退出状态会被忽略。在这些状态下,非零退出状态将导致事务中止。在这种情况下,钩子将不会以“aborted”状态被调用。

push-to-checkout

此钩子由 git-receive-pack[1] 在响应 git push 并更新其仓库中的引用,且推送试图更新当前检出的分支,并且 receive.denyCurrentBranch 配置变量设置为 updateInstead 时调用。如果远程仓库的工作树和索引与当前检出的提交有任何不同,默认情况下此类推送会被拒绝;当工作树和索引都与当前提交匹配时,它们会被更新以匹配新推送的分支末端。此钩子用于覆盖默认行为。

该钩子接收当前分支末端即将更新到的提交。它可以以非零状态退出以拒绝推送(这样做时,它不能修改索引或工作树)。或者,它可以对工作树和索引进行任何必要的更改,使其在当前分支末端更新为新提交时达到所需状态,并以零状态退出。

例如,该钩子可以简单地运行 git read-tree -u -m HEAD "$1",以模拟与 git push 相反方向运行的 git fetch,因为 git read-tree -u -m 的双树形式本质上与 git switchgit checkout 相同,它们在切换分支的同时保留工作树中不干扰分支间差异的本地更改。

pre-auto-gc

此钩子由 git gc --auto 调用(请参阅 git-gc[1])。它不接收参数,从此脚本以非零状态退出会导致 git gc --auto 中止。

post-rewrite

此钩子由重写提交的命令调用(调用 --amend 时的 git-commit[1]git-rebase[1];但是,像 git-fast-import[1]git-filter-repo 这样的全历史(重)写工具通常不会调用它!)。它的第一个参数表示调用它的命令:目前为 amendrebase 之一。将来可能会传递更多依赖于命令的参数。

该钩子在标准输入上接收重写后的提交列表,格式为:

<old-object-name> SP <new-object-name> [ SP <extra-info> ] LF

extra-info 再次取决于命令。如果它为空,则前面的 SP 也会省略。目前,没有任何命令传递任何 extra-info

该钩子总是在自动注释复制(请参阅 git-config[1] 中的 "notes.rewrite.<command>")发生后运行,因此可以访问这些注释。

以下特定于命令的注释适用:

rebase

对于 squashfixup 操作,所有被压缩的提交都被列为重写为压缩后的提交。这意味着会有多行共享同一个 new-object-name

提交保证按 rebase 处理它们的顺序排列。

sendemail-validate

此钩子由 git-send-email[1] 调用。

它接收这些命令行参数。它们是:1. 存放要发送的电子邮件内容的文件名。2. 存放电子邮件 SMTP 头的文件名。

SMTP 头以与传递给用户邮件传输代理 (MTA) 完全相同的方式传递。实际上,给用户 MTA 的电子邮件是 $2 的内容后跟 $1 的内容。

下面显示了一些常见头的示例。请注意大小写和多行制表符结构。

From: Example <from@example.com>
To: to@example.com
Cc: cc@example.com,
 A <author@example.com>,
 One <one@example.com>,
 two@example.com
Subject: PATCH-STRING

以非零状态退出会导致 git send-email 在发送任何电子邮件之前中止。

执行钩子时会设置以下环境变量。

GIT_SENDEMAIL_FILE_COUNTER

一个从 1 开始的计数器,每处理一个存放待发送电子邮件的文件(不包括任何 FIFO)时递增 1。此计数器不遵循补丁系列计数方案。它将始终从 1 开始,并以 GIT_SENDEMAIL_FILE_TOTAL 结束。

GIT_SENDEMAIL_FILE_TOTAL

将要发送的文件总数(不包括任何 FIFO)。此计数器不遵循补丁系列计数方案。它将始终等于正在发送的文件数,无论是否有封面信(cover letter)。

这些变量可以例如用于验证补丁系列。

随 Git 附带的示例 sendemail-validate 钩子检查所有已发送的补丁(不包括封面信)是否可以在上游仓库默认分支之上无冲突地应用。留有一些占位符,用于在给定系列的所有补丁应用后执行额外的验证步骤。

fsmonitor-watchman

此钩子在配置选项 core.fsmonitor 设置为 .git/hooks/fsmonitor-watchman.git/hooks/fsmonitor-watchmanv2(取决于要使用的钩子版本)时调用。

版本 1 接收两个参数:版本 (1) 和自 1970 年 1 月 1 日午夜以来的纳秒流逝时间。

版本 2 接收两个参数:版本 (2) 和用于标识自该令牌以来更改的令牌。对于 watchman,这将是一个时钟 ID。此版本必须在文件列表之前向 stdout 输出新令牌,后跟一个 NUL 字符。

钩子应将自请求时间以来可能已更改的工作目录中的所有文件列表输出到 stdout。逻辑应具有包容性,以免错过任何潜在的更改。路径应相对于工作目录的根目录,并用单个 NUL 分隔。

包含实际上未更改的文件是可以的。应包括所有更改,包括新创建和删除的文件。当文件重命名时,应包括旧名称和新名称。

Git 将限制其检查更改的文件以及根据给定的路径名检查哪些目录是否存在未跟踪文件。

告诉 git “所有文件都已更改”的一种优化方法是返回文件名 /

退出状态决定了 git 是否将使用来自钩子的数据来限制其搜索。出错时,它将回退到验证所有文件和文件夹。

p4-changelist

此钩子由 git-p4 submit 调用。

p4-changelist 钩子在变更列表消息被用户编辑后执行。它可以通过 --no-verify 选项绕过。它接收单个参数:存放建议变更列表文本的文件名。以非零状态退出会导致命令中止。

钩子允许编辑变更列表文件,并可用于将文本规范化为某种项目标准格式。它也可用于在检查消息文件后拒绝提交(Submit)。

运行 git-p4 submit --help 以获取详细信息。

p4-prepare-changelist

此钩子由 git-p4 submit 调用。

p4-prepare-changelist 钩子在准备默认变更列表消息后、编辑器启动前执行。它接收一个参数:包含变更列表文本的文件名。从脚本以非零状态退出将中止该过程。

该钩子的目的是就地编辑消息文件,且不会被 --no-verify 选项抑制。即使设置了 --prepare-p4-only,也会调用此钩子。

运行 git-p4 submit --help 以获取详细信息。

p4-post-changelist

此钩子由 git-p4 submit 调用。

p4-post-changelist 钩子在 P4 中成功提交后调用。它不接收参数,主要用于通知,不能影响 git p4 提交操作的结果。

运行 git-p4 submit --help 以获取详细信息。

p4-pre-submit

此钩子由 git-p4 submit 调用。它不接收参数,也不从标准输入接收任何内容。从该脚本以非零状态退出会阻止 git-p4 submit 启动。它可以通过 --no-verify 命令行选项绕过。运行 git-p4 submit --help 以获取详细信息。

post-index-change

此钩子在索引被写入 read-cache.c do_write_locked_index 时调用。

传递给钩子的第一个参数是工作目录被更新的指示器。“1”表示工作目录已更新,“0”表示工作目录未更新。

传递给钩子的第二个参数是索引是否被更新以及 skip-worktree 位是否可能已更改的指示器。“1”表示 skip-worktree 位可能已更新,“0”表示它们未更新。

当钩子运行时,只有一个参数应该设置为“1”。钩子运行并传递“1”, "1" 是不可能的。

另请参阅

GIT

Git[1] 套件的一部分