---
date: 2026-04-01
type: deployment-incident
severity: high
tags: [git, pr, deployment, release-pipeline]
---

# PR 合并顺序错误导致生产部署空变更

## 事件

默认语言改动（`defaultLocale: 'zh' → 'en'`）合并到 develop 后，staging PR 因分支落后卡住未能合并，但 production PR 被提前合并了。结果 production 拿到的是一个空 PR（staging 上还没有这个改动），部署后线上文件仍是旧值。

## 根因

三个 PR 是串行发起的（develop → staging → production），但没有严格等待前一个合并成功再发下一个。staging PR 卡在"分支落后需要更新"时，production PR 已经被创建并合并了——此时 staging 还是旧代码，所以 production 合并的 staging → production diff 为空。

## 规则

**PR 合并必须严格串行确认，不能并行：**

```
1. PR → develop: 等待合并成功 ✅
2. PR → staging: 等待合并成功 ✅（必须确认 state=merged）
3. PR → production: 只有 staging 确认合并后才能创建
```

绝不能因为 staging 卡住就跳过去先合 production。staging 合不了就停下来排查，不继续往后走。

## 在发布流程中的检查点

```bash
# 每一步都必须确认 merged=true 才继续
STATE=$(curl -s "$GITEA_API/pulls/$PR_NUM" -H "Authorization: token $GITEA_TOKEN" | python3 -c "import sys,json; d=json.load(sys.stdin); print('merged' if d.get('merged') else d['state'])")
if [ "$STATE" != "merged" ]; then
  echo "STOP: PR #$PR_NUM not merged yet ($STATE), do NOT proceed to next stage"
  exit 1
fi
```

## 补救方式

如果已经发生了空合并到 production：
1. 先合并被卡住的 staging PR
2. 再创建新的 staging → production PR（这次会包含实际变更）
3. 合并后重新部署

## 关联

更新了 `memory/reference_release_pipeline.md` 的发布流程，在每步之间加了强制确认。
