反对约定式提交(Conventional Commits)的理由:为什么作用域比类型更重要
约定式提交优先考虑了错误的元数据
约定式提交是一个积极的错误标准,因为它优先考虑变更的类型(例如,fix、feat、chore)而不是作用域(受影响的代码库的具体区域)。在实践中,对于依赖提交日志的利益相关者来说,作用域是最关键的信息。
为什么作用域重于类型
对于提交历史的主要使用者来说,了解什么被更改了比了解它是如何分类的要更有价值:
- 贡献者: 需要识别代码特定区域的变更,以跟上项目的惯性或在变基(rebasing)期间识别潜在冲突。
- 调试器: 寻找触及了出现 Bug 的组件的变更。由于任何类型的变更都可能引入 Bug(包括 Bug 修复),因此
type标签对于隔离问题是无用的。 - 事件响应人员: 在生产环境故障期间扫描日志,以寻找与错误激增相关的特定子系统(例如,
auth作用域)的变更。
约定式提交将作用域设为可选,实际上将变更的主题视为次于其类别的次要信息。此外,type 通常是冗余的;一个写得好的描述,例如“防止命名空间化的 SVG 样式元素被剥离”,本身就传达了这是一个修复,而不需要 fix: 前缀。
自动化承诺的失败
约定式提交承诺了若干自动化优势,但在现实世界的软件工程场景中往往无法实现。
自动生成变更日志
直接从提交消息中生成变更日志会将两个不同的受众混淆。提交日志是面向开发者的,用于跟踪代码库如何演进的故事。变更日志是面向用户的,应该从业务角度描述功能差异。
由于单个功能通常需要多次提交,自动化工具会产生大量嘈杂、细粒度的日志,这对最终用户来说毫无用处。此外,回退(reverts)也是个问题:回退对于开发者的历史记录至关重要,但对用户来说应该是不可见的,因为回退的变更等同于从未进行过变更。
语义化版本控制(SemVer)自动化
由于开发的复杂性,使用提交类型来触发主版本、次版本或修订版本号的增加是不可靠的:
- 回退: 一个立即被回退的破坏性变更(breaking change)在自动化工具中可能仍会触发主版本号的增加。
- 意外破坏: 微小的破坏性变更可能被错误地标记为修订版本(patch),导致版本控制错误。
- 追溯性修复: 随后的提交可能会抵消之前的破坏性变更,但工具已经标记了版本号的增加。
构建与发布触发器
基于提交类型触发安全检查或构建(例如,跳过 docs: 的检查)存在安全风险。恶意攻击者可以将引入漏洞的提交标记为 docs: fix typos 以绕过自动化工具。
替代方案:带作用域前缀的提交
与其遵循僵化的格式,成功的规模化项目——包括 Linux, FreeBSD, Git, Go, and NixOS——都利用了带作用域前缀的消息。在这些项目中,作用域是由项目的自然架构定义的(例如,子系统、包路径或微服务名称)。
| Project | Format | Example |
|---|---|---|
| Linux | subsystem: description |
i2c: virtio: mark device ready before registering the adapter |
| Go | package: description |
net/http/cookiejar: add godoc links |
| Git | area: description |
gitlab-ci: update macOS image |
| FreeBSD | prefix: Description |
linuxulator: Return EINVAL for invalid inotify flags |
| nixpkgs | pkg-name: description |
xwayland: 24.1.11 -> 24.1.12 |
社区观点与反论点
虽然对约定式提交的批判很尖锐,但社区中的开发者对它的效用提供了不同的观点:
支持约定式提交的论点
- CI/CD 必要性: 有些人认为,对于 99% 的项目,自动标记 SemVer 并在每次合并到 main 分支时发布的能力,其价值超过了格式本身的理论缺陷。
- 对初级开发者的强制执行: 一些维护者使用约定式提交,因为它可以很容易通过 pre-commit hooks 强制执行,防止“可怕”或粗心的提交消息进入历史记录。
- 审查者期望: 一些审查者更喜欢
type在前,因为这能让他们在深入阅读代码之前立即建立对变更性质的的预期。
反对的论点
- 形式主义过度于实质: 批评者认为这种格式是一种“仪式”,浪费了主题行中宝贵的字符数。
- 上下文缺失: 几位开发者指出,无论是作用域还是类型,都不如 Issue ID 或工单号重要,因为这提供了变更背后的“为什么”——这种上下文在约定式提交标准中是完全缺失的。
- 替代元数据: 建议包括使用 Git trailers(页脚)来承载机器可读的元数据(如
Co-authored-by或Issue-ID),从而将主题行留给人类可读的英文。