# git stash pop 跨分支：tracked 文件在目标分支不存在 → DU conflict

**日期**：2026-05-17
**场景**：在分支 A（基于较新 develop，含文件 `foo.mjs`）modified `foo.mjs`，stash 起来。切到分支 B（基于较旧 develop，**不含** `foo.mjs`），stash pop。结果 `foo.mjs` 显示 `DU` 状态（deleted by us, modified by them），merge conflict。

git status 显示：
```
DU docs/templates/README.md
DU docs/templates/flow-renderer.mjs
```

字面"deleted by us, modified by them"令人困惑——这不是用户主动删除，是 git 把"分支 B 没这文件"理解成"我们删了"。

## 根因

stash 存储的是相对当时分支 HEAD 的 **patch（diff）**。pop 时 git 把 patch 应用到当前分支 HEAD：
- 分支 A HEAD 含 `foo.mjs`（origin/develop tip 上的版本）+ patch = "modified" diff
- 分支 B HEAD 不含 `foo.mjs`
- patch 试图 apply 修改到一个"被对方删除"的文件 → conflict 类型 = "they modified, we deleted"
- git 用 `DU` 标记，等用户解决

这不是用户的"删除"动作，是分支 base 差异的副作用。

## 绕方案（推荐）

**从 stash entry 直接 checkout 文件到当前 working tree**：

```bash
git checkout stash@{0} -- docs/templates/README.md docs/templates/flow-renderer.mjs
```

这把 stash entry 里的最终版本（含我所有修改）直接写入当前 working tree，**完全绕开 conflict 解析机制**。文件作为 untracked / staged 状态出现（取决于原 stash 时是否 staged）。

然后：
```bash
git stash drop stash@{0}   # 已经手工取出，丢掉 stash
git add <files>
git commit
```

## 其他绕方案

- `git checkout --theirs <file>` 接受 stash 版本，但前提是 git 把 stash 视为 "theirs"（不一定如此，stash pop 时 theirs/ours 语义混乱）
- `git rm <file>` 然后 `git checkout stash@{0} -- <file>` 重新拿
- 重新 commit 当前分支的"不存在"为 deletion，再 cherry-pick stash 转 commit — 太重

## 防止再踩

**stash 跨分支 pop 前先确认两分支是否有 base 差异**：
```bash
git log --oneline -5 <other-branch>   # 看 base commit
diff <(git ls-tree -r <branch-A> | sort) <(git ls-tree -r <branch-B> | sort) | head
```

如果差异大（一个含某些文件另一个不含），用 `git checkout stash@{0} -- <files>` 而不是 `git stash pop`。

## 项目相关

agent-pool 模式下 slot 切分支频繁，这种"跨分支 stash"场景比单仓库多很多：
- slot 在 feature/X 分支工作
- 临时切 feature/Y 分支看另一个分支的代码
- 切回 X 用 stash 保护改动
- 反向（Y → 含 Y 没有的文件改动 → pop 时 conflict）

记一下绕方案，下次少踩。
