etcd 分支管理实践:main 开发分支、release-X.Y 稳定分支与滚动发布模型
etcd 采用滚动发布模型(rolling release model)管理其 Git 分支:main 是唯一开发分支,所有新功能先落地于此;每个 minor 版本发布后会冻结出一条 release-X.Y 稳定分支,社区仅维护最近两个稳定版本,补丁(patch)以 cherry-pick 方式回合。读完本文,你可以理解 etcd 的版本分支体系、判断一个 PR 应该针对哪个分支提交,并掌握从 main 切出新稳定分支、以及向稳定分支回移修复的完整机制。
一、滚动发布模型总览
etcd 团队采用了滚动发布模型,并支持两个稳定版本(two stable versions)的 etcd。其核心规则如下(源自 Documentation/contributor-guide/branch_management.md):
- 新开发工作发生在
main分支上; main分支必须始终保持绿色构建(green build);- 向后兼容的 bug 修复应针对
main分支提交,随后被回合(port)到稳定分支; - 当
main分支准备好发布时,它会被打上 tag,并成为新的稳定分支。
所有版本号遵循 语义化版本 2.0.0(semver)规范。仓库内的证据与这套规范一一对应:CHANGELOG/ 目录按主版本组织变更记录(CHANGELOG-3.4.md、CHANGELOG-3.5.md、CHANGELOG-3.6.md、CHANGELOG-3.7.md、CHANGELOG-4.0.md 等,见 CHANGELOG/README.md),而 api/version/version.go 中维护着当前 main 分支的版本常量与集群兼容版本:
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
MinClusterVersion = "3.0.0"
Version = "3.8.0-alpha.0"
当前 main 分支的版本号带有 -alpha.0 后缀,这正是"main 是预发布/开发分支"这一分支管理策略的直接体现:main 上的版本总是下一个 minor 版本的 alpha 预发布,直到正式发布被 tag 出去。同一文件中还定义了 V3_0 到 V4_0 的完整版本枚举(api/version/version.go),供集群混合版本(mixed-version)逻辑使用。
二、main 开发分支
main 分支是 etcd 的开发分支,所有新功能(new features)都首先在这里落地。
- 试验新功能:想要尝鲜实验性特性,应拉取
main分支进行尝试。官方提醒:main可能不稳定,因为新功能可能引入 bug。 - Feature freeze(功能冻结):在下一个稳定版本发布前,功能类 PR 会被冻结。会为该 major/minor 版本指派一名发布经理(release manager),带领 etcd 社区进行为期一到两周的测试、修复与发布文档整理。
发布经理团队与具体职责在 Documentation/contributor-guide/release.md 的 "Release management" 一节有完整说明:所有发布版本编号遵循语义化版本 2.0.0;major/minor 版本(或其预发布)发布前需要确认对应 milestone 已完成、升级文档已就绪,并在必要时 bump 仓库中硬编码的 MinClusterVersion。
从 CI 角度看,main 分支的绿色构建由 Prow 的 presubmit 任务保障:etcd 的 CI 托管在 kubernetes/test-infra 的 Prow 上,PR 提交后会自动运行静态检查、单元、集成与 e2e 测试(如 pull-etcd-e2e-amd64 这类任务会针对 main、release-3.6、release-3.5、release-3.4 等分支运行),详见 Documentation/contributor-guide/prow_jobs.md。这解释了为什么分支管理规则要求"main 必须始终绿色"——它是所有稳定分支未来代码的上游。
三、稳定分支(release- 前缀)
所有以 release- 为前缀的分支都被视为稳定分支(stable branches),例如 release-3.4、release-3.5、release-3.6。当前仓库中可观察到从 release-0.4 到 release-3.7 的一整排历史稳定分支,完整体现了 etcd 自 3.x 时代延续下来的分支命名惯例。
稳定分支的生命周期规则:
- 每个 minor 版本发布后,都会为该版本新建一条稳定分支,由**补丁发布经理(patch release manager)**负责管理;
- 社区持续修复最近两个稳定发布中向后兼容的 bug;
- 在每个受支持的发布分支上,只要存在需要回合的补丁,就每两周发布一次 patch 版本。
这里的关键约束是"只支持最近两个稳定版本":当 release-3.7 与 release-3.6 同时受支持时,release-3.5 就不再接收新的 patch 发布。补丁发布的具体门槛在 Documentation/contributor-guide/release.md 的 "Patch release criteria" 一节给出了量化标准:
- 修复了一个或多个重大 CVE(CVSS ≥ 7.5);
- 修复了一个或多个关键 bug;
- 修复了三个或更多重要 bug;
- 修复了五个或更多次要 bug。
满足上述任一条件才值得发布新的 patch 版本,配合"每两周一次"的节奏,保证了补丁发布既及时又不泛滥。
四、分支是如何诞生的:从 main 到新稳定分支
branch_management 文档中"main 被 tag 后即成为新稳定分支"这一句话,在仓库的发布流程中对应具体的可执行步骤。
4.1 切出稳定分支
在 Documentation/contributor-guide/release.md 的 "Release steps" 第 9 步中写得很明确:如果本次是新的 major 或 minor 稳定发布,发布完成后通过如下命令创建新的稳定分支:
git push origin release-${VERSION_MAJOR}.${VERSION_MINOR}
也就是说,稳定分支不是长期并行开发的,而是 main 到达发布点后"切分"出来的快照,之后只接收回合的修复。
4.2 发布脚本中的分支语义
发布脚本 scripts/release.sh 进一步印证了分支与版本的对应关系:
if [ -z "${BRANCH:-}" ]; then
BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
BRANCH=${BRANCH:-"release-${MINOR_VERSION}"}
fi
脚本从版本号(如 3.5.13)推导出 minor 版本,并把默认发布分支解析为 release-${MINOR_VERSION};同时脚本会校验 git tag 确实打在 ${BRANCH} 上,否则报错终止(见 scripts/release.sh)。文档中给出的发布命令是:
# 在仓库根目录执行,${VERSION} 为不带 v 前缀的版本号,如 3.5.13
DRY_RUN=false ./scripts/release.sh ${VERSION}
# 预发布(来自 main 分支的版本,如 3.6.0-alpha.2)需显式指定 BRANCH=main
DRY_RUN=false BRANCH=main ./scripts/release.sh ${VERSION}
注意最后一行:预发布(alpha/beta/rc)从 main 分支发布,而正式 patch 发布从 release-X.Y 分支发布。这与 api/version/version.go 中 main 分支 Version = "3.8.0-alpha.0" 的状态完全吻合——main 产出预发布 tag,stable 分支产出正式 tag。仓库构建工具链版本由 .go-version(当前为 1.26.6)约束,发布前置条件中也要求本地 Go 版本与该文件保持一致。
五、变更如何回移:cherry-pick 到稳定分支
branch_management 规定"向后兼容的 bug 修复先提交到 main,随后回合到稳定分支"。这个"随后回合"的机制在 Documentation/contributor-guide/cherry-pick.md 中完整描述,有两条路径:
5.1 自动化路径(推荐)
cherry-pick 主要由 k8s-infra-cherrypick-robot 处理。在已合并的 PR 下评论目标分支即可:
/cherry-pick release-3.6
机器人会自动创建一个针对目标 release 分支的 cherry-pick PR。注意 release.md 中的约束:cherry-pick PR 的提交不应包含 merge commits,且内容应严格限定为 bug 修复与安全补丁;补丁发布经理会审核这些 PR,并从最旧的提交开始按顺序 cherry-pick 到稳定分支,保证每个 patch 发布都严格优于其前一个版本。
5.2 手动回退路径
当自动化机器人不可用时,仓库自带了回移脚本 scripts/cherrypick.sh(基于 kubernetes 社区的 cherry_pick_pull.sh 改造)。先设置远程与环境变量:
export UPSTREAM_REMOTE=upstream # 指向 github.com/etcd-io/etcd 的 remote 名
export FORK_REMOTE=origin # 指向自己 fork 仓库的 remote 名
export GITHUB_USER=${github-username}
然后将 PR 回移到指定分支并自动发起 PR:
# 将 PR 12345 cherry-pick 到 release-3.6 并提案为 PR
./scripts/cherrypick.sh ${UPSTREAM_REMOTE}/release-3.6 12345
# 将 12345 和 56789 合并回移,作为单个 PR 提案
./scripts/cherrypick.sh ${UPSTREAM_REMOTE}/release-3.6 12345 56789
从源码看(scripts/cherrypick.sh),脚本要求工作树干净、没有进行中的 rebase/am,会校验目标分支是真实存在的远程分支,并通过 hub 工具创建 PR;设置 DRY_RUN 环境变量可跳过 push 和建 PR,只把回移的提交留在本地分支中,方便制作不打 PR 的补丁。
六、对贡献者的实战指引
把上述机制落到日常贡献场景,可以归纳为一张决策表:
| 你要做的事 | 目标分支 | 说明 |
|---|---|---|
| 新增功能、API 变更 | main |
所有新特性先落地 main;main 处于 alpha 状态,可放心开发 |
| 修复向后兼容的 bug | main |
合并后由机器人/经理回合到受支持的 release-X.Y |
| 请求修复进入稳定版 | 在已合并的 main PR 上评论 /cherry-pick release-X.Y |
仅限 bug 修复与安全补丁,不含 merge commit |
| 体验最新特性 | 检出 main 构建 |
可能不稳定,不建议生产使用 |
| 生产环境使用 | 受支持的 release-X.Y 分支/发布 tag |
仅最近两个 minor 版本获得 patch 支持 |
几个补充要点:
- feature freeze 期间不要提功能 PR:下一个稳定版本发布前一到两周内,main 上功能类 PR 冻结,只有 bug 修复和文档类变更会被处理,此时由该版本的 release manager 主导。
- stable 分支不做 feature 演进:补丁发布经理的职责是维持稳定分支的健康,回移内容被严格限制在 bug 修复与安全补丁,这与 features 文档中"patch 发布不承担 feature 毕业/废弃"的规则(见 Documentation/contributor-guide/features.md)一致。
- 版本联动:稳定分支的发布还会触发下游联动——例如 etcd 3.6 补丁需要 bump 到 Kubernetes 1.34 及更新版本,3.5 补丁 bump 到 Kubernetes 1.33 及更早受支持版本,流程见 Documentation/contributor-guide/bump_etcd_version_k8s.md。这说明 etcd 的分支体系不是孤立的,而是与整个 Kubernetes 生态的发布节奏耦合在一起的。
七、小结
etcd 的分支管理可以浓缩为三条主线:main 负责演进(新功能、alpha 预发布、feature freeze 管理)、release-X.Y 负责稳定(每两周一次的 patch 节奏、只支持最近两个 minor 版本、严格限制回移内容)、cherry-pick 负责两者之间的桥接(机器人自动化优先,scripts/cherrypick.sh 手动兜底)。理解这套模型后,无论是提交 PR、参与发布还是排查版本兼容性,都能准确地把变更放到正确的分支上。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00