IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    不细说GitHook

    ysicing (i@ysicing.me)发表于 2024-04-22 12:49:12
    love 0

    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实现代码评审,该怎么操作?
    后面有空可以给大家细说这个。



沪ICP备19023445号-2号
友情链接