Git钩子脚本能够与代码库一起管理吗?

506
我们希望制作一些基本的钩子脚本,供大家共享 -- 用于诸如预格式化提交消息之类的事情。Git有钩子脚本,通常存储在<project>/.git/hooks/下。但是,这些脚本在克隆时不会被传播,并且它们没有版本控制。
有没有好的方法帮助每个人获取正确的钩子脚本?我可以让这些钩子脚本指向我仓库中版本受控制的脚本吗?

21
好问题。我只希望有更好的答案(无意抱怨@mipadi,只是希望git能够以更自动化的方式解决这个问题,即使只需要在git clone时指定选项也可以)。 - lindes
我同意,@lindes!但也许有意限制这种钩子共享吧?我想对于Windows用户来说会变得混乱。 - kristianlm
@kristianlm:有时候它可能会变得混乱,也有时候它很好用。我只是希望有一些选项或者其他的东西可以复制这些钩子。我想我只能在某个时候查看git-core代码并进行修补了。:)(或者希望其他人这样做...或者使用mipadi的答案中的解决方法,或者其他什么方法。) - lindes
2
pre-commit 可以轻松地管理 pre-commit 钩子。虽然它没有回答 OP 关于管理任意 git 钩子的问题,但是 pre-commit 钩子可能是最常用于代码质量目的的。 - ericsoco
15个回答

342
Git 2.9 中,配置选项 core.hooksPath 指定自定义钩子目录。
将您的钩子移动到存储库中跟踪的 hooks 目录中。然后,配置每个仓库实例使用跟踪的 hooks 来代替 $GIT_DIR/hooks
git config core.hooksPath hooks

一般来说,路径可以是绝对路径,也可以是相对于钩子运行的目录(通常是工作树根目录;请参见man githooks的描述部分)。


17
...并且钩子目录指向可以是一个单独的钩子存储库 ;) - René Link
30
这个配置参数在执行git clone时自动设置吗? - Ring
8
通常情况下,无法通过正在克隆的仓库设置git配置变量。我认为这是为了防止执行任意代码。git config 通过钩子、提交信息上的用户名和其他重要功能来控制代码的执行。 - Max Shenfield
3
如果团队中的某个人切换到另一个分支,该怎么办?他们必须在每个分支中都包含它。 - Abhijeet Khangarot
1
没错。另一方面,如果您在较新的提交中更新钩子,那么在基于该提交构建的分支上工作时,克隆的存储库将自动获取它们。这两种方法都有其优缺点。 - fabb
显示剩余6条评论

165
理论上,您可以在项目目录中创建一个名为hooks(或其他名称)的目录,并在其中放置所有脚本,然后在.git/hooks中创建符号链接。当然,每个克隆存储库的人都必须设置这些符号链接(尽管您可以变得非常高级,并编写一个部署脚本,克隆者可以运行该脚本以进行半自动设置)。
在*nix上执行符号链接所需的全部内容如下:
root="$(pwd)"
ln -s "$root/hooks" "$root/.git/hooks"

如果你准备覆盖 .git/hooks 中的内容,请使用 ln -sf


41
这并不容易,因此我附上一个链接,教您如何正确地创建符号链接:https://dev59.com/QG455IYBdhLWcg3wAvNI - David T.
36
现在,Git 2.9 版本已有一个配置选项 core.hooksPath,可以设置一个位于 .git 之外的文件来链接到钩子文件夹。 - Aaron Rabinowitz

54

对于Node.js用户来说,一个简单的解决方法是更新package.json文件,使用以下内容:

{
  "name": "name",
  "version": "0.0.1",
  ......
  "scripts": {
    "preinstall": "git config core.hooksPath hooks",

preinstall将在执行

npm install

之前运行, 并将Git重定向到查找.\hooks(或您选择的任何名称)目录中的钩子。 该目录应该像.\.git\hooks一样模仿文件名(减去.sample)和结构。

想象一下Maven和其他构建工具都有与preinstall相当的东西。

它还应该适用于所有平台。

如果您需要更多信息,请参见Two ways to share Git hooks with your team


请注意,core.hooksPath 仅适用于 git 版本 >= 2.9(https://dev59.com/TVkS5IYBdhLWcg3w5KAh#39338979)。 - diogo.silva

17

如果您的项目是JavaScript项目,并且使用npm作为包管理器,您可以使用shared-git-hooksnpm install上强制执行Git hooks。

完全透明披露:我编写了这个包。


2
警告 - 不支持 Windows(除非在 git bash 中以管理员身份运行)。简单的解决方案是将“preinstall”:“git config core.hooksPath hooks”添加为 package.json 中的脚本。即,hooks 是包含 git 脚本的文件夹。 - Shane Gannon

12

我想把几个答案合并成一个。假设你在project/目录下:

设置自定义钩子

  1. Create .githooks directory and place your hooks in it. (See .git/hooks for examples)

  2. Create a .gitconfig file that points the directory ¹:

    git config -f .gitconfig core.hooksPath .githooks
    
  3. Create the following rule in your Makefile: ²

    enable-git-hooks:
        git config --local include.path ../.gitconfig
        $(warning REMEMBER, YOU MUST HAVE REVIEWED THE CUSTOM HOOKS!)
    

启用自定义钩子

每个开发人员都应该在审查后明确启用这些自定义钩子。在您的README中添加指令,例如:

通过 make enable-git-hooks 命令,在审查过后启用自定义钩子。


3
你所说的 Makefile 是什么意思?这个问题与编程语言无关。 - Marco Lackovic
3
有人可能会认为Makefile是与语言无关的。 - MKesper

10
大多数现代编程语言,或者说它们的构建工具,都支持插件来管理Git钩子。这意味着你只需要配置你的package.jsonpom.xml等文件,除非他们更改构建文件,否则你团队中的任何人都必须遵守。
插件将为您添加内容到.git目录中。
示例: Git Build Hook Maven Plugin githook-maven-plugin git-hooks-js

我尝试以通用的方式实现这一点,以在我的项目中使用,因此我编写了这个工具:https://pypi.org/project/hooks4git/ - Lovato

4
使用 git-hooks。它将 .git/hooks 路由到项目目录下的脚本 githooks 中。
此外,还有许多功能可帮助您最小化复制和符号链接钩子。

4
我们正在使用Visual Studio解决方案(和项目),其中包含预构建事件和后构建事件。我正在添加一个名为“GitHookDeployer”的附加项目。该项目会在后构建事件中自修改一个文件。该文件设置为复制到构建目录。因此,每次都会构建该项目,且不会被跳过。在构建事件中,它还确保所有git钩子都已就位。
请注意,这不是通用解决方案,因为某些项目当然没有任何东西可供构建。

2
理想情况下,如果您遵循示例文件,钩子应该用Bash编写。但是您可以使用任何可用的语言编写它,并确保它具有可执行标志。
因此,您可以编写Python或Go代码来实现您的目标,并将其放置在hooks文件夹下。它会工作,但它不会与存储库一起管理。
两个选项:
a) 多脚本
您可以在您的帮助中编写您的钩子,并添加一小段代码到钩子中,调用您完美的脚本,像这样:
$ cat .git/hooks/pre-commit
#!/bin/bash
../../hooks/myprecommit.js
单一脚本 更好的选择是只添加一个脚本来控制所有内容,而不是多个脚本。因此,您可以创建一个 hooks/mysuperhook.go 文件,并将您想要的每个钩子指向它。
$ cat .git/hooks/pre-commit
#!/bin/bash
../../hooks/mysuperhook.go $(basename $0)

该参数将为您的脚本提供触发的钩子,并且您可以在代码内部进行区分。为什么?有时您可能希望对提交和推送运行相同的检查,例如。

然后呢?

然后,您可能希望拥有进一步的功能,例如:

  • 手动触发钩子以检查提交或推送之前的一切是否正常。如果只是调用脚本(选项a或b)就可以解决问题。
  • CI上触发钩子,这样您就不需要为CI重新编写相同的检查。例如,只需调用提交和推送触发器即可。与上述相同的方法应该可以解决它。
  • 调用外部工具,如Markdown验证器或YAML验证器。您可以进行系统调用并需要处理标准输出和标准错误。
  • 确保所有开发人员都有一个简单的方法来安装钩子,因此需要将一个好的脚本添加到存储库中以使用正确的默认钩子替换它们。
  • 拥有一些全局助手,例如检查阻止提交到develop和master分支,而不必将其添加到每个存储库中。您可以通过拥有另一个带有全局脚本的存储库来解决它。

这可以更简单吗?

是的,有几个工具可帮助您管理Git钩子。每个工具都针对不同的问题进行了定制,您可能需要了解它们所有的内容,以找到最适合您或您团队的工具。GitHooks.com提供了很多关于钩子的阅读材料,并且目前有几种可用的工具。
截至今天,在那里列出了21个项目,采用不同的策略来管理Git钩子。有些只针对单个钩子,有些针对特定语言等等。
其中一个工具是我编写的,作为一个免费的开源项目提供,称为hooks4git。它是用Python编写的(因为我喜欢它),但其想法是在一个名为.hooks4git.ini的单个配置文件中处理上述所有项目,该文件位于您的存储库内,并可以调用任何您想要调用的脚本,使用任何语言。
使用Git钩子绝对是非常棒的,但通常它们被呈现的方式只会让人望而却步。

我之前发布了一个非常简短的版本,如与版主商定,这里将包含说明,并附上我自己编写的一款工具的简短链接,我认为这可能会帮助其他开发人员。 - Lovato

2
您可以使用类似于 pre-commit 的管理解决方案来管理 pre-commit 钩子。 或者像 Datree.io 这样的集中式解决方案来管理服务器端的 git-hooks。 它具有内置策略,例如:
  1. 检测并防止 合并密码
  2. 强制执行正确的 Git 用户配置
  3. 强制执行 Jira 票据集成 - 在拉取请求名称/提交消息中提及票据编号。
它不会替换所有钩子,但可能会帮助您的开发人员处理最明显的问题,而无需在每个开发人员的计算机/仓库上安装钩子的配置麻烦。
免责声明:我是 Datree 的创始人之一。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接