Cherry Studio 分支策略与版本标签管理全指南:从贡献分支到自动化发布工作流
Cherry Studio 分支策略与版本标签管理全指南:从贡献分支到自动化发布工作流
本文系统梳理 Cherry Studio 开源项目(AI 生产力套件,提供智能对话、自主 Agent 与 300+ 助手能力)的分支模型与版本标签管理制度:main 作为唯一活跃开发基线、release/* 作为发布专用分支、四类贡献分支的命名与 PR 规范,以及覆盖 hotfix 回移植(backport)、草稿发布、元数据同步在内的 GitHub Actions 自动化闭环。读完本文,你将掌握该项目的完整分支治理规范,并能对照仓库内的 Workflow 定义理解每条规则背后的自动化实现原理。
一、分支策略总览:为什么需要一套结构化分支模型
Cherry Studio 通过一套结构化的分支策略来维持代码质量并理顺开发流程。这套策略的核心原则是以 main 为唯一活跃开发基线——所有功能、重构、优化与修复均面向 main 提交,发布过程则完全由 release/* 分支承载,并通过 GitHub Actions 自动化串接,尽量避免手工操作带来的状态漂移。
feature/* ──┐
fix/* ──┤ PR 合并
docs/* ──┼──────────────► main ──► release/v<version> ──► v<version> tag
hotfix/* ──┘ (Pre Release 创建) (Release 构建发布)
▲
└── backport/v<version>/pr-<n>(hotfix 回移植)
从源码结构看,这一模型并非纸面约定,而是被 .github/workflows 目录下的多套自动化工作流强制执行的,后文将逐条对应。
二、主分支(Main Branches)
2.1 main:唯一活跃开发分支
- 包含最新的开发代码;
- 不允许直接提交——所有变更必须通过 Pull Request(PR)进入;
- 代码可能包含尚在开发中的特性,不保证完全稳定。
工作流层面,Pre Release(prepare-release.yml)在 jobs.prepare 中通过 if: github.ref == 'refs/heads/main' 显式守卫,从源头上杜绝了从特性分支误触发发布准备的可能。
2.2 release/*:发布分支
- 由 Pre Release 工作流从
main的精确当前头(head)创建,正常流程下不手工创建; - 承载面向正式发布的稳定代码;
- 只接受经过评审的 hotfix 回移植与发布元数据更新;文档类变更仍走
main; - 在部署到生产环境前需经过充分测试。
2.3 testplan 分支
Test Plan(测试计划)流程使用独立的 testplan 分支体系,详见 Test Plan(本文档的姊妹篇)。简单来说:testplan 是一个临时分支,只用于测试计划的版本发布,不支持基于它开发、也不接受直接提交,且始终基于最新 main(而非已发布版本)叠加特性。
相对链接转换提示:上述
testplan说明对应的原文档是 docs/contrib/test-plan.md,其中 RC 通道分支命名为testplan/rc/x.y.z、Beta 通道为testplan/beta/x.y.z,版本号形如x.y.z-rc.n/x.y.z-beta.n。
三、贡献分支(Contributing Branches):命名与 PR 规范
向 Cherry Studio 提交贡献时,遵循以下四类分支规范,所有分支均从 main 创建、PR 目标回 main:
| 分支类型 | 命名格式 | 说明 |
|---|---|---|
| 功能分支 Feature | feature/issue-number-brief-description | 新功能开发,编号关联 issue |
| 缺陷修复分支 Bug Fix | fix/issue-number-brief-description | 常规 bug 修复 |
| 文档分支 Documentation | docs/brief-description | 纯文档变更,无需 issue 编号 |
| 热修复分支 Hotfix | hotfix/issue-number-brief-description | 面向活跃草稿发布的紧急修复 |
3.1 Hotfix 分支的严格标题语法
Hotfix PR 的标题必须精确匹配以下两种形式之一(对应 backport-release-fixes.yml 中的 HOTFIX_TITLE_PATTERN):
hotfix: <description>
hotfix(<kebab-case-scope>): <description>
其正则定义为:
^hotfix(\([a-z0-9]+(-[a-z0-9]+)*\))?: [^[:space:]].*$
约束要点:作用域(scope)必须是小写字母数字组成的 kebab-case;冒号后必须跟一个空格;描述不能为空。
CI 会根据该精确标题语法同步 hotfix 标签——标题匹配则自动加标签,标题被改为非 hotfix 形式则自动移除。这保证了"合并即标记"的自动化链条(见 backport-release-fixes.yml 的 classify job)。
3.2 Hotfix 的双语发布说明(release-note)
对面向用户的修复,需要在 PR 模板的 release-note 代码围栏内提供恰好一行带组件标签的英文说明和一行中文说明,且不得添加列表前缀:
<!--LANG:en-->
[Component] English description.
<!--LANG:zh-CN-->
[组件] 中文说明。
<!--LANG:END-->
若不需要发布说明,则在围栏内保留 NONE(省略整个围栏也能被自动化接受,但保留模板段落更规范)。校验规则实现在 scripts/release/hotfix-release-notes.js 的 extractHotfixReleaseNote 函数中:
- 每个 hotfix PR 最多只能有一个
release-note代码块; - 三个标记(
<!--LANG:en-->、<!--LANG:zh-CN-->、<!--LANG:END-->)必须齐全、顺序正确且不重复; - 英文与中文各必须是一行
[组件] 描述格式; - 中文说明必须确实包含中文字符(用 Unicode Han 脚本正则校验)。
任何一条不满足都会导致自动化回移植流程中止,因此提交 hotfix 时务必按此模板填写。
四、Pull Request 通用规范
面向 main 的活跃开发(功能、重构、优化、修复)统一遵守:
- 提交 PR 前确保分支已同步最新
main; - PR 描述中附上相关的 issue 编号;
- 确保全部测试通过、代码符合项目质量标准;
- 新增功能或改动 UI 组件时,附上 before/after 截图。
五、版本标签管理(Version Tag Management)
- 主版本发布:
v1.0.0、v2.0.0等; - 功能版本发布:
v1.1.0、v1.2.0等; - 补丁版本发布:
v1.0.1、v1.0.2等; - 草稿激活期间的修复:若一个草稿 release 已经存在,合并进该草稿的修复沿用草稿现有的版本标签;发布之后,新的修复应在下一个更大的语义化版本中发布,通常是下一个补丁版本(例如
v1.0.1之后发布v1.0.2)——不得创建独立的v1.0.1-hotfix标签。
从 prepare-release.yml 的 resolve 步骤可以看到版本意图的解析逻辑:Pre Release 工作流接受 patch / minor / major 三种递增模式,或 2.1.0、2.1.0-rc.1、2.1.0-beta.1 这类精确版本号,且强制要求目标版本严格大于 main 当前记录的已发布基线版本(semver.gt(targetVersion, currentVersion))。
六、发布分支的自动化生命周期(源码级展开)
本节对照 Release Workflow Operations 运行手册,将"分支策略"文档中 release/* 的每条规则映射到实际工作流:
| 阶段 | 来源 | 工作流 | 产物 |
|---|---|---|---|
| 预览 | 任意同仓库分支 | Preview Release(preview-release.yml) | 内部测试用的隔离草稿 Release |
| 准备 | main | Pre Release(prepare-release.yml) | 创建 release/v<version> 并附带签名发布元数据提交 |
| 校验 | release/v<version> | CI(ci.yml) | 校验精确发布分支提交 |
| 调度 | 发布分支 CI 成功 | Auto Release Build(auto-release-build.yml) | 启动一次精确头全平台构建 |
| 构建 | release/v<version> | Release(release.yml) | 创建/移动草稿标签、上传产物、组装发布正文 |
| 热修复 | 已合并的 main PR | Backport Release Hotfixes(backport-release-fixes.yml) | 针对活跃发布分支打开回移植 PR |
| 审批发布 | 精确头全平台构建成功 | Publish Release(publish-release.yml) | 等待 release 环境审批,重新校验后发布草稿 |
| 同步 | 已发布的 GitHub Release | Post Release(post-release.yml) | 打开纯元数据的 release-sync/v<version> PR |
6.1 阶段一:Pre Release 准备发布分支
操作方式:Actions → Pre Release → Run workflow,分支选择器选 main,version 输入 patch/minor/major 或精确版本号。
该工作流的关键行为(对应分支策略文档中"从精确校验过的 main 头创建"):
- 冻结所选的
main提交作为发布源,并校验其记录的版本确实是最新已发布版本;若基线标签v<baseline-version>不是main的祖先,则要求存在一条完整消息中恰含release-metadata-boundary: v<baseline-version>行的提交(该标记始终指向已发布版本而非目标版本); - 收集发布说明,只从临时准备工作区提取三处源元数据变更,随后恢复到冻结的源 SHA;
- 一个新 job 仅从工作流产物复制元数据文件,通过 GitHub API 从冻结的源提交创建
release/v<version>; - 目标分支与目标标签不得已存在,且提交必须是 Verified 且带 DCO
Signed-off-by。
发布准备只允许改动以下文件(发布元数据边界):
package.jsonelectron-builder.ymlresources/cherry-studio/release-history.jsonresources/builtin-agents/cherry-assistant/product-manifest.json
稳定版会更新发布历史(release history);预发布版(prerelease)不改动 release-history.json。
6.2 阶段二至三:发布分支 CI 与构建
推送 release/v<version> 会自动触发 CI。CI 成功后 Auto Release Build 会复核成功的 SHA 仍是当前分支头,才派发 Release 工作流(all 平台);过期的 CI 完成会被忽略,精确头的构建不会被重复派发两次。Release 工作流要求存在 head_sha 与待发布提交完全相等的 ci.yml push 运行记录——旧提交的成功运行不满足此门禁。
Release 构建前的自校验清单:
- 必须从
release/v<semver>分支启动; - 分支版本与
package.json一致; - 该精确分支提交的 CI 已成功;
- 不存在匹配的已发布 Release。
每个选中平台都会从同一提交构建全球版与中国版两个版本;两个 Windows 安装程序保留既有的全局 NSIS GUID,安装任一端都会替换同一安装而非产生第二个应用。所有选中平台构建成功后,最终 job 下载完整的暂存产物集,按 release ID 更新草稿,只有这时才创建或将 v<version> 移动到精确校验过的分支提交——标签移动仅允许在 release 仍为草稿时发生。
6.3 阶段四:Hotfix 与自动回移植(backport)
所有 hotfix 开发仍然从 main 开始,流程如下:
- 从当前
main创建常规修复分支; - 打开目标为
main的 PR; - 使用严格的
hotfix:/hotfix(<scope>):标题; - 按前文 3.2 节规范填写
release-note围栏; - 等待评审与 CI,合并进
main。
合并后 Backport Release Hotfixes 工作流自动接管:它锁定 release 状态,找到唯一一个带有匹配发布分支的草稿语义化版本 Release,将源 PR 的变更集应用到回移植主题分支 backport/v<version>/pr-<source-number>(若已有打开的回移植 PR,则把新修复追加到该 PR 的同一主题分支,形成聚合回移植)。每个生成的提交都经过 GitHub Verified 与 DCO 签名,且绝不直接提交到发布分支。
源 PR 的状态通过三个标签跟踪:
| 标签 | 含义 | 操作者动作 |
|---|---|---|
backport/v<version> | 回移植 PR 已打开 | 评审回移植 PR 并等待 CI |
backported/v<version> | 回移植 PR 已合并,或修复已在分支中 | 合并后等待发布分支 CI 并重建;若已存在则无需重建 |
backport-failed/v<version> | 自动化在开 PR 前失败,或回移植 PR 未合并被关闭 | 检查工作流运行、手工回移植或重新打开 PR |
回移植 PR 合并后:等待发布分支新头的 CI → Auto Release Build 自动启动 all 重建 → 复核更新后的草稿 release。
解决回移植失败的手工流程(当源 PR 被标 backport-failed/v<version> 且尚无回移植 PR 时):
- 从当前
release/v<version>头创建临时冲突解决分支; - 只应用 hotfix PR 的预期变更,绝不将整个
main合并进发布分支; - 冲突解决偏向"发布分支 + 所需修复",不引入无关的后续
main变更; - 运行
PR_BODY="$(gh pr view <source-number> --json body --jq .body)" node scripts/release/hotfix-release-notes.js应用双语说明(NONE或缺失时为 no-op); - 对所有改动的代码与元数据文件执行相应校验;
- 创建签名且带 DCO 的提交,打开目标为
release/v<version>的 PR 供评审; - 合并后等待发布分支 CI 与自动草稿重建;
- 在源 PR 上将
backport-failed/v<version>替换为backported/v<version>并注明手工解决 PR/提交。
6.4 阶段五:发布(Publish)
仅在最新发布分支提交通过 CI、且该精确提交的 all 平台构建成功后发布:
- 在 Releases 页打开草稿,最终核对标签、目标提交、双语说明、生成变更与产物(不要在此页面点击 Publish release);
- 打开成功精确头
all构建创建的 Publish Release 运行; - 审批其到受保护
release环境的部署。稳定版会被标记为 latest;预发布版保持 prerelease,不取代最新的稳定版。
发布 job 会做最终状态快照:要求已批准运行、草稿、标签、分支与所选 SHA 全部一致;拒绝打开着的发布分支 PR,拒绝每个在发布分支点之后合并、却缺少 backported/v<version> 标签的 hotfix 合并——即使回移植 job 只是排队未开 PR,也会阻塞发布(fail-closed)。审批等待期间发布分支若发生变化,发布会失败关闭,新的精确头构建会创建新的审批。最终快照中拉取的 main SHA 是该发布的 hotfix 截止点,之后合并的 hotfix 归属下一版本。发布后标签对本工作流不可变,已发布的 Release 拒绝更新,后续修复必须走新版本。
6.5 阶段六:合并发布元数据同步 PR
发布触发 Post Release 自动运行。它把已发布标签作为权威元数据源,计算从发布分支点到该标签的纯元数据增量,在 main 快照上以三方合并应用,并打开 release-sync/v<version> PR。该 PR 只允许包含前文列出的四个文件。
收尾操作:
- 评审元数据 PR,确认不含发布分支代码或回移植提交;
- 标题保持精确的
chore(release): sync v<version> metadata; - PR 正文保留
release-metadata-boundary: v<version>标记行; - 等待其 CI 通过;
- Squash 合并时,提交标题为
chore(release): sync v<version> metadata(仅允许附加 GitHub 的可选(#<PR-number>)后缀),且 squash 提交正文须独立成行包含release-metadata-boundary: v<version>。
该 squash 提交正是下一次 Pre Release 使用的发布说明边界(release-note boundary),因此在同步完成前不要开始下一个版本的准备。若元数据已与 main 一致,Post Release 直接退出不开 PR;若之前的元数据 PR 被关闭未合并,可用 GitHub 的 Re-run all jobs 或 gh run rerun <run-id> 重置同步分支并生成替代 PR。
七、常见故障速查(Failure Guide)
| 症状 | 含义 | 解决办法 |
|---|---|---|
| Pre Release 被跳过 | 不是从 main 运行的 | 重新选择 main 运行 |
| 发布分支已存在 | 该版本已准备过 | 检查既有分支与草稿,不要盲目覆盖 |
| 找不到成功的 CI push 运行 | 所选发布提交未通过 CI | 在该精确 SHA 上等待或修复 CI,再重跑 Release |
| 未派发自动构建 | CI 失败、结果过期或已存在精确头构建 | 修复/重跑精确头 CI;仅在构建已失败时手工重试 Release |
分支与 package.json 版本不一致 | 发布引用不一致 | 停止并纠正准备流程,不要强制打标签 |
| Release 已发布 | 已发布的 Release 不能重建 | 准备新版本 |
| 审批过期 | 审批等待期间发布分支移动了 | 使用新精确头全平台构建创建的审批运行 |
backport-failed/v<version> | 自动准备失败或回移植 PR 未合并被关 | 检查关联工作流运行,或按上文手工流程处理 |
| 回移植 PR 未合并被关闭 | hotfix 尚未进入发布分支 | 重新打开 PR 或完成手工回移植 |
| 提交非 Verified 或缺 DCO | Token 身份或签名失败 | 修复工作流/token 配置,绝不绕过检查 |
八、发布流程不变量(Invariants)
分支策略文档隐含并由运行手册显式声明以下不变量,它们共同定义了这套自动化发布体系的边界:
- 内部功能预览只用 Preview Release 从同仓库分支构建;源码仅在受保护
release环境审批后运行,预览草稿永不进入正式发布状态; - 只从
release/v<version>构建,且只发布精确审批过的发布分支 SHA,绝不从main发布; - 每个 hotfix 都先合并进
main,再回移植到发布分支; - hotfix 通过回移植 PR 进入发布分支,绝不通过自动化直接提交;
- 绝不把整个
main合并进活跃发布分支; - 草稿在精确发布提交通过 CI 且所有必需产物齐备之前绝不发布;
- 只通过受保护的 Publish Release 审批发布,绝不从 Releases 页面直接发布;
- 绝不移动已发布的 release 标签;
- 绝不把完整发布分支合并回
main; - 元数据同步 PR 的标题与正文边界标记保持原样、以 squash 方式合并,并在准备下一版本前完成。
九、从仓库确认这些规则(延伸阅读)
分支策略文档所描述的所有规则,均可在仓库中找到对应的强制执行实现与工具脚本:
- 工作流定义:.github/workflows 目录下 27 个 YAML 文件,核心为
prepare-release.yml、release.yml、backport-release-fixes.yml、publish-release.yml、post-release.yml、auto-release-build.yml、preview-release.yml、ci.yml; - 发布工具脚本:scripts/release 下的
hotfix-release-notes.js(双语说明解析与校验)、backport-patch.js(回移植补丁应用)、validate-release-state.js(发布前状态门禁)、validate-prepared-release.js(准备产物校验)、sync-release-history.js(发布历史同步)、compose-release-body.js(发布正文组装)、edition.js(全球版/中国版判定)、validate-edition-artifacts.js(分版本产物校验); - 版本基线解析:
prepare-release.yml中Verify published release baseline步骤,通过semver库强制目标版本严格大于已发布基线; - 测试计划分支:
testplan/rc/x.y.z与testplan/beta/x.y.z的完整规则见 docs/contrib/test-plan.md; - 完整维护者运行手册:docs/contrib/release-workflow.md。
这套"单一开发基线 + 自动化发布分支 + 标签驱动的 hotfix 回移植"模型,使得 Cherry Studio 能够在保持 main 持续迭代的同时,让每个版本的发布、补丁与元数据同步都处于可审计、可回滚的受控状态。
更多推荐
所有评论(0)