# Git 分支工作流(Branching Workflow) ModelRouter 采用 **GitHub Flow + 发布分支** 模型:`main` 是唯一长命分支且永远可部署, 新工作从它开出特性分支;每个版本从 `main` 分出独立的发布分支并打 tag;hotfix 提交到 发布分支且必须回流 `main`。 目的:让「已发版的版本在生命周期内可被单独修补」成为一等操作,同时 `main` 始终包含 全部修复、永远可部署。 ## 分支角色 | 分支 | 命名 | 生命周期 | 用途 | |---|---|---|---| | 主分支 | `main` | 永久 | 唯一长命分支。永远可部署。积攒下一个版本的功能。 | | 特性分支 | `feature/<描述>` | 短命(开发→合并即删) | 新特性 / 一般 bug 修复。从 `main` 开出,完成后合回 `main`。 | | 发布分支 | `release/vX.Y.Z` | 一个版本周期 | 从 `main` 分出,打 tag 发布。该版本生命周期内的 hotfix 都提交在此分支。 | ## 变更流向(重要) ``` feature/foo ───────┐ ▼ main ──────────────── 下一个版本 ──────► │ │ │ 切出 │ 切出 ▼ ▼ release/v1.4.2 release/v1.4.3 │ │ tag: v1.4.2 tag: v1.4.3 │ │ hotfix ◄─────┘ hotfix ◄─────┘ │ │ └── cherry-pick 回 main ───────┘ ``` ### 关键规则 1. **main 永远可部署**:不在 main 上留半成品。任何未完成的工作必须在特性分支上。 2. **特性从 main 开,完成后合回 main**:`git checkout -b feature/xxx main`, 开发完 `git merge --no-ff feature/xxx` 或 squash 合回。 3. **发布 = 从 main 切 release 分支 + 打 tag**: ```bash git checkout -b release/v1.4.2 main git tag -a v1.4.2 -m "ModelRouter v1.4.2" git push origin release/v1.4.2 v1.4.2 ``` 构建安装包、上传 GitCode Release 都基于这个 tag,保证可精确回溯发布态。 4. **版本生命周期内只收该版本的 hotfix**:新特性一律并入 `main` 等下一个版本, 绝不塞进已发布的 release 分支(除非主动选择在该版本内发次要版)。 5. **hotfix 必须回流 main**: ```bash git checkout release/v1.4.2 # 在发布分支提交修复 git commit -m "fix: ..." git checkout main git cherry-pick # 回主分支 ``` 这是本模型最重要的一条:**main 只前进、不丢修复**。如果 hotfix 不回 main, 下一个版本就会带着旧 bug 发布。 ### 版本生命周期结束 下一个版本发布时,上一个 release 分支退役: - **默认:直接删除远端 release 分支**(`git push origin :release/v1.4.2`)。 因为 hotfix 都已逐个 cherry-pick 回 main,main 已包含全部修复,无需再合并。 - **如需要长期维护旧版**(例如企业大客户卡在旧版本):保留分支,仅 stopship 接受 该版本的安全修复,继续走「提交 + cherry-pick 回 main」循环。 ## 明确不做的事 - **不 rebase main**:`main` 的历史保持追加式,任何人拉取后 `git pull` 都得到直接可用的历史。 - **发布分支不整体 merge 回 main**:hotfix 已逐个 cherry-pick,整体合并只会制造冲突且无收益。 - **不在 main 直接写"临时改一下"**:即使是单人项目,也至少走 `feature/xxx → merge main` 的形式,让历史保留"为什么改"的边界。 ## 单人 vs 多人 - **单人**(本项目当前):特性分支可省去 PR,`git checkout -b feature/xxx` → 完成 → 合并回 main。发布分支与 tag 流程完全一致。 - **多人 / 开源协作**:特性分支走 PR(pull request)+ Code Review, 由维护者 merge;冲突在特性分支上解决,不在 main 上解决。 ## 提交信息规范(与分支配套) - `feat(...)`: 新功能 - `fix(...)`: 修复 - `chore(...)`: 构建 / 版本号 / 依赖 / 文档无关改动 - `docs(...)`: 文档 - `refactor(...)`: 重构 - 括号内为影响域,如 `fix(adapters)`、`feat(webui)`、`chore(version)` - 一句话总结,必要时正文展开「问题 / 根因 / 修复 / 验证」 ## 发布操作速查(配套) 每次发布严格按此顺序: ```bash # 1. 确认 main 就绪 git checkout main && git pull # 2. 切发布分支并打 tag git checkout -b release/vX.Y.Z main git tag -a vX.Y.Z -m "ModelRouter vX.Y.Z" # 3. 推送分支 + tag git push origin release/vX.Y.Z git push origin vX.Y.Z # 4. 构建安装包(核心包 + GUI 各平台) make core-dist VERSION=X.Y.Z # 5. 创建 GitCode Release + 上传安装包 # 见 https://gitcode.com/JianFeeeee/ModelRouter/releases # 上传注意:必须 PUT --http1.1,否则 OBS 回调失败文件不进列表; # 替换旧版附件 = 删 tag(release 随 tag 一起消失)后重建。 ``` ## 为什么是这套(背景) 2026-08 之前本项目直接在所有改动提交到 `main` + 打 tag,出现两个痛点: 1. 1.4.2 已发版后又追了一个调度打分修复,只能删远端 tag 清空 release 再重传安装包 —— 版本发布态与代码历史脱节,无法精确回溯"当时发的是什么"。 2. 没有特性分支,无法并行开发互不干扰的两件事。 引入发布分支后:版本发布态 = `release/vX.Y.Z` 分支 + `vX.Y.Z` tag,可精确回溯; hotfix 有明确落点;main 保持"最新 + 全部修复 + 可部署"。 > 英文版见 [docs/git-workflow-en.md](git-workflow-en.md)。