雷达智富

首页 > 内容 > 程序笔记 > 正文

程序笔记

具有预提交功能的 Git Hook 管理

2024-07-30 36

Git 提供了一个强大的底层自动化工具:hooks。在本教程中,您将了解预提交框架,该框架可以为脚本集合带来秩序和结构。

使用 Git 并不完全是小事。即使像撤消步骤这样简单的事情也远远超出了简单的撤消快捷方式,但一旦整个团队在存储库中工作,问题的根源就会变得非常高。

Git 本身可以很好地处理简单的“硬”问题,例如合并冲突或丢失更新,并帮助提供令人惊讶的清晰错误消息。然而,当遇到更复杂或“软”的问题时,Git 也无能为力。

示例:假设团队已就特定提交策略达成一致,例如以可理解、有意义的方式并使用指定的格式编写提交消息。然后,无论好坏,你首先必须依赖所有团队成员的可靠性。

这正是 Git 挂钩可以发挥作用并强制正确提交消息的地方 - 或者更确切地说鼓励它们,正如我稍后将使用具体示例展示的那样。

什么是 Git 挂钩?

Git 挂钩本质上是非常简单的东西:根据某些工作流程事件自动执行的脚本。这些脚本可以用任何脚本语言编写,例如用于广泛操作的 Python 或用于较小干预的 Bash 脚本。工作流事件是指各个步骤,例如客户端的提交和推送或服务器端的更新。

使用就像概念一样简单:脚本都位于“./git/hooks”目录中,并具有固定的描述性名称,例如“pre-push”。为了方便起见,许多脚本默认在 hooks 文件夹中都有示例文件。

对于简单的测试,只需在预推送脚本中编写“echo foobar”之类的命令即可;在实际执行push语句之前,终端已经显示消息“foobar”。

不同类型的挂钩

每个钩子都与三个方面相关:它们到底何时执行,即由哪个 git 命令触发?传递哪些参数?该脚本是在客户端还是在远程存储库中运行?下面我展示了通常的 Git 工作流程中最重要的钩子。总共大约有 28 个钩子,这里只讨论 15 个,这些钩子使用得比较频繁。

让我们从由“git am”触发的钩子开始,即通过电子邮件处理补丁时。这里有三个钩子:

  • applypatch-msg:获取以提交消息作为参数的文件名,在设置提交消息之前应用并可以相应地更改它。

  • pre-applypatch:在应用补丁之后但在提交之前应用(例如检查状态)。

  • post-applypatch:可以在提交后使用来分发通知。

“git commit”命令总共调用了四个钩子:

  • 预提交:在提交消息之前运行且不带参数 - 例如检查存储库中所做的更改。

  • prepare-commit-msg: 在发送标准提交消息之后、启动提交消息编辑器之前启动,并接收(最多)三个参数:包含消息的文件的名称、其来源和,如果适用,其哈希值。例如,使用此挂钩可以在提交消息中包含诸如问题标识符之类的内容。

  • commit-msg: 在消息编辑器之后调用,可以再次检查/操作消息 - 此挂钩也用于下面的提交策略。

  • 提交后:在完成提交后在工作流中调用的挂钩,主要用于通知 - 例如向团队分发列表发送电子邮件,告知某些内容已提交。

使用预提交

预提交的工作原理非常简单:框架安装在 Git 存储库中,并通过“git commit”命令触发。然后,它在适当的时间,更准确地说是在特定阶段(提交、推送等)执行已安装的挂钩。

钩子本身可以用几乎任何语言或针对不同的环境编写,包括 Conda、Docker、Dotnet、Node、Lua、Perl、Ruby、Rust、Pygrep,当然还有 Python 和 shell 代码。预提交通常还会处理运行脚本的环境所需的任何依赖项。在某些情况下,例如使用 shell 脚本,用户必须并且可以自行处理。

通过存储钩子,您可以获得更大的灵活性:尽管这些钩子可以本地存储并直接存储在相关存储库中,但默认情况下,它们是从自己的存储库中提取的 - 就像包管理器一样。

Pre-Commit 本身指定安装 Pip、Brew 和 Conda - 然而,Ubuntu 下也显示了 Snap 和 Apt 软件包,这些软件包不是最新的。我建议通过 Pip 安装:

pip install pre-commit

请务必注意任何错误消息;在我们的例子中,安装安装在“~/.local/”目录中,该目录不在路径中。 Apt 版本又像往常一样安装在路径中。如果一切正常,“pre-commit --version ”应该显示版本号。

现在转到所需的存储库。所有配置都发生在“pre-commit-config.yaml”文件中,您可以将其放置在存储库的根目录中。首先,您可以创建一个简单的示例配置,该配置使用预提交挂钩存储库中的一些挂钩:

pre-commit sample-config > .pre-commit-config.yaml

默认情况下简单输出示例配置;您必须像上面那样自己填写 YAML 配置。内容非常简单,以下是演示配置的摘录:

repos:  
- repo: https://github.com/Pre-Commit/Pre-Commit-hooks  
rev: v3.2.0  
hooks:  
- id: trailing-whitespace

因此需要三部分信息:带有钩子的存储库、所需版本的标签以及所需钩子的 ID - 稍后会详细介绍。毫不奇怪,此处加载的钩子会删除行尾不必要的空格。

现在配置已准备就绪,您可以安装预提交:

pre-commit install

使用此命令,“预提交”文件仅存储在“.git/hooks”目录中 - 预提交挂钩因此被激活,并在“git commit”期间使用创建的配置执行预提交。是的,框架、Git 挂钩和实际文件都具有相同的名称“Pre-Commit”,这有点令人困惑。

除了新的提交之外,还可以针对单个文件或只是所有文件手动触发挂钩,这对于新挂钩来说当然是有意义的:

pre-commit run --all-files

这意味着将执行 YAML 配置中指定的所有钩子,并在必要时更改文件 - 每个钩子都通过以下形式的格式良好的输出进行确认:

`Trim Trailing Whitespace.................................................Passed  
- hook id: trailing-whitespace  
exit code: 1  
- files were modified by this hook`

叉钩回购

hooks 存储库基本上只需要包含两件事:hook 脚本本身和另一个 YAML 配置,这里是“pre-commit-hooks.yaml”文件。最好的方法是直接通过 GitHub 界面从预提交项目中分叉已使用的钩子存储库:

repos:  
- repo: https://github.com/IHR-REPO/pre-commit-hooks  
rev: v1.0.0  
hooks:  
- id: trailing-whitespace
- 

然后,工作存储库中的配置需要更新:

pre-commit autoupdate

这会将 pre-commit.yaml 中的 rev 条目设置为最新版本。如果使用您自己的钩子存储库中的预定义和分叉钩子有效,您可以测试您自己的脚本。

使用你自己的钩子

这里的钩子是一个超级简单的 shell 脚本,只需将钩子存储库主目录中的文件“test.sh”中的“foo”替换为“bar”:

#!/bin/bash sed -i ' s/foo/bar/ ' *

然后必须让“pre-commit-hooks.yaml”知道这个钩子 - 为此,您只需复制所看到的“trailing-whitespace”钩子的部分并相应地进行调整:

- id: test  
name: test  
description: testing stuff  
entry: ./test.sh  
language: script  
types: [text]  
stages: [commit, push, manual]

除了名称和 ID 之外,这里还需要更改两个条目:“script”被指定为“语言”,并且对于“entry”,必须设置脚本的路径,相对于钩子存储库的主目录;例如,test.sh 本身位于主目录中。

“类型”和“阶段”的其他条目是可选的;此时,您可以指定挂钩仅考虑文本文件以及应将其限制在哪些阶段。

现在再次需要在 hooks 存储库中创建一个新版本。现在缺少最后一步:必须将新的自定义挂钩添加到工作存储库中的 pre-commit-config.yaml 中:

repos:  
- repo: https://github.com/IHR-REPO/pre-commit-hooks  
rev: v1.0.1  
hooks:  
- id: trailing-whitespace  
- id: test

最终更新后,可以访问测试挂钩。

pre-commit autoupdate

非常重要,尽管不是预提交特定的:脚本必须是可执行的 - 当然这也需要传达给 git。这在使用“git add”添加脚本时有效,但之后也有效:

git update-index --chmod=+x test.sh

最后的话

两个存储库,两个 YAML 配置,一个发布,另一个存储库更新,一个实际上仅使用 Python 作为示例的文档 - 预提交并不完全直观,第一个小时可能会非常令人沮丧,但之后就很棒了工具。


更新于:1个月前
赞一波!1

文章评论

全部评论