不细说GitHook

GitHook小记

最近在研究Hook相关的,这里小记一下

Git Hooks 是自动化任务、执行编码标准、执行持续部署和运行测试的绝佳工具,通常与自动化搭配比较多。

什么是Hook?

Hooks 是可以放置在 .git/hooks 目录中的程序,以便在 git 执行某些流程时触发生效(即当仓库中特定事件发生时执行的脚本)。

Git 在提交、推送或合并代码等特定操作之前或之后执行称为“钩子”的脚本。它们允许您在开发过程中自动执行任务、执行策略以及与代码库交互。

Git hooks 通常存储在Git 存储库的.git/hooks目录中, 另外用户还可以通过客户端使用core.hooksPath配置变量来配置它。

目前主要分两种类型, 客户端hook服务端hook

  • 客户端hook: 通常存储在本地,仅针对个人生效,默认没配置,需要自行配置,且没法通过git同步
  • 服务端hook: 通常由Git服务维护,通常不建议修改或没权限修改,例如Gitlab付费版本才支持。另外通常这种由Git服务提供附加功能支持,如Webhook或者Rule来支持类似功能

怎么写Hook脚本

Hook目前对语言没有什么要求,条件允许的情况下,你想用啥就用啥。目前主要比较常见的是bash或者bash+go

如果对Hook脚本不知道怎么写,那么内置的样例脚本是非常有参考价值的,因为他们标注了每个hook需要传入的参数(每个hook有所不同)

git init --bare
cd hooks

进入hooks目录,你会看到如下文件

19:38 ➜  hooks git:(master) tree
.
├── applypatch-msg.sample
├── commit-msg.sample
├── fsmonitor-watchman.sample
├── post-update.sample
├── pre-applypatch.sample
├── pre-commit.sample
├── pre-merge-commit.sample
├── pre-push.sample
├── pre-rebase.sample
├── pre-receive.sample
├── prepare-commit-msg.sample
├── push-to-checkout.sample
├── sendemail-validate.sample
└── update.sample

1 directory, 14 files

大多数可用的hooks就是这些,.sample后缀默认不能执行。为了测试一个hook,你仅仅需要移除.sample后缀。或者,如果你写了一个新脚本,你只需要使用上面这些文件名,去除.sample后缀创建一个文件即可。

客户端常用Hooks

Hooks作用于当前仓库,当你执行git clone时他们不会被复制到新仓库。

如果你的团队需要通过hooks做些什么事,例如提交代码前先进行代码扫描、提交信息是否关联了禅道的需求或者Bug等,这里可能就需要一点技巧来保证你整个团队的hooks是一致的,最新的。

接下来我来简单介绍一下,本地常用的3种hooks

提交前pre-commit

在提交代码之前执行,这种也是用的最多的。

pre-commit中,可以执行各种操作,例如:

  • 代码风格检查:使用工具(如 linters)检查代码是否符合预定义的代码风格规范。
  • 静态代码分析:运行静态代码分析工具,检查代码中的潜在问题和错误。
  • 单元测试:运行单元测试以验证代码的正确性。
  • 格式化代码:自动格式化代码,以确保代码风格的一致性。
  • 检查敏感信息:检查提交的代码中是否包含敏感信息,例如密码、API 密钥等

没有参数传递给pre-commit脚本,并且非零状态时候退出会拒绝本次提交。
可以看看默认的.git/hooks/pre-commit.sample
这个脚本会在遇到空白错误时终止提交,就像git diff-index命令定义的那样(末尾空格、只有空格的行、起始行使用tab产的空格都被默认认为是错误的)

默认情况下,你可能没法感知这个行为,可以给这个脚本添加上Debug即可(set -x), 截取部分如下

#!/bin/bash
set -x
echo "pre commit"

准备提交信息 prepare-commit-msg

用于在创建提交消息(commit message)之前执行操作,

#!/bin/bash

set -x

echo "prepare-commit-msg $@"

1到3个参数需要传递给prepare-commit-msg的脚本

  • 包含提交信息的临时文件名称, 通常是.git/COMMIT_EDITMSG
  • 提交类型。可能是消息提交(使用了-m or -F选型),模板提交(-t选项),合并提交(该提交是一个merge合并提交),或者压缩(squash)提交(该提交是压缩其他提交)。
  • 相关提交的SHA1哈希值,仅仅当被提供-c, -C, 或者 –amend选项时候需要加入这个参数

和pre-commit一样,当非零状态退出时中止提交。

这个hook我用的不多

提交日志 commit-msg

commit-msg跟prepare-commit-msg类似, 但是他用的更多些。
用于在提交消息(commit message)被创建后执行操作。它允许您在提交消息创建完成后运行自定义的脚本或命令,以对提交消息进行验证、格式化或其他处理。

#!/bin/bash

set -x

echo "commit-msg $@"

唯一需要传入的参数是包含这个日志的文件的名称(.git/COMMIT_EDITMSG)

和pre-commit一样,当非零状态退出时中止提交。

#!/bin/bash

set -x

echo "commit-msg $@"

exit 1

服务端hooks

服务端hooks跟本地的基本差不多一样,只不过放在服务端仓库(远端仓库)而已。当hooks放在正式仓库中,那他们就可以用来作为拒绝某些提交的规定的方法了,另外通常情况下这些hooks由服务端维护,个人没有权限编辑或者变更。

接下来我也简单介绍一下,服务端常用的3种hooks

  • 推送接受前(pre-receive
  • 推送更新中(update
  • 推送接受后(post-receive

推送接受前 pre-receive

当使用git push命令推送提交到仓库时,pre-receive就会触发执行

pre-receive钩子脚本中,可以执行各种操作,例如:

  • 验证提交:对即将被推送到远程仓库的提交进行验证,例如检查提交消息、代码规范、权限等。
  • 拒绝推送:如果提交不符合要求,您可以中止推送操作并给出相应的错误提示。
  • 更新参考(refs):在某些情况下,您可以通过修改参考(refs)来实现自定义操作,如更新特定分支或标签。

需要注意的是,pre-receive 是在服务器端执行的,它可以对所有提交进行集中检查和控制。如果脚本返回非零退出码,Git 将拒绝推送操作,并将错误信息返回给推送者。

应用场景:在这里添加任何你想要的开发规定。如果你只希望用公司邮箱用户推送,不喜欢某些格式写的提交信息,或者不喜欢提交里所做的修改,你可以拒绝这个推送。当然你不能限制开发者生成不合格的提交,但是你可以在pre-receive中阻止他们推送不合规的提交到正式仓库

这个脚本不需要入参,但是每个被推送的引用都会按照如下所示的标准输入格式,以一个独立的一行传递给脚本

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

测试脚本

set -x

while read oldrev newrev refname; do
	echo "$refname"
done

尝试推送多个分支,只要任意一个被拒绝,所有推送都会被拒绝

更新推送 update

更新推送在pre-receive之后执行,即在推送接受前(实际更新前)被调用,但是相对pre-receive区别是,你推送几个分支,就会执行几次。

更新推送hook不需要读取标准输入,而是接受三个参数:

  • 正在更新的引用的名称refname
  • 存储在引用里的旧的对象名oldrev
  • 存储在引用里的新的对象名newrev

这里主要更多的是对引用的操作

  • 验证引用更新:对即将被推送到远程仓库的引用更新进行验证,例如检查提交消息、代码规范、权限等。
  • 拒绝推送:如果引用更新不符合要求,您可以中止推送操作并给出相应的错误提示。
  • 更新引用:在某些情况下,您可以通过修改引用来实现自定义操作,如更新特定分支或标签

接受推送后 post-receive

用的不多,更多的是推荐使用webhook

总结

本文只是简单科普githook相关适宜,给大家留个问题,如果你想通过hook实现代码评审,该怎么操作?
后面有空可以给大家细说这个。

Sponsor

Like this article? $1 reward

Comments

According to the relevant laws and regulations of the People's Republic of China, the comment function of the current website has been disabled. If you need to comment, please visit ysicing.me, but the comments still need to be reviewed by AI.