如何巧用 Git Hook,解决代码提交中的代码规范性、冲突和错误以及工作流程问题?
近日,在极狐 TechTalk 直播上,极狐(GitLab) 后端工程师田鲁分享了自己的实践经验。以下内容整理自本次直播,你也可以点击文末「阅读原文」观看视频回放。Enjoy~
在开发过程中,开发人员提交代码后,需要继续做很多工作,因此我们不由萌生一个问题:是否可以把一些工作前置处理,减少等待时间?
首先,我们先回顾一下常见的代码流程:
在该流程中,若在本地发现问题,修复起来时间相对较短;若在远程执行 Pipeline 后才发现问题,则修复时间较长,并且增加了服务器的压力。
那么是否可以将一些工作提前,如在中间部分(如上图)完成来提高本地效率,缩短开发流程呢?如题所言“向前一步”,即把原本在 CI 中执行的部分工作,放在本地执行。
常见代码开发过程中,通常依赖于后置处理,即开发人员的代码提交到 Git 上以后,运行 CI/CD 或者 Code Review 过程中才发现常见问题,包括:
这样既浪费了 CI/CD 资源,也花费了不必要的时间,导致开发效率低。
举个🌰,如下图极狐 GitLab 中的 Pipelines,在构建作业 → 测试 → 发布的环节中,我们需要等上传测试后才能发现错误,接着在本地修改,再把 Pipeline 推送上来,才能确认这个错误是否被修复;若没有修复,则需要重复修改,直至修复完成,这个过程耗费很多时间。
可能大家会想到,对团队成员进行口头约束,或从制度上要求开发人员必须自己做检测,但这些几乎是流于形式。
那么,极狐 GitLab 如何处理解决这些问题的?
极狐 GitLab 通过自动化流程,高效落实开发工作,让团队协作更流畅。
➤ 代码规范性问题
在提交代码前,运行代码风格检查和自动化测试等脚本,帮助开发人员发现并修复代码中的规范性问题,从而保证代码的质量和可维护性。
➤ 冲突和错误问题
在提交代码前运行 Git Hook,帮助开发人员避免将错误或不规范的代码推送到代码仓库中,从而减少代码冲突和错误。
➤ 工作流程问题
开发人员规范化 Git 工作流程,提高工作效率和协作效果。通过配置 Git Hook,可以自动化执行代码检查、测试、构建和部署等任务,避免手动操作繁琐和出错。
极狐 GitLab 在具体实践中逐步完善了该自动化流程,从而确保研发任务能更有效执行。这部分在极狐 GitLab 的文档里也有更具体说明,感兴趣的小伙伴可以查阅我们的资源与文档。
与许多其他版本控制系统一样,Git 有一种方法可以在发生某些重要操作时,触发自定义脚本,即 Git Hook(Git 钩子)。
当我们初始化一个项目之后,.git 目录下有一个 hooks 目录,可以看到上图左侧有很多执行任务,比如 pre-commit,代表在运行这些命令之后或之前,会进行一些校验和检测来执行相应任务。
Git Hook 分为两部分:本地和远程,如下图所示:
本地 Git Hook,由提交和合并等操作触发:
远程 Git Hook,运行在网络操作上,例如接收推送的提交:
在这里,我们主要关注本地 hook,比如说 pre-message 和 pre-push,因此我们会借助这些工具来实现规范化代码内容。
极狐 GitLab 是一个非常大的代码仓库,包含前端代码、后端代码,还有运维相关代码:
当然也支持不同语言项目,像 Python、Java 或者其它编程语言,也会有相应代码规范要求,可以自己添加。
每个 Lint 都会去检测代码中的变动,从而检测代码是否符合预期。只有符合预期的代码,才能够推送进来,避免代码提交之后,再发现代码规范问题,在反复修改上浪费时间。
这就好比整个代码仓库是房子,代码是水,Lint 相当于过滤器,必须让这些代码经过过滤后,才能从水龙头流出,成为生活用水。
下图展示的是 GitHub 安全事故:很多人在测试或调试代码过程中,把一些 Token 放在里面,无意识地推送到仓库中,导致 API 和加密密钥泄露,这很容易被人发现和利用,进而造成巨大损失。
极狐 GitLab 十分注重代码安全,我们必须想办法阻止开发人员将密钥提交到仓库,也就是必须在 Commit 之前,阻止开发人员把密钥信息给放到 Git 历史记录中。
那么,常见的安全代码检测工具有哪些?这里给大家提供一个参考,就是 Gitleaks。
Gitleaks 是一个 SAST 静态代码检测工具,检测代码中常见的 Secret、Token、Password 等内容,生成 Secret 检测报告产物,避免误提交,提高研发安全性。
上述代码规范检测、代码安全检测,都是在代码提交前,及时发现问题和解决问题,提升代码质量和安全性。自动化内容检测偏向于常规性内容检测,例如:
自动化内容检测避免代码提交到在服务器后再去修改内容,也是提高开发效率的手段之一。
上述 3 个步骤放在本地开发阶段执行,基于以下原因,开发效率就会有很大提升,甚至整个运行时间降低 50%,同时更高效地提升了代码质量:
我们可以使用 Git Hook 里的 bash 脚本来编写,比如前面提到的 Eslint、Stylelint 等,但是这种方式有个比较大的缺点:无法放在仓库中,则无法看到变更历史,也不方便分发,而且可能不是每个开发人员都熟悉脚本的开发。
因此,我们可能需要更友好的 Git Hook 管理工具,这里推荐工具:Lefthook。
Lefthook 是一个开源的 Git Hook 管理工具,帮助开发人员自动化和规范化 Git 工作流程。
Lefthook 具备以下特点:
1. 支持多种编程语言:包括 Python、JavaScript、Ruby、Go、Java 等;
2. 简单易用:轻松安装和配置,使用过程也非常简单;
3. 高灵活性:允许用户在 Git Hook 中使用任何语言和工具,而不仅仅是 shell 脚本;
4. 高可扩展性:可与其他工具和系统集成,比如 CI/CD 工具、代码检查工具、自动化测试工具等;
5. 支持跨平台:支持 macOS、Linux 和 Windows 等多个平台。
前文介绍了本地开发的前置一步,接下来通过实例让大家体会一下在前置处理中,如何使用 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 后的效果:
从而这段代码报错了,阻止 commit 的提交。
发现这些问题之后,就可以直接在本地去修复了,不用等待 CI/CD 时间;修复完再次提交,就成功了,可以看到 CI/CD 正常运行,让 CI/CD 在 测试期间也能正常通过,效率就大大提高了。
除了这些内容,我们还会进行一些常规检测,比如在 Lefthook 配置里,有一个叫 Ruby 代码风格检测工具 Rubocop,有一些命令可以修复大部分错误内容,我们也可以加入一些自定义命令,如出现问题,自动修复并推送到服务后,给钉钉发送信息等。
极狐 GitLab 中,大概有十几个 Lefthook 命令,在开发过程中自动发现常见问题并解决。
很多时候,造成效率低下的原因,是发现问题的时机太晚,Git Hook 在本地就能帮助我们解决代码规范问题、代码安全问题,并通过自定义脚本内容来自动执行,减少 CI/CD、Code Review 时间,整体提升开发效率。