EMQX 开源仓库贡献指南:分支同步链、Conventional Commit 规范与 Changelog 工程实践
2026/9/21 16:09:37 网站建设 项目流程

EMQX 开源仓库贡献指南:分支同步链、Conventional Commit 规范与 Changelog 工程实践

【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址: https://gitcode.com/gh_mirrors/em/emqx

本文以 CONTRIBUTING.md 为骨架,结合 EMQX 仓库中真实的脚本(如 scripts/check-changes-filename-pattern.sh、scripts/ff-release-from-dev.sh)与changes/目录的既有产物,系统讲解向 EMQX 提交代码时必须遵守的三件事:往哪个分支提 PR、如何书写规范的 commit message、以及如何登记 changelog。读完本文,你将能准确判断 PR 的目标分支,写出符合仓库要求的提交信息,并为自己的改动添加一条能通过 CI 校验的变更记录。

一、先了解仓库:EMQX 的提交入口

EMQX 是一个以 Erlang/Elixir 为主实现的高性能 MQTT 消息服务器,仓库根目录采用 monorepo 结构,核心业务代码集中在apps/目录下(例如apps/emqxapps/emqx_authapps/emqx_bridge_kafka等),发布相关脚本位于scripts/,版本演进记录位于changes/。向这样一个多版本并行维护的仓库提交代码,分支策略与提交规范是合入的第一步关卡。

本仓库欢迎任何形式的 Bug 报告、Issue 与功能请求(feature request)。在动手提交代码之前,建议先通读本指南,重点理解以下三个环节:

  1. 分支目标选择——决定你的改动最终进入哪些发布线(release line);
  2. 提交信息格式——决定你的提交在git log与自动化工具中的可读性;
  3. Changelog 登记——决定你的改动是否会被收录进官方版本变更记录。

二、分支策略:选择正确的目标分支

2.1 dev-XX 分支与正向同步链(forward-sync chain)

EMQX 同时维护多条dev-XX分支,每条对应一个仍在支持的发布线(例如dev-58dev-60dev-63)。这些分支之间存在一条自动正向同步链:一个改动合入较早的分支后,会通过同步机制自动传递到链条上的每一个后续分支,无需为每条分支分别提交 PR

从仓库脚本 scripts/rel-versions 可以确认当前 6.x 系列的同步链形态:

dev-60 -> dev-61 -> dev-62 -> dev-63 -> dev-70

该脚本注释明确指出:"The 6.x line ends at dev-63; there is no 6.4 release, so dev-63 syncs forward into dev-70"(6.x 线止步于 dev-63,由于不存在 6.4 版本,dev-63 继续向前同步到 dev-70)。这说明同步链可以跨大版本延续。该脚本还说明了链上各分支与发布线的关系:release-XX分支会从对应的dev-XX分支自动快进(见 2.3 节),因此合入 dev 分支的改动最终会到达该发布线的发布分支。

2.2 目标分支的选择规则

  • 优先选择改动影响的最早的仍活跃dev-XX分支,尤其是高严重级别(high-severity)的修复。因为同步链是单向向前的,只有合入最早的受影响分支,修复才能经由链条覆盖所有下游发布线。
  • 如果不确定哪条分支最早或仍活跃,直接瞄准最新的dev-XX分支即可。此时应在 PR 描述中说明这一情况并请求维护者指引;评审过程中维护者可以视情况将 PR 重定向到更早的分支。
  • 切勿针对多条dev-XX分支提交重复 PR。同步链本身会向前传播改动,重复 PR 只会造成重复评审工作量,且若未同时合入还会导致内容分叉(diverge)。
  • 绝不直接向release-XX分支提交 PR。这些分支由对应的dev-XX分支自动快进而来,不接受直接推送。

2.3 发布分支的快进机制(源码佐证)

release-XX不接受直接推送这一规则,在脚本 scripts/ff-release-from-dev.sh 中有完整的落地实现。该脚本用于将release-XX快进(fast-forward)到dev-XX,核心逻辑是:

VERSION="$1" DEV_BRANCH="dev-${VERSION}" RELEASE_BRANCH="release-${VERSION}" # 若两者 SHA 相同则无事可做 if [ "${DEV_SHA}" = "${REL_SHA}" ]; then exit 0 fi # git push 不带 --force,本质上就是仅快进操作 git push origin "${DEV_SHA}:refs/heads/${RELEASE_BRANCH}"

脚本刻意依赖git push(不带--force)天然拒绝非快进更新的特性来保证release-XX始终是dev-XX的祖先;当出现分叉时,会在 CI 环境变量中写入NOT_FAST_FORWARD=1并报错。这一设计从工程层面印证了 CONTRIBUTING.md 中"release 分支仅由 dev 分支快进、不接受直接推送"的约束。

三、Commit Message 规范

仓库对 commit message 有非常精确的格式要求,目的是让项目历史更易阅读、更易被 git 工具与自动化流程消费

3.1 整体格式

每条提交信息由headerbodyfooter三部分组成,header 内部又分为typescopesubject

<type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer>
  • header(含 type)是必填项,header 中的scope 为可选项
  • 本仓库没有预定义 scope 列表,允许按需自定义 scope 以提升可读性;
  • 每行长度不得超过 100 个字符,以保证在 GitHub 界面和各种 git 工具中都能被完整阅读;
  • footer 中如有关联的 Issue,应写入关闭引用(closing reference),例如Closes: #123

3.2 完整示例

示例 1:仅含 header 的最小提交

feat: add Fuji release compose files

示例 2:带 scope、body 与 footer 的完整提交

fix(script): correct run script to use the right ports Previously device services used wrong port numbers. This commit fixes the port numbers to use the latest port numbers. Closes: #123, #245, #992

可以看到,body 中先用一句话说明"之前的错误行为",再说明"本次提交做了什么"——这正是规范要求的"说明动机并与旧行为做对比"。

3.3 字段细则

Revert(回滚提交):如果提交是对某次历史提交的回滚,必须以revert:开头,随后跟被回滚提交的 header,并在 body 中写明This reverts commit <hash>.(hash 为被回滚提交的 SHA)。

Type(必填):必须是以下枚举值之一:

Type含义
feat面向用户的新功能(而非面向构建脚本的新功能)
fix面向用户的缺陷修复(而非对构建脚本的修复)
docs仅文档变更
style格式、缺失分号等,不涉及生产代码变更
refactor生产代码重构,如变量重命名
chore更新构建任务等,不涉及生产代码变更
perf提升性能的代码变更
test补充缺失的测试或重构测试,不涉及生产代码变更
build影响 CI/CD 流水线、构建系统或外部依赖的变更(示例 scope:jenkins、makefile)
ciDevOps 为 CI 目的提供的变更
revert回滚某次之前的提交

Scope(可选):本仓库没有预定义 scope,可自定义以增强清晰度,例如示例中的fix(script):

Subject(必填):对变更的简洁描述,要求:

  • 使用祈使句、现在时:写change,不写changedchanges
  • 首字母不大写;
  • 结尾不加句号(.)。

Body(可选):与 subject 相同,使用祈使句、现在时;应包含变更动机,并与旧行为进行对比。

Footer(可选):承载两类信息:

  • Breaking Changes:必须以BREAKING CHANGE:开头(后跟一个空格或两个换行),其余部分描述破坏性变更的具体内容;
  • Issue 关闭引用Closes: #xxx,可一次引用多个 Issue。

四、Changelog 登记规范

影响 EMQX 功能行为的变更,必须changes目录下以独立 markdown 文件描述。这一要求不仅是文档约定,仓库中还提供了 CI 脚本强制校验文件名模式。

4.1 文件命名模式

changes/ee/(feat|fix|perf|breaking)-<PR-id>.en.md

各字段含义:

  • feat | fix | perf | breaking:变更类型——新功能(feat)、缺陷修复(fix)、性能改进(perf)或破坏性变更(breaking);
  • PR-id:GitHub PR 编号。由于 PR 创建前无法预知编号,常见的做法是在单独的提交中补充 changelog 条目(即 PR 合入后补一条);
  • en:ISO 639-1 语言代码,表示该 changelog 条目的语言。目前仓库只接受英文条目

4.2 仓库内的真实产物印证

打开 changes/ee 目录可以看到大量符合该模式的实际文件,例如:

  • feat-14040.en.mdfeat-14479.en.md(新功能)
  • fix-xxx.en.md(修复)
  • perf-xxx.en.md(性能改进)
  • breaking-14765.en.mdbreaking-14865.en.md(破坏性变更)

feat-14040.en.md为例,其内容是一句紧凑的英文描述:"Added timeouts to the internal RPC calls during node rebalance. Previously, the rebalance process could hang if a node was unresponsive."(为节点再平衡期间的内部 RPC 调用添加超时;此前若节点无响应,再平衡过程可能挂起)。可见条目要求非常紧凑,同时保留"动机 + 旧行为对比"的表述结构。

4.3 CI 强制校验(源码佐证)

脚本 scripts/check-changes-filename-pattern.sh 在 CI 中执行,通过git diff --diff-filter=A找出新增文件,并对以fix-feat-perf-开头的文件强制匹配以下模式,否则直接报错退出:

^changes/ee/(fix|feat|perf)-[0-9]+\.en\.md$

也就是说,如果你的 changelog 文件放错了目录(如changes/ce/)、类型前缀不在枚举内、PR 编号不是纯数字,或语言后缀不是.en.md,CI 都会拦截。CONTRIBUTING.md 中给出的模式是(feat|fix|perf|breaking)四种前缀,而 CI 脚本只校验fix|feat|perf三种——breaking条目同样存在于仓库中(如breaking-14765.en.md),说明breaking是约定中的合法前缀,但 CI 正则对未以这三类前缀开头的文件不强制。

4.4 Changelog 的自动化生成(源码佐证)

仓库还提供了半自动化的 changelog 生成脚本 scripts/generate-changelog.sh:

  • 输入:PR 编号(命令行参数或环境变量GITHUB_PULL_REQUEST_NUMBER);
  • 流程:从远端拉取 PR 的 base 与 head SHA,计算 diff,调用 OpenAI 或 Gemini API 将 diff 分类为feat/fix/perf并生成两句以内的紧凑摘要,随后按changes/ee/${PREFIX}-${PR_NUMBER}.en.md写入文件;
  • 在 GitHub Actions 环境下,脚本还会自动提交该文件并推回 PR 分支。

由此可以看出,changelog 文件的类型前缀(feat/fix/perf)与 commit message 的 type 语义保持一致,整条工程链路(提交 → PR → changelog → 版本记录)是打通的。而changes/目录下的版本文件(如 changes/6.3.1.en.md、changes/e5.9.1.en.md)则汇集了这些条目,构成每个版本对外发布的变更说明。

五、实操速查:一次规范提交的完整流程

综合以上规则,向 EMQX 提交一次合规改动的推荐流程如下:

  1. 定位基线分支:确认改动影响的最早dev-XX分支;不确定就选最新的dev-XX,并在 PR 描述中说明;
  2. 创建分支并开发:基于目标 dev 分支切出特性分支;
  3. 提交:按<type>(<scope>): <subject>编写 header,必要时补充 body 与 footer;整行不超过 100 字符;需要回滚时以revert:开头并注明This reverts commit <hash>.
  4. 登记 changelog:若改动影响 EMQX 功能,在changes/ee/下新建<prefix>-<PR-id>.en.md(prefix ∈ feat/fix/perf/breaking),写一句紧凑的英文描述;PR 编号未知时可稍后补提交;
  5. 发起 PR:目标分支选 dev 分支而非 release 分支,不要对多条 dev 分支重复开 PR;等 CI(含check-changes-filename-pattern.sh)通过。

六、常见问题(FAQ)

Q1:我的修复同时影响 5.8 与 6.x,该往哪条分支提交?答:向受影响的最早的仍活跃dev-XX分支提交(例如dev-58),同步链会把它自动带到后续所有分支;切勿分别向多条 dev 分支开 PR。

Q2:不确定 scope 该怎么写?答:scope 是可选项且无预定义列表,可以不写,或使用能准确描述改动范围的短语(如fix(script):)。

Q3:changelog 文件里的 PR 编号还没确定怎么办?答:按规范在 PR 创建后的单独提交中补充,文件名里的 PR-id 以实际 PR 编号为准;CI 会校验文件必须位于changes/ee/且格式为{fix|feat|perf}-<数字>.en.md

Q4:破坏性变更如何标记?答:在 commit 的 footer 中以BREAKING CHANGE:开头描述破坏性内容;同时按需在changes/ee/下添加breaking-<PR-id>.en.md条目。

Q5:我的提交只改了文档,需要 changelog 吗?答:changelog 针对"影响 EMQX 功能行为"的变更;仅文档类改动使用docs:类型的提交即可,通常无需 changelog 条目。

七、延伸阅读

  • 分支同步链与版本推算:scripts/rel-versions
  • 发布分支快进机制:scripts/ff-release-from-dev.sh
  • Changelog 文件名 CI 校验:scripts/check-changes-filename-pattern.sh
  • Changelog 自动化生成:scripts/generate-changelog.sh
  • 变更记录存放目录:changes/ee
  • 仓库主 README:README.md

【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址: https://gitcode.com/gh_mirrors/em/emqx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询