Files
ModelRouter/docs/git-workflow.md
JianFeeeee 3806aaee03 docs(workflow): codify the branch model — main / feature / release branches
Adopt GitHub Flow + release branches, replacing "everything straight to main
plus a tag" which caused the 1.4.2 pain (a fix had to be retro-fitted to the
released version, forcing a remote-tag delete + full re-upload).

- main: only long-lived branch, always deployable, accumulates the next version
- feature/<desc>: born from main, merged back when done
- release/vX.Y.Z: cut from main, tagged, installers built from the tag
- hotfixes land on the release branch AND are cherry-picked back to main so
  main never loses a fix
- end of lifecycle = retire the release branch (delete; or keep for long-term
  maintenance), no wholesale merge back — hotfixes already flowed
- explicitly no rebase of main, no release-branch-merge, no quick edits on main

Companion release checklist includes the upload lessons (PUT --http1.1) and the
replace-artifacts-by-deleting-the-tag catch.

Docs in docs/git-workflow.md (zh) and docs/git-workflow-en.md, linked from both
READMEs.
2026-08-31 12:36:17 +08:00

128 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Git 分支工作流Branching Workflow
ModelRouter 采用 **GitHub Flow + 发布分支** 模型:`main` 是唯一长命分支且永远可部署,
新工作从它开出特性分支;每个版本从 `main` 分出独立的发布分支并打 taghotfix 提交到
发布分支且必须回流 `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 <hotfix-commit> # 回主分支
```
这是本模型最重要的一条:**main 只前进、不丢修复**。如果 hotfix 不回 main
下一个版本就会带着旧 bug 发布。
### 版本生命周期结束
下一个版本发布时,上一个 release 分支退役:
- **默认:直接删除远端 release 分支**`git push origin :release/v1.4.2`)。
因为 hotfix 都已逐个 cherry-pick 回 mainmain 已包含全部修复,无需再合并。
- **如需要长期维护旧版**(例如企业大客户卡在旧版本):保留分支,仅 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 流程完全一致。
- **多人 / 开源协作**:特性分支走 PRpull 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 回调失败文件不进列表;
# 替换旧版附件 = 删 tagrelease 随 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)。