头图

💡 如何巧用 Git Hook,解决代码提交中的代码规范性、冲突和错误以及工作流程问题?

近日,在极狐Tech Talk 直播上,极狐(GitLab) 后端工程师田鲁分享了自己的实践经验。以下内容整理自本次直播,你也可以点击文末「阅读原文」观看视频回放。Enjoy~

在开发过程中,开发人员提交代码后,需要继续做很多工作,因此我们不由萌生一个问题:是否可以把一些工作前置处理,减少等待时间?

首先,我们先回顾一下常见的代码流程:

1. 开发人员在本地编写代码之后,执行 Git Commit 操作 ,保存本地仓库;

2. 将代码推送到远端服务器,触发 CI Pipeline,执行 Pipeline 中各阶段任务:Build、Unit test、Integration test;

3. 执行 CD Pipeline 阶段任务:Review、Staging、Production。

在该流程中,若在本地发现问题,修复起来时间相对较短;若在远程执行 Pipeline 后才发现问题,则修复时间较长,并且增加了服务器的压力。

那么是否可以将一些工作提前,如在中间部分(如上图)完成来提高本地效率,缩短开发流程呢?如题所言“向前一步”,即把原本在 CI 中执行的部分工作,放在本地执行。

代码流程中的后置处理之痛

常见代码开发过程中,通常依赖于后置处理,即开发人员的代码提交到 Git 上以后,运行 CI/CD 或者 Code Review 过程中才发现常见问题,包括:

  • 代码规范 → 花大量时间沟通达成一致;
  • 冲突与错误 → 提交后发现与主分支冲突,需要重复修改代码和提交;
  • 敏感误提交 → 可能造成安全事故;
  • 缺少自动化任务 → 手动执行,容易遗忘。

这样既浪费了 CI/CD 资源,也花费了不必要的时间,导致开发效率低。

举个🌰,如下图极狐GitLab 中的 Pipelines,在构建作业 → 测试 → 发布的环节中,我们需要等上传测试后才能发现错误,接着在本地修改,再把 Pipeline 推送上来,才能确认这个错误是否被修复;若没有修复,则需要重复修改,直至修复完成,这个过程耗费很多时间。

可能大家会想到,对团队成员进行口头约束,或从制度上要求开发人员必须自己做检测,但这些几乎是流于形式。

那么,极狐GitLab 如何处理解决这些问题的?

极狐GitLab 自动化流程落实前置处理

极狐GitLab 通过自动化流程,高效落实开发工作,让团队协作更流畅

  • 代码规范性问题
    在提交代码前,运行代码风格检查和自动化测试等脚本,帮助开发人员发现并修复代码中的规范性问题,从而保证代码的质量和可维护性。
  • 冲突和错误问题
    在提交代码前运行 Git Hook,帮助开发人员避免将错误或不规范的代码推送到代码仓库中,从而减少代码冲突和错误。
  • 工作流程问题
    开发人员规范化 Git 工作流程,提高工作效率和协作效果。通过配置 Git Hook,可以自动化执行代码检查、测试、构建和部署等任务,避免手动操作繁琐和出错。

极狐GitLab 在具体实践中逐步完善了该自动化流程,从而确保研发任务能更有效执行。这部分在极狐GitLab 的文档里也有更具体说明,感兴趣的小伙伴可以查阅我们的资源与文档

前置处理的关键方法:Git Hook

与许多其他版本控制系统一样,Git 有一种方法可以在发生某些重要操作时,触发自定义脚本,即 Git Hook(Git 钩子)。

当我们初始化一个项目之后,.git 目录下有一个 hooks 目录,可以看到上图左侧有很多执行任务,比如 pre-commit,代表在运行这些命令之后或之前,会进行一些校验和检测来执行相应任务。

Git Hook 分为两部分:本地和远程,如下图所示:

本地 Git Hook,由提交和合并等操作触发

  • 比如代码发生变更,进行 git add,把 message 进行 commit changes;
  • 当 git commit 时,就会执行一个钩子叫 pre-commit(准备提交钩子)。

远程 Git Hook,运行在网络操作上,例如接收推送的提交

  • 在 commit 之后,要推送到远端,此时有一个叫 pre-push 钩子,把信息推送 git 仓库;
  • 在远程阶段,极狐GitLab 相当于一个远程仓库。如图有很多仓库,分别承担不同功能,比如 pre-receive ,主要在服务器端接收通过本地推上来代码,然后 update 相关代码,post-receive 说明代码接受成功,同时有一个服务器钩子执行。

在这里,我们主要关注本地 hook,比如说 pre-message 和 pre-push,因此我们会借助这些工具来实现规范化代码内容。

提前进行代码规范检测

极狐GitLab 是一个非常大的代码仓库,包含前端代码、后端代码,还有运维相关代码:

  • 前端代码如 ESlint、Jsonlint、HAML-lint、Markdown-lint;
  • Ruby 相关的如 RuboCop、Stylelint;
  • Yaml 相关的如 Yaml-lint。

当然也支持不同语言项目,像 Python、Java 或者其它编程语言,也会有相应代码规范要求,可以自己添加。

每个 Lint 都会去检测代码中的变动,从而检测代码是否符合预期。只有符合预期的代码,才能够推送进来,避免代码提交之后,再发现代码规范问题,在反复修改上浪费时间

这就好比整个代码仓库是房子,代码是水,Lint 相当于过滤器,必须让这些代码经过过滤后,才能从水龙头流出,成为生活用水。

提前进行代码安全检测

下图展示的是 GitHub 安全事故:很多人在测试或调试代码过程中,把一些 Token 放在里面,无意识地推送到仓库中,导致 API 和加密密钥泄露,这很容易被人发现和利用,进而造成巨大损失。

极狐GitLab 十分注重代码安全,我们必须想办法阻止开发人员将密钥提交到仓库,也就是必须在 Commit 之前,阻止开发人员把密钥信息给放到 Git 历史记录中。

那么,常见的安全代码检测工具有哪些?这里给大家提供一个参考,就是 Gitleaks。

Gitleaks 是一个 SAST 静态代码检测工具,检测代码中常见的 Secret、Token、Password 等内容,生成 Secret 检测报告产物,避免误提交,提高研发安全性。

提前进行自动化内容检测

上述代码规范检测、代码安全检测,都是在代码提交前,及时发现问题和解决问题,提升代码质量和安全性。自动化内容检测偏向于常规性内容检测,例如:

  • gettext:查找未翻译的内容,提示开发人员及时翻译;
  • docs-metadata:提醒开发人员为文本添加描述等;
  • graphql-doc:检测 graphql 的 doc 是否完整;

自动化内容检测避免代码提交到在服务器后再去修改内容,也是提高开发效率的手段之一。

上述 3 个步骤放在本地开发阶段执行,基于以下原因,开发效率就会有很大提升,甚至整个运行时间降低 50%,同时更高效地提升了代码质量

  • 本地运行速度快;
  • 及时发现问题,减少沟通协作成本;
  • 节省 Code Review 时间;
  • 节省 CI/CD 运行资源。

友好的 Git Hook 管理工具:Lefthook

我们可以使用 Git Hook 里的 bash 脚本来编写,比如前面提到的 Eslint、Stylelint 等,但是这种方式有个比较大的缺点:无法放在仓库中,则无法看到变更历史,也不方便分发,而且可能不是每个开发人员都熟悉脚本的开发。

因此,我们可能需要更友好的 Git Hook 管理工具,这里推荐工具:Lefthook。

什么是 Lefthook?

Lefthook 是一个开源的 Git Hook 管理工具,帮助开发人员自动化和规范化 Git 工作流程。

Lefthook 具备以下特点:

1.  支持多种编程语言:包括 Python、JavaScript、Ruby、Go、Java 等;

2.  简单易用:轻松安装和配置,使用过程也非常简单;

3.  高灵活性:允许用户在 Git Hook 中使用任何语言和工具,而不仅仅是 shell 脚本;

4.  高可扩展性:可与其他工具和系统集成,比如 CI/CD 工具、代码检查工具、自动化测试工具等;

5.  支持跨平台:支持 macOS、Linux 和 Windows 等多个平台。

如何使用 Lefthook?

前文介绍了本地开发的前置一步,接下来通过实例让大家体会一下在前置处理中,如何使用 left hook 处理代码的风格安全问题。

上图是我第一次编辑的一段 Ruby 代码:通过 ChatGPT 抓取 GitHub issue 的一个内容。可以看到,acces-token 是一个环境变量,生成一个client 接口,接着我们去抓取相关 issue 信息,最后把它们打印出来。

这段代码无论从风格上还是从安全性上来说,都是一个很简单的内容。

假设本地开发人员对这段代码进行了二次编辑,他发现设置本地变量比较麻烦,直接把密钥写在代码中(如上图。密钥为随机值),同时还把代码风格打乱了,空了很多多余行,换行也是往后对齐,导致整个代码乱糟糟,不符合规范。

把这段代码推送到 CI 上,就会被检测出问题,或者 Code Review 发现这些Token 不应该上传,但这样属于事后处理,实际上,我们应该在提交之前处理掉这些问题。

那么我们看下 Lefthook 的配置, Lefthook 是类似一个 yml 的文件的配置。如下图,这里有一个 pre-push 的 hook,还有推送前的一个命令叫 pre commit。这里我们着重讲讲 pre-commit。

pre-commit 它运行两个方面:

1. Rubocop 风格检测:对 .rb 后缀的文件进行入库,检测是否符合规范;

2. 密钥检测:检测文件中是否发生了密码的泄露。

当我们在 commit 时,就会运行这两个命令,检测提交的代码内容。

检测上图这段糟糕的的代码时,看到执行钩子 pre-commit 后的效果:

  • 密钥检测提醒第七行有一个 api key 泄露,确实左边第七行用了一个明文密钥;
  • 风格检测提醒 15-17 行是多余空行,第 25 行写法不符合规范。

从而这段代码报错了,阻止 commit 的提交。

发现这些问题之后,就可以直接在本地去修复了,不用等待 CI/CD 时间;修复完再次提交,就成功了,可以看到 CI/CD 正常运行,让 CI/CD 在 测试期间也能正常通过,效率就大大提高了。

除了这些内容,我们还会进行一些常规检测,比如在 Lefthook 配置里,有一个叫 Ruby 代码风格检测工具 Rubocop,有一些命令可以修复大部分错误内容,我们也可以加入一些自定义命令,如出现问题,自动修复并推送到服务后,给钉钉发送信息等。

极狐GitLab 中,大概有十几个 Lefthook 命令,在开发过程中自动发现常见问题并解决。

总结

很多时候,造成效率低下的原因,是发现问题的时机太晚,Git Hook 在本地就能帮助我们解决代码规范问题、代码安全问题,并通过自定义脚本内容来自动执行,减少CI/CD、Code Review 时间,整体提升开发效率。


极狐GitLab
64 声望36 粉丝

极狐(GitLab) 以“核心开放”为原则,面向中国市场,提供开箱即用的开放式一体化安全DevOps平台——极狐GitLab。通过业界领先的优先级管理、安全、风险和合规性功能,实现产品、开发、QA、安全和运维团队间的高效协同...