# Promotion PR (develop→staging / staging→production) 卡 outdated 时没有 "Update branch" 按钮，必须开 sync-back PR

**日期**：2026-05-12
**触发场景**：PR #346 (develop→staging) approve 完 + CI 全过，被 "此分支相比基础分支已过期" 阻塞；Gitea web UI 上没有 "Update branch" 按钮可点；API `POST /pulls/{id}/update` 返回 403。

## 现象 vs 预期

用户预期：和 feature PR 一样，右边有个按钮一点就把 base 合进来，up-to-date 解锁。

实际：promotion PR 上**根本不显示**这个按钮 / 显示了点也 403。

## 根因

"Update branch" 不是 UI 魔法，而是 Gitea 在后台执行：

```
git merge <base> into <head>
git push <head>
```

**需要对 head 分支有 push 权限**。

| PR 类型 | head | head 是保护分支 | 能直推 head | Update 按钮 |
|---|---|---|---|---|
| feature/xxx → develop | feature/xxx | 否 | ✅ | ✅ 可点 |
| develop → staging | **develop** | **是** | ❌ | ❌ 隐藏/403 |
| staging → production | **staging** | **是** | ❌ | ❌ 隐藏/403 |

develop/staging/production 三个分支保护规则都禁直推 + `block_on_outdated_branch=true`，没有任何"绕过 PR 直推"的合法通道，所以 promotion PR 卡 outdated 时**没有捷径**。

## 解法：sync-back PR

开一个**反向 PR**把 base 上的新 commit 回吸到 head：

- 卡 develop→staging promotion → 开 `staging → develop` 的 sync-back PR
- 卡 staging→production promotion → 开 `production → staging` 的 sync-back PR

操作（在 slot 里）：

```bash
eval "$(bash scripts/dev/agent-pool/agent-claim.sh chore/sync-back-staging-to-develop develop)"
git fetch origin staging
git merge origin/staging --no-edit
git push -u origin chore/sync-back-staging-to-develop

# 用 Gitea API 开 PR (base=develop, head=sync-back 分支)
curl -X POST -H "Authorization: token $GITEA_API_TOKEN" \
  -H "Content-Type: application/json" \
  "http://43.130.59.228/api/v1/repos/FFAIWorkspace/workspace/pulls" \
  -d '{"title":"...","head":"chore/sync-back-staging-to-develop","base":"develop","body":"..."}'
```

sync-back PR 合掉后，原 promotion PR 自动 up-to-date。

## 为什么会撞

每次上一个 promotion 用 **squash** 合掉时，staging 上生成的 SHA 跟 develop 上的不一样，导致 staging 出现 develop 没有的新 commit。下一个 promotion PR 一开就 outdated。

## 不要尝试

- ❌ 本地 `git push origin develop` —— 保护分支直接拒
- ❌ API `POST /pulls/{id}/update` —— 403
- ❌ Gitea web UI 找 "Update branch" 按钮 —— 不会显示

## 关联

- `block_on_outdated_branch=true` 在 develop / staging / production 都开
- 禁止 PR 作者自合的铁律 —— sync-back PR 同样不能自合，需要另一位成员
- 项目长期改进方向：promotion 默认用 merge commit（保 SHA），不用 squash，可以彻底消灭 sync-back 需求
