docs: 对齐分支命名实际用法 + 修正示例配置的存储位置说明

三处都是"文档说的"与"仓库实际做的"不一致,读文档的人会被误导。

1. 分支命名:文档写 release/vX.Y.Z 且举例 release/v1.4.2,实际从
   release/v1.4.x 起一律用字面 x(release/v1.5.x / v1.7.x)。改成实际情况,
   并说明"一条 minor 分支跨多个 patch"是刻意的:patch 是同批功能的修订,
   hotfix 落同一条分支,回流 main 时不必处理多条 release 分支间的依赖。

2. 退役规则与实践不符:文档说"下个版本发布就删上一个 release 分支",但
   release/v1.4.x / v1.5.x 至今仍在。保留无害(hotfix 已回流),但与规则
   矛盾。两份文档都如实记下这个出入,并记录特性分支**确实**在清理——本次
   删除的四个分支都逐提交用 git patch-id 核对过,工作已全部进入 main
   (唯一 patch-id 不同的是 bf0657b 的发布前变体,diff 过 api.go 改动逐字节
   相同)。留着只是给下个版本制造 cherry-pick/merge 陷阱。

3. 存储位置:示例配置说"WebUI 新增/编辑的源会写入 runtime_file",且默认
   模型注释说 AUTO"按各源 priority 自动选最高可用源"。两处都与实现相反——
   上游源、网关密钥、AUTO 链都在 config.yaml(AddSource 走
   UpsertSourceInYAML,密钥与链走 cfg.Save);runtime.json 只剩源模板、
   删除标记和预置模板名单。已核实 store.Upsert(runtime 源)已无调用点,
   store 里的 Keys/Auto 只被加解密、从不写入,是遗留字段。

priority 本身不是完全没用,所以注释保留并说清它的两个真实用途:首次启动
seedAuto 的初值,以及 AUTO 生图链未配置时挑"最佳模型"(bestChatModel /
bestImageModel 按 priority 取最大)。
This commit is contained in:
JianFeeeee
2026-10-01 20:41:57 +08:00
parent 18e422a943
commit ad54616bee
3 changed files with 56 additions and 21 deletions

View File

@ -15,7 +15,7 @@ deployable.
|---|---|---|---| |---|---|---|---|
| Main | `main` | permanent | Only long-lived branch. Always deployable. Accumulates the next version. | | Main | `main` | permanent | Only long-lived branch. Always deployable. Accumulates the next version. |
| Feature | `feature/<desc>` | short (dev → merge → delete) | New features / ordinary fixes. Born from `main`, merged back into `main`. | | Feature | `feature/<desc>` | short (dev → merge → delete) | New features / ordinary fixes. Born from `main`, merged back into `main`. |
| Release | `release/vX.Y.Z` | one version cycle | Cut from `main`, tagged for release. Version-specific hotfixes land here. | | Release | `release/vX.Y.x` | one version cycle | Cut from `main`, tagged for release. Version-specific hotfixes land here. |
## Change flow (important) ## Change flow (important)
@ -26,15 +26,21 @@ deployable.
│ │ │ │
│ cut │ cut │ cut │ cut
▼ ▼ ▼ ▼
release/v1.4.2 release/v1.4.3 release/v1.6.x release/v1.7.x
│ │ │ │
tag: v1.4.2 tag: v1.4.3 tag: v1.6.0 tag: v1.7.6
│ │ │ │
hotfix ◄─────┘ hotfix ◄─────┘ hotfix ◄─────┘ hotfix ◄─────┘
│ │ │ │
└── cherry-pick back ──────────┘ └── cherry-pick back ──────────┘
``` ```
The patch position in the branch name is a literal `x`, while the tag carries
the concrete version: one `release/v1.7.x` can hold tags v1.7.0 … v1.7.6.
Spanning several patches on a single minor branch is deliberate — patches are
revisions of the same feature batch, hotfixes land on one branch, and back-port
to main never has to resolve dependencies between several release branches.
### Key rules ### Key rules
1. **main is always deployable**: never leave half-done work on `main`. 1. **main is always deployable**: never leave half-done work on `main`.
@ -43,9 +49,9 @@ deployable.
then `git merge --no-ff feature/xxx` (or squash) when done. then `git merge --no-ff feature/xxx` (or squash) when done.
3. **Release = cut a release branch from main + tag**: 3. **Release = cut a release branch from main + tag**:
```bash ```bash
git checkout -b release/v1.4.2 main git checkout -b release/v1.7.x main
git tag -a v1.4.2 -m "ModelRouter v1.4.2" git tag -a v1.7.0 -m "ModelRouter v1.7.0"
git push origin release/v1.4.2 v1.4.2 git push origin release/v1.7.x v1.7.0
``` ```
Build installers and upload the GitCode Release from this tag so the Build installers and upload the GitCode Release from this tag so the
published state is exactly reproducible. published state is exactly reproducible.
@ -54,7 +60,7 @@ deployable.
an already-released branch (unless you deliberately ship a minor revision). an already-released branch (unless you deliberately ship a minor revision).
5. **Hotfixes MUST flow back to main**: 5. **Hotfixes MUST flow back to main**:
```bash ```bash
git checkout release/v1.4.2 # fix in the release branch git checkout release/v1.7.x # fix in the release branch
git commit -m "fix: ..." git commit -m "fix: ..."
git checkout main git checkout main
git cherry-pick <hotfix-commit> # and into main git cherry-pick <hotfix-commit> # and into main
@ -67,12 +73,23 @@ deployable.
When the next version ships, the previous release branch retires: When the next version ships, the previous release branch retires:
- **Default: delete the remote release branch** - **Default: delete the remote release branch**
(`git push origin :release/v1.4.2`). All hotfixes were already (`git push origin :release/v1.7.x`). All hotfixes were already
cherry-picked into main, so main contains everything; no merge needed. cherry-picked into main, so main contains everything; no merge needed.
- **Long-term maintenance** (e.g. an enterprise client pinned to an old - **Long-term maintenance** (e.g. an enterprise client pinned to an old
version): keep the branch, accept only security fixes, keep the version): keep the branch, accept only security fixes, keep the
commit-then-cherry-pick loop. commit-then-cherry-pick loop.
> **Where practice diverged from this section (checked 2026-10-01)**:
> `release/v1.4.x` and `release/v1.5.x` still exist locally and on the remote,
> so "retire the previous branch when the next version ships" was never
> carried out. Keeping them is harmless (hotfixes were back-ported), but it
> contradicts the rule above and makes a reader wonder whether they should be
> there at all. **Feature branches, by contrast, are cleaned up**:
> `feature/key-quota-control`, `feature/toolcall-id-sanitize`,
> `feature/anthropic-usage-cache` and `feature/agentrouter-id-sanitize` were
> deleted on 2026-10-01 after confirming with a per-commit `git patch-id`
> comparison that their work had already landed in main.
## Explicit non-goals ## Explicit non-goals
- **Never rebase main**: main's history stays append-only; anyone pulling gets - **Never rebase main**: main's history stays append-only; anyone pulling gets
@ -134,8 +151,8 @@ pain points:
2. No feature branches meant two independent efforts could not proceed in 2. No feature branches meant two independent efforts could not proceed in
parallel without colliding. parallel without colliding.
With release branches: the published state = `release/vX.Y.Z` branch + With release branches: the published state = `release/vX.Y.x` branch +
`vX.Y.Z` tag, exactly reproducible; hotfixes have a clear landing spot; main the concrete `vX.Y.Z` tag, exactly reproducible; hotfixes have a clear landing
stays "latest + all fixes + deployable". spot; main stays "latest + all fixes + deployable".
> 中文版见 [docs/git-workflow.md](git-workflow.md)。 > 中文版见 [docs/git-workflow.md](git-workflow.md)。

View File

@ -13,7 +13,7 @@ ModelRouter 采用 **GitHub Flow + 发布分支** 模型:`main` 是唯一长
|---|---|---|---| |---|---|---|---|
| 主分支 | `main` | 永久 | 唯一长命分支。永远可部署。积攒下一个版本的功能。 | | 主分支 | `main` | 永久 | 唯一长命分支。永远可部署。积攒下一个版本的功能。 |
| 特性分支 | `feature/<描述>` | 短命(开发→合并即删) | 新特性 / 一般 bug 修复。从 `main` 开出,完成后合回 `main`。 | | 特性分支 | `feature/<描述>` | 短命(开发→合并即删) | 新特性 / 一般 bug 修复。从 `main` 开出,完成后合回 `main`。 |
| 发布分支 | `release/vX.Y.Z` | 一个版本周期 | 从 `main` 分出,打 tag 发布。该版本生命周期内的 hotfix 都提交在此分支。 | | 发布分支 | `release/vX.Y.x` | 一个版本周期 | 从 `main` 分出,打 tag 发布。该版本生命周期内的 hotfix 都提交在此分支。 |
## 变更流向(重要) ## 变更流向(重要)
@ -24,15 +24,20 @@ ModelRouter 采用 **GitHub Flow + 发布分支** 模型:`main` 是唯一长
│ │ │ │
│ 切出 │ 切出 │ 切出 │ 切出
▼ ▼ ▼ ▼
release/v1.4.2 release/v1.4.3 release/v1.6.x release/v1.7.x
│ │ │ │
tag: v1.4.2 tag: v1.4.3 tag: v1.6.0 tag: v1.7.6
│ │ │ │
hotfix ◄─────┘ hotfix ◄─────┘ hotfix ◄─────┘ hotfix ◄─────┘
│ │ │ │
└── cherry-pick 回 main ───────┘ └── cherry-pick 回 main ───────┘
``` ```
分支名里 patch 位是**字面的 x**,而 tag 打具体版本号:`release/v1.7.x` 这一条
发布分支上的 tag 可以有 v1.7.0 … v1.7.6 多个。一条 minor 分支跨多个 patch 是
刻意的:patch 是同一批功能的不同修订,hotfix 落在同一条分支上,回流 main 时
也不必处理多条 release 分支之间的依赖。
### 关键规则 ### 关键规则
1. **main 永远可部署**:不在 main 上留半成品。任何未完成的工作必须在特性分支上。 1. **main 永远可部署**:不在 main 上留半成品。任何未完成的工作必须在特性分支上。
@ -40,16 +45,16 @@ ModelRouter 采用 **GitHub Flow + 发布分支** 模型:`main` 是唯一长
开发完 `git merge --no-ff feature/xxx` 或 squash 合回。 开发完 `git merge --no-ff feature/xxx` 或 squash 合回。
3. **发布 = 从 main 切 release 分支 + 打 tag**: 3. **发布 = 从 main 切 release 分支 + 打 tag**:
```bash ```bash
git checkout -b release/v1.4.2 main git checkout -b release/v1.7.x main
git tag -a v1.4.2 -m "ModelRouter v1.4.2" git tag -a v1.7.0 -m "ModelRouter v1.7.0"
git push origin release/v1.4.2 v1.4.2 git push origin release/v1.7.x v1.7.0
``` ```
构建安装包、上传 GitCode Release 都基于这个 tag,保证可精确回溯发布态。 构建安装包、上传 GitCode Release 都基于这个 tag,保证可精确回溯发布态。
4. **版本生命周期内只收该版本的 hotfix**:新特性一律并入 `main` 等下一个版本, 4. **版本生命周期内只收该版本的 hotfix**:新特性一律并入 `main` 等下一个版本,
绝不塞进已发布的 release 分支(除非主动选择在该版本内发次要版)。 绝不塞进已发布的 release 分支(除非主动选择在该版本内发次要版)。
5. **hotfix 必须回流 main**: 5. **hotfix 必须回流 main**:
```bash ```bash
git checkout release/v1.4.2 # 在发布分支提交修复 git checkout release/v1.7.x # 在发布分支提交修复
git commit -m "fix: ..." git commit -m "fix: ..."
git checkout main git checkout main
git cherry-pick <hotfix-commit> # 回主分支 git cherry-pick <hotfix-commit> # 回主分支
@ -61,11 +66,20 @@ ModelRouter 采用 **GitHub Flow + 发布分支** 模型:`main` 是唯一长
下一个版本发布时,上一个 release 分支退役: 下一个版本发布时,上一个 release 分支退役:
- **默认:直接删除远端 release 分支**(`git push origin :release/v1.4.2`)。 - **默认:直接删除远端 release 分支**(`git push origin :release/v1.7.x`)。
因为 hotfix 都已逐个 cherry-pick 回 main,main 已包含全部修复,无需再合并。 因为 hotfix 都已逐个 cherry-pick 回 main,main 已包含全部修复,无需再合并。
- **如需要长期维护旧版**(例如企业大客户卡在旧版本):保留分支,仅 stopship 接受 - **如需要长期维护旧版**(例如企业大客户卡在旧版本):保留分支,仅 stopship 接受
该版本的安全修复,继续走「提交 + cherry-pick 回 main」循环。 该版本的安全修复,继续走「提交 + cherry-pick 回 main」循环。
> **实践与本节的历史出入(2026-10-01 核对)**:`release/v1.4.x` 与 `release/v1.5.x`
> 至今仍在本地与远端,说明"下一个版本发布就删上一个分支"实际没有执行。
> 保留无害(hotfix 已回流),但它与上面写的规则不一致,读文档的人会以为
> 这些分支不该存在。**特性分支则确实在清理**:`feature/key-quota-control`、
> `feature/toolcall-id-sanitize`、`feature/anthropic-usage-cache`、
> `feature/agentrouter-id-sanitize` 四个分支在 2026-10-01 删除——它们的工作
> 早已全部进入 main(逐提交用 `git patch-id` 比对确认),留着只是给下个版本
> 制造 cherry-pick/merge 陷阱。
## 明确不做的事 ## 明确不做的事
- **不 rebase main**:`main` 的历史保持追加式,任何人拉取后 `git pull` 都得到直接可用的历史。 - **不 rebase main**:`main` 的历史保持追加式,任何人拉取后 `git pull` 都得到直接可用的历史。

View File

@ -13,13 +13,17 @@ listen: 127.0.0.1:8080
# 客户端访问本网关所需的 API Key(Bearer)。留空数组 = 不鉴权(仅内网)。 # 客户端访问本网关所需的 API Key(Bearer)。留空数组 = 不鉴权(仅内网)。
gateway_keys: [] gateway_keys: []
# 默认模型选择:具体模型 id 或 AUTO(按各源模型的 priority 自动选最高可用源) # 默认模型选择:具体模型 id 或 AUTO。
# AUTO = 走 WebUI「优先级页」保存的调度链(存在本文件的 `auto:` 字段)。
default_model: AUTO default_model: AUTO
# Lua 适配器目录(默认 adapters/,首次启动自动写入内置适配器) # Lua 适配器目录(默认 adapters/,首次启动自动写入内置适配器)
adapter_dir: adapters adapter_dir: adapters
# 运行时持久化文件(WebUI 新增/编辑的源会写入此文件,重启后仍生效) # 运行时文件:存放 WebUI 管理的源模板、已删除标记、预置模板名单。
#
# 注意:**AUTO 调度链、网关密钥、上游源都存在本 config.yaml 里**,
# 不在这个文件。runtime.json 只管模板与删除标记。
runtime_file: runtime.json runtime_file: runtime.json
# 全局并发上限(0 = 不限) # 全局并发上限(0 = 不限)