反对约定式提交(Conventional Commits)的理由:为什么作用域比类型更重要

约定式提交优先考虑了错误的元数据

约定式提交是一个积极的错误标准,因为它优先考虑变更的类型(例如,fixfeatchore)而不是作用域(受影响的代码库的具体区域)。在实践中,对于依赖提交日志的利益相关者来说,作用域是最关键的信息。

为什么作用域重于类型

对于提交历史的主要使用者来说,了解什么被更改了比了解它是如何分类的要更有价值:

  • 贡献者: 需要识别代码特定区域的变更,以跟上项目的惯性或在变基(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-byIssue-ID),从而将主题行留给人类可读的英文。

Sources