Files
ModelRouter/docs/git-workflow-en.md
JianFeeeee 8578696cc1 chore!: 移除厂商私有协议适配器与渠道业务插件(合规清理)
G-Star 合规要求下,把"模拟官方客户端、复刻私有协议、自动领取平台额度"这一类
能力整体移出仓库。这些实现依赖各平台未公开的端点、签名算法与官方 client id,
属于绕过客户端校验获取额度,风险高于普通协议适配。

移除(93 个文件):
- 适配器:opencodezen(伪装 UA 取免费池)、trae、buddy、kimicode
- 插件:channels.lua(12 个平台登录/领额度/签到)、quota.lua(厂商额度探针)
- 随之删除的 78 个渠道/额度专用测试与 3 份渠道文档

同时修掉的既有问题:
- **硬编码第三方 OAuth client_secret**(Google Cloud Code 的 GOCSPX-…,两处)
  随 channels.lua 一起消失。
- `deploy.sh` 的 `sync_plugins` 整段删除:它仍按"内置插件是发行物"的旧前提
  把插件复制/覆盖进 plugin_dir,与"插件属运维资产、网关不安装不覆盖"的契约
  冲突。现在部署脚本只同步适配器与二进制/配置。
- 适配器清单去掉已移除项;e2e 配置改用显式 `auto:` 链(`models.priority` 早已
  移除,该测试此前已失效)。

保留(公开协议):openai / anthropic / gemini / deepseek / github / groq /
mistral / ollama / qwen38 / sensenova = 10 个适配器;插件示例 billing / usage。

验证:go build -tags luajit ./... OK;internal/lua 21.4s、provider、core 51s、
gateway 122.8s、e2e 9.0s 全绿。
2026-10-27 09:23:24 +08:00

158 lines
6.9 KiB
Markdown

# Git Branching Workflow
ModelRouter uses a **GitHub Flow + release-branch** model: `main` is the only
long-lived branch and is always deployable; new work branches off it as a
feature branch; each version gets its own release branch with a tag; hotfixes
land on the release branch and MUST flow back to `main`.
Goal: make "patching an already-released version during its support window" a
first-class operation, while `main` always contains every fix and stays
deployable.
## Branch roles
| Branch | Name | Lifetime | Purpose |
|---|---|---|---|
| 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`. |
| Release | `release/vX.Y.x` | one version cycle | Cut from `main`, tagged for release. Version-specific hotfixes land here. |
## Change flow (important)
```
feature/foo ───────┐
▼
main ──────────────── next version ──────►
│ │
│ cut │ cut
▼ ▼
release/v1.6.x release/v1.7.x
│ │
tag: v1.6.0 tag: v1.7.6
│ │
hotfix ◄─────┘ hotfix ◄─────┘
│ │
└── 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
1. **main is always deployable**: never leave half-done work on `main`.
Unfinished work lives on a feature branch.
2. **Features start from main and merge back**: `git checkout -b feature/xxx main`,
then `git merge --no-ff feature/xxx` (or squash) when done.
3. **Release = cut a release branch from main + tag**:
```bash
git checkout -b release/v1.7.x main
git tag -a v1.7.0 -m "ModelRouter v1.7.0"
git push origin release/v1.7.x v1.7.0
```
Build installers and upload the GitCode Release from this tag so the
published state is exactly reproducible.
4. **Only version-specific hotfixes go into a release branch during its
window**: new features always go to `main` for the next version, never into
an already-released branch (unless you deliberately ship a minor revision).
5. **Hotfixes MUST flow back to main**:
```bash
git checkout release/v1.7.x # fix in the release branch
git commit -m "fix: ..."
git checkout main
git cherry-pick <hotfix-commit> # and into main
```
Most important rule: **main only moves forward and never loses fixes**. If a
hotfix never reaches main, the next release ships with the old bug.
### End of a version lifecycle
When the next version ships, the previous release branch retires:
- **Default: delete the remote release branch**
(`git push origin :release/v1.7.x`). All hotfixes were already
cherry-picked into main, so main contains everything; no merge needed.
- **Long-term maintenance** (e.g. an enterprise client pinned to an old
version): keep the branch, accept only security fixes, keep the
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
- **Never rebase main**: main's history stays append-only; anyone pulling gets
directly usable history.
- **Release branches are not merged back wholesale**: hotfixes were already
cherry-picked; a whole-branch merge only creates conflicts with no benefit.
- **No "quick edit" directly on main**, even single-person: at minimum use
`feature/xxx → merge main` so history keeps its why-boundaries.
## Single vs multi person
- **Single** (this repo today): skip PRs — `git checkout -b feature/xxx` →
finish → merge back to main. Release branch + tag flow unchanged.
- **Multi / open source**: feature branches go through PR + Code Review,
maintainers merge; resolve conflicts on the feature branch, never on main.
## Commit message conventions
- `feat(...)`: new feature
- `fix(...)`: bug fix
- `chore(...)`: build / version / deps / non-code changes
- `docs(...)`: documentation
- `refactor(...)`: refactoring
- Scope in parens, e.g. `fix(adapters)`, `feat(webui)`, `chore(version)`
- One-line summary; expand with problem/root-cause/fix/verification when needed
## Release checklist (companion)
```bash
# 1. main is ready
git checkout main && git pull
# 2. cut release branch + tag
git checkout -b release/vX.Y.Z main
git tag -a vX.Y.Z -m "ModelRouter vX.Y.Z"
# 3. push branch + tag
git push origin release/vX.Y.Z
git push origin vX.Y.Z
# 4. build installers (core + GUI platforms)
make core-dist VERSION=X.Y.Z
# 5. create GitCode Release + upload
# https://atomgit.com/HeNanMU-EEA/ModelRouter/releases
# upload MUST use PUT --http1.1, otherwise the OBS callback fails and the
# file never lands in the release; replacing artifacts = delete the tag
# (release disappears with it) then recreate.
```
## Why this model (background)
Before 2026-08 everything went straight to `main` plus a tag, which caused two
pain points:
1. After 1.4.2 shipped, a scheduler-scoring fix had to be added to the same
version — the only option was deleting the remote tag to clear the release
and re-uploading all installers. The published state was detached from code
history; "what exactly shipped" could not be traced.
2. No feature branches meant two independent efforts could not proceed in
parallel without colliding.
With release branches: the published state = `release/vX.Y.x` branch +
the concrete `vX.Y.Z` tag, exactly reproducible; hotfixes have a clear landing
spot; main stays "latest + all fixes + deployable".
> 中文版见 [docs/git-workflow.md](git-workflow.md)。