# Gitea "Update branch" 之后再 amend 会被 force-with-lease 安全拒推

**日期**: 2026-05-16
**触发**: PR #389 已开，AI review 给了非阻断 needs_fix；我准备 amend 一个小修复再推。
推送时 `git push --force-with-lease` 失败：`! [rejected] (stale info)`。

## 不直观的关键点

在 Gitea PR 页面上点 **"Update branch"** 会**自动**把 base（develop）merge 到 feature 分支（产生一个 merge commit），用来满足 `block_on_outdated_branch=true` 的分支保护规则——**但本地完全感知不到这次 merge**，因为它发生在远端。

后续如果我在本地：

1. `git commit --amend`（基于我本地的旧 tip）
2. `git push --force-with-lease`

force-with-lease 会比对"我记忆中的远端 tip"和"实际远端 tip"，发现不一致 → 拒推。**这正是 force-with-lease 设计的目的**，比起 `--force` 它救了我一次。

## 安全恢复路径

**绝不要** `git push --force` 硬覆盖——会把 Gitea 自动加的 merge commit 删掉，PR 又退回 "outdated branch" 状态。

正确做法：

```bash
git fetch origin <branch>
git reset --hard origin/<branch>      # 放弃本地 amend
# 重新手工应用改动（diff 在 IDE 里还在 / 自己记得）
git add -p && git commit -m "..."     # 作为 NEW commit
git push                              # fast-forward，无需 force
```

## 元规则

- **远端 merge commit ≠ "脏历史"**——它是分支保护机制的一部分，不能随便覆盖
- amend 仅适用于 commit 还**没推**或者**推出去后远端没人动过**的窗口
- 一旦 Gitea 自动加了 merge / 别人在 UI 上动过你的分支，amend 流程作废，改走"新增 commit"流程

## 检测信号

push 报 `! [rejected] (stale info)` 一定先跑 `git fetch + git log --oneline origin/<branch> -3`，看远端是否多了 commit。**不要**条件反射 `--force` 解决。

## 关联

- `--force-with-lease` 文档：救了这次，比 `--force` 强
- 配合 `--force-if-includes`：更严格，但 Gitea web UI 改 base 后也会拒
- 团队约定（CLAUDE.md）：保护分支禁止 force push，feature 分支可 force，但**遇到远端被 merge 时仍应走 fast-forward**
