← 返回信息流
AI 资讯Hacker News·2 小时前

别再死磕 Conventional Commits 了

原标题:Stop Using Conventional Commits

速览

本文探讨了 Conventional Commits 规范的局限性,指出其强制性的格式要求可能增加开发负担。作者主张放弃这种僵化的约定,提倡根据项目实际需求采用更自然、灵活的代码提交策略,以提升开发效率。

AI 深度解读

停止使用 Conventional Commits:对 Git 提交规范的深度反思

来源:Hacker News 讨论热帖 标签:Git, Commits, Scoped Commits, Conventional Commits

背景

Conventional Commits(约定式提交)作为一种在开源社区和企业开发中广泛流行的 Git 提交消息规范,旨在通过结构化的格式来增强提交信息的语义化。许多开发者在参与开源项目或阅读开源项目的 CHANGELOG 时,都曾遇到过这种格式。它被许多团队强制要求使用,甚至被一些人奉为圭臬。

然而,这篇来自 Hacker News 的深度文章对 Conventional Commits 提出了激烈的批评。作者认为,尽管该规范被众多知名开源项目采用,但它实际上是一个“ actively bad standard”( actively 糟糕的标准)。它不仅鼓励开发者关注错误的重点,而且未能兑现其核心承诺。文章指出,Conventional Commits 在优先级排序上存在根本性错误,将“类型(Type)”置于“范围(Scope)”之前,从而导致了信息价值的流失。

核心内容

格式缺陷:范围(Scope)被边缘化

Conventional Commits 的核心格式如下:

<type>[optional scope]: <description>
[optional body]
[optional footer(s)]

其中,<type> 描述了变更的类型(如 fix, feat, chore, docs, refactor 等),scope 是可选的,用于描述变更涉及的模块或组件,description 则是变更的具体描述。

文章指出,这种格式存在一个致命的缺陷:类型(Type)的优先级高于范围(Scope)。这完全是本末倒置。在 Git 提交的历史记录中,范围(Scope)才是最重要的信息,因为它指出了代码库中具体被修改的区域。

为了证明这一点,文章分析了不同利益相关者对“范围”的关注度远高于“类型”:

  1. 贡献者(Contributors)

    • 当开发者回顾提交历史时,他们主要关注代码库中哪些区域发生了变化。
    • 原因包括:了解自上次贡献以来的项目动态、理解项目的整体演进方向、以及在拉取(pull)或变基(rebase)时查找可能与当前工作进行冲突的提交。
    • 在这些场景下,开发者关心的是“哪些模块被触碰了”,而不是“这是修复还是新功能”。
  2. 调试者(Debuggers)

    • 在调查 Bug 时,开发者需要查看提交历史,找出可能触及 Bug 出现组件的变更。
    • 此时,范围是最关键的信息。类型毫无用处,因为任何类型的变更(包括 fix)都可能引入新的 Bug。
  3. 事故响应者(Incident Responders)

    • 当生产环境宕机时,扫描事故发生时间附近的提交历史是定位问题的有效手段。
    • 例如,如果在 API 错误激增的峰值处看到与 auth(认证)范围相关的提交,这极有可能是问题的根源。
    • 同样,类型在这里无关紧要,因为任何变更都可能导致生产事故。

Conventional Commits 将范围设为“可选”,这被作者比喻为“没有主语的句子”。更糟糕的是,它将类型强行提升到提交消息的最前端,完全搞错了信息的优先级。

类型(Type)的冗余与限制性

作者进一步论证,提交类型不仅不重要,反而具有破坏性:

  1. 冗余性

    • 提交消息的描述部分通常已经清楚地表明了变更类型。
    • 例如:fix(compiler): prevent namespaced SVG <style> elements from being stripped。即使只看描述,也能明显看出这是一个 Bug 修复。
    • 提交行的空间非常宝贵,浪费字符在类型上是低效的。
  2. 限制性

    • 许多变更难以被单一的类型所定义。
    • 例如:refactor(core): Update webmcp support to use document.modelContext
    • 这个提交可能同时包含了重构、Bug 修复和新特性支持。强制将其归类为 refactor 是一种误导。
    • 真正重要的是:这是对 core/webmcp 组件的变更。

承诺的破灭

Conventional Commits 声称能带来三大好处,但作者逐一驳斥:

  1. 自动生成 CHANGELOG(变更日志)

    • 受众不同:CHANGELOG 面向最终用户,关注业务和功能层面的差异;Commit Log(提交历史)面向开发者,关注代码库随时间演进的“故事”。
    • 粒度不匹配:在复杂项目中,一个显著功能的上线可能需要多次提交。开发者需要看到构建过程中的细节,但用户只关心最终功能。
    • 回退(Revert)问题:Rich 指出,回退提交在开发者看来是重要的历史故事,但在用户看来,回退等同于“未发生”。Conventional Commits 难以优雅处理这种语义差异。
  2. 自动确定语义化版本升级(Semantic Versioning)

    • 基于提交类型自动判断 Major/Minor/Patch 版本升级看似美好,但现实情况复杂:
      • 回退的干扰:如果引入的破坏性变更(Breaking Change)过于严重而被回退,工具仍会识别为 Major 升级,导致版本错误。
      • 意外破坏:开发者可能在不知情的情况下引入了破坏性变更,导致工具错误地只升级了 Minor 或 Patch 版本。
      • 事后修复:后续提交可能修复了之前的破坏性变更,但工具可能仍将其识别为破坏性变更。
    • 虽然可以通过 rebase 重写历史来修正,但这通常会破坏工作流,并向贡献者呈现一种“修正主义”的历史记录,降低了提交历史的可信度。
  3. 向队友、公众和利益相关者传达变更性质

    • 如前所述,队友和公众对 CHANGELOG 和 Commit Log 的需求截然不同。Conventional Commits 试图用一种格式满足两者,结果两头不讨好。
  4. 触发构建和发布流程

    • 文章在此处截断,但标题暗示这也是一个“坏主意”。通常,基于提交消息触发 CI/CD 流程被认为是不稳定的,因为提交消息可能包含错误信息或无法准确反映代码的实际状态。

关键要点

  • 优先级错误:Conventional Commits 将 type(类型)置于 scope(范围)之前,而实际上范围对于代码库的追踪、调试和事故响应至关重要。
  • 范围应为核心:提交消息中,指明“哪个模块/组件被修改”比“这是什么类型的修改”更有价值。
  • 类型是冗余的:提交描述通常已隐含变更类型,显式标注类型浪费空间且可能不准确(如混合了重构和新功能的提交)。
  • CHANGELOG 与 Commit Log 受众不同:用户关心功能差异,开发者关心代码演进历史。试图用 Commit Log 自动生成 CHANGELOG 会导致信息失真。
  • 自动化版本控制不可靠:基于提交类型自动推断语义化版本升级,在面对回退、意外破坏和事后修复等复杂场景时极易出错。
  • 历史记录的真实性:为了符合规范而重写 Git 历史(Rebase)会破坏提交故事的真实性,降低历史记录的可信度。

意义与影响

这篇文章对软件工程中广泛采用的 Conventional Commits 规范提出了根本性的挑战。其核心观点是:Git 提交历史的首要目的是为开发者提供清晰的代码演进脉络,而非为自动生成文档或版本控制提供结构化数据。

  1. 对开发实践的启示

    • 开发者应更关注提交消息的描述性范围明确性,而非拘泥于固定的类型前缀。
    • 团队在制定提交规范时,应优先考虑如何帮助开发者快速定位变更范围,而不是如何方便机器解析。
  2. 对工具链的影响

    • 依赖 Conventional Commits 自动生成 CHANGELOG 或版本号的工具链需要重新评估其可靠性。
    • 建议将 CHANGELOG 的
查看原文 →sumnerevans.com