章节 ▾ 第二版

8.3 自定义 Git - Git 钩子

Git 钩子

与许多其他版本控制系统类似,Git 可以在某些重要操作发生时触发自定义脚本。这些钩子分为两组:客户端钩子和服务器端钩子。客户端钩子由提交和合并等操作触发,而服务器端钩子则在接收推送提交等网络操作时运行。你可以出于各种原因使用这些钩子。

安装钩子

所有钩子都存储在 Git 目录的 hooks 子目录中。在大多数项目中,它就是 .git/hooks。当你使用 git init 初始化一个新的仓库时,Git 会用一系列示例脚本填充 hooks 目录,其中许多脚本本身就很有用;它们还记录了每个脚本的输入值。所有示例都以 shell 脚本编写,其中也包含一些 Perl,但任何命名正确、可执行的脚本都能正常工作——你可以用 Ruby、Python 或任何你熟悉的语言编写它们。如果你想使用这些捆绑的钩子脚本,你需要重命名它们;它们的文件名都以 .sample 结尾。

要启用一个钩子脚本,请在你的 .git 目录的 hooks 子目录中放置一个命名正确(不带任何扩展名)且可执行的文件。从那时起,它就会被调用。我们将在本节中介绍大多数主要的钩子文件名。

客户端钩子

客户端钩子有很多。本节将它们分为提交工作流钩子、邮件工作流脚本和其他。

注意

需要注意的是,当你克隆仓库时,客户端钩子不会被复制。如果你想通过这些脚本强制执行策略,你可能需要在服务器端进行;请参阅Git 强制策略示例中的示例。

提交工作流钩子

前四个钩子与提交过程有关。

pre-commit 钩子首先运行,甚至在你输入提交信息之前。它用于检查即将提交的快照,看看你是否遗漏了什么,确保测试运行,或检查代码中你需要检查的任何内容。如果此钩子以非零状态退出,则会中止提交,尽管你可以使用 git commit --no-verify 绕过它。你可以做诸如检查代码风格(运行 lint 或类似工具)、检查尾随空格(默认钩子正是这样做的)或检查新方法是否有适当文档之类的事情。

prepare-commit-msg 钩子在提交信息编辑器启动之前但在默认信息创建之后运行。它允许你在提交作者看到默认信息之前对其进行编辑。此钩子接收几个参数:包含当前提交信息的文件路径、提交类型以及(如果是修改提交)提交的 SHA-1 值。此钩子通常不适用于普通提交;相反,它适用于默认信息是自动生成的提交,例如模板提交信息、合并提交、压缩提交和修改提交。你可以将其与提交模板结合使用,以编程方式插入信息。

commit-msg 钩子接收一个参数,它同样是包含开发者编写的提交信息的临时文件路径。如果此脚本以非零状态退出,Git 将中止提交过程,因此你可以使用它在允许提交通过之前验证你的项目状态或提交信息。在本章的最后一部分,我们将演示如何使用此钩子来检查你的提交信息是否符合要求的模式。

整个提交过程完成后,post-commit 钩子会运行。它不接收任何参数,但你可以通过运行 git log -1 HEAD 轻松获取最后一次提交。通常,此脚本用于通知或类似目的。

电子邮件工作流钩子

你可以为基于电子邮件的工作流设置三个客户端钩子。它们都由 git am 命令调用,因此如果你的工作流中没有使用该命令,你可以安全地跳到下一节。如果你正在通过 git format-patch 准备的电子邮件接收补丁,那么其中一些可能会对你有帮助。

第一个运行的钩子是 applypatch-msg。它接收一个参数:包含提议的提交信息的临时文件名。如果此脚本以非零状态退出,Git 将中止补丁。你可以使用此钩子确保提交信息格式正确,或通过让脚本就地编辑来规范化信息。

通过 git am 应用补丁时运行的下一个钩子是 pre-applypatch。有点令人困惑的是,它在补丁应用之后但在提交之前运行,因此你可以使用它在提交之前检查快照。你可以使用此脚本运行测试或检查工作树。如果缺少某些内容或测试不通过,以非零状态退出将中止 git am 脚本,而不提交补丁。

git am 操作期间运行的最后一个钩子是 post-applypatch,它在提交完成后运行。你可以使用它来通知一个组或你拉取的补丁的作者你已完成此操作。你不能用此脚本停止补丁过程。

其他客户端钩子

pre-rebase 钩子在你执行任何 rebase 操作之前运行,并可以通过以非零状态退出中止该过程。你可以使用此钩子来禁止 rebase 任何已经推送的提交。Git 安装的示例 pre-rebase 钩子就是这样做的,尽管它做出了一些可能与你的工作流不符的假设。

post-rewrite 钩子由替换提交的命令运行,例如 git commit --amendgit rebase(但不包括 git filter-branch)。它的唯一参数是哪个命令触发了重写,并且它通过 stdin 接收重写列表。此钩子具有与 post-checkoutpost-merge 钩子许多相同的用途。

成功运行 git checkout 后,post-checkout 钩子会运行;你可以使用它为你的项目环境正确设置工作目录。这可能意味着移动你不希望版本控制的大型二进制文件、自动生成文档或类似的操作。

post-merge 钩子在成功的 merge 命令后运行。你可以使用它来恢复 Git 无法跟踪的工作树中的数据,例如权限数据。此钩子同样可以验证 Git 控制之外的文件是否存在,你可能希望在工作树更改时将其复制进来。

pre-push 钩子在 git push 期间运行,在远程引用更新之后但在任何对象传输之前。它接收远程名称和位置作为参数,并接收通过 stdin 传递的待更新引用列表。你可以使用它在推送发生之前验证一组引用更新(非零退出代码将中止推送)。

Git 作为其正常操作的一部分,偶尔会通过调用 git gc --auto 进行垃圾回收。pre-auto-gc 钩子在垃圾回收发生之前被调用,可用于通知你正在发生此操作,或者在不合适的时候中止回收。

服务器端钩子

除了客户端钩子,作为系统管理员,你还可以使用几个重要的服务器端钩子来为你的项目强制执行几乎任何类型的策略。这些脚本在推送到服务器之前和之后运行。pre 钩子可以随时以非零状态退出以拒绝推送,并向客户端打印错误消息;你可以设置一个你希望的任意复杂的推送策略。

pre-receive

处理来自客户端的推送时运行的第一个脚本是 pre-receive。它接收从标准输入推入的引用列表;如果它以非零状态退出,则所有引用都不会被接受。你可以使用此钩子来做诸如确保所有更新的引用都不是非快进式引用,或者对所有引用及其通过推送修改的文件进行访问控制。

update

update 脚本与 pre-receive 脚本非常相似,不同之处在于它为推送者尝试更新的每个分支运行一次。如果推送者尝试推送到多个分支,pre-receive 只运行一次,而 update 为每个他们正在推送的分支运行一次。此脚本不从标准输入读取,而是接收三个参数:引用(分支)的名称、推送前该引用指向的 SHA-1 值,以及用户尝试推送的 SHA-1 值。如果 update 脚本以非零状态退出,则只有该引用被拒绝;其他引用仍然可以更新。

post-receive

post-receive 钩子在整个过程完成后运行,可用于更新其他服务或通知用户。它接收与 pre-receive 钩子相同的标准输入数据。示例包括向列表发送电子邮件、通知持续集成服务器或更新工单跟踪系统——你甚至可以解析提交信息,查看是否有任何工单需要打开、修改或关闭。此脚本无法停止推送过程,但客户端在它完成之前不会断开连接,因此如果你尝试执行任何可能需要很长时间的操作,请务必小心。

提示

如果你正在编写一个其他人需要阅读的脚本/钩子,请优先使用命令行参数的完整版本;六个月后你就会感谢我们了。

scroll-to-top