维护的项目多了以后,我养成了一个职业病:开 PR 之前先翻一遍 commit message。不是我有洁癖,而是被坑怕了。早几年带一个中后台团队,十几个前端、后端、测试混在同一个仓库里,提交信息那叫一个乱——"fix""update""111""asdf",还有干脆空着的。真到发版本、写 CHANGELOG、回溯线上 bug 的时候,Git 历史就跟一锅粥似的,git log --oneline 根本没法看。后来我把"提交信息规范化"这件事折腾了个遍,最终动手用 Rust 写了一个零依赖的 Git 提交信息校验工具 gitru,才算把这个问题真正摁住。
先说清楚 gitru 是什么:它是一个跑在 Git commit-msg 钩子里的校验工具,负责在你提交代码的那一刻检查提交信息是否符合团队规范,不符合就直接拦下。它不依赖 Node、不依赖任何运行时、不依赖任何第三方库,编译完就是一个独立的可执行文件,几十 KB 的二进制扔到任何机器上都能跑,校验一条提交信息的耗时在毫秒级。
这篇文章我不打算写成一份干巴巴的 README 翻译,而是把"为什么要做这个工具""核心设计是怎么想的""怎么接入现有项目",再到"实际用下来踩了哪些坑"完整复盘一遍。如果你也在为团队 commit message 头疼,或者单纯想找一个比 commitlint 更轻的替代品,这篇应该对你有用。
1. 被烂提交信息支配的恐惧:gitru 到底在解决什么问题
1.1 提交信息不是写给 Git 看的,是写给六个月后的你
很多人觉得 commit message 就是个备注,随便写写就行。但完整的 Git 工作流里,提交信息真正服务的对象是这些场景:
- code review 时,reviewer 靠 commit message 判断改动意图;
- 发版时,conventional-changelog 这类工具要解析 feat/fix 才能自动生成 CHANGELOG;
- 语义化版本 bump 也要依赖提交类型做 major/minor/patch 判断;
- git bisect 排查回归时,一条清晰的提交信息能帮你快速锁定嫌疑范围;
- revert 一个提交时,如果原始信息没有上下文,回滚理由都写不明白。
这不是理论上的"最佳实践",而是实打实的成本。我见过最典型的一次事故:某次线上故障定位花了两个多小时,最后发现是一个同事在提交信息里写 "fix something stupid" 的改动引入了回归。如果提交信息能展示清楚改动动机和安全影响,这个回溯过程至少能缩短一半。
所以提交信息校验本质上不是"管得宽",而是把 Git 历史当成团队资产来保护。校验的价值不在当下,而在三个月、半年后,当所有人都不记得这次改动为什么存在的时候,历史记录还能替你说清楚。
1.2 规范落地为什么总是失败:不是缺文档,是缺强制
提到规范,大部分团队的第一反应是"写进开发文档"。但文档的宿命是被遗忘。真正有效的做法只有一个:在提交的那一刻强制执行,让不符合规范的提交根本落不下来。
这也是大家最终都会走向 git hook 的原因。社区里最常用的方案是 husky 搭配 commitlint,成熟度没得说,可它有四个硬伤:
第一,环境依赖重。commitlint 是 Node 生态,项目里必须能跑到 npm。Java、Go、Python 这类仓库为了校验提交信息硬塞一个 node_modules,怎么看都别扭。第二,安装体量大、速度慢。一个 commitlint CLI 拉上各种 preset 和依赖,动辄几十 MB,在 CI 环境里就是实打实的构建成本。第三,钩子很难做到开箱即用。JavaScript 项目有 husky 自动装钩子,但别的语言项目经常靠每人手动拷贝脚本,钩子版本不一致、某台机器没装 Node 直接跳过校验,这种情况我见了太多。第四,规则配置分散。每个仓库一份规则,今天这个改了明天那个忘改,团队规范成了拼图游戏。
我想要的工具是:拿到仓库就能校验,不装任何运行时,配置文件跟仓库走,人人都用同一套规则。这正是 gitru 的出发点。它解决的不是"没有规范"的问题,而是"规范执行不下去"的问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. gitru 的核心设计:Rust、零依赖、单文件
2.1 零依赖不是噱头,是不想再被供应链折腾
设计 gitru 时我给自己定了一条死规矩:运行时不依赖任何第三方库,编译产物是单个静态可执行文件。这条规矩来自我被 Node 系工具伤过的经历,也来自对供应链安全的一点洁癖。
依赖越少,攻击面越小。commit 信息校验要处理的是开发者本地的任意输入,如果工具本身拉了一大堆传递依赖,任何一个上游包出问题都会波及所有使用方。零依赖意味着没有中间层,代码路径清晰,安全审计就是读自己这几千行代码的事。Rust 在这里的胜出几乎是必然的:它没有 GC、没有运行时,标准库自带的 I/O、字符串处理、进程操作能力足够,编译出来就是一份独立的静态二进制。相比之下,Go 虽
