# 2026-05-20 bash cwd 跨命令丢失 → 相对路径打到主仓库 develop 提交

## 背景

本月在 slot 内做 PR 修复时,踩坑 2 次:
- **#457 收尾 PR (enum UPPER_SNAKE)**: sed/python 多行命令在 slot-2 执行,但 cwd
  突然跑到主仓库,sed 修改了主仓库的文件而非 slot-2 的;commit 落在主仓库
  develop 分支 (`[develop 9f87a38c]`),保护分支拒推救了一命。
- **#474 PR-A 第 2 批**: 类似 — git commit 前 git status 显示 `develop` 分支
  + "nothing to commit",而 slot-2 工作树确实有变更。

两次都是**真实 bug,差点污染主仓库 develop**(CLAUDE.md §14 铁律违反)。

## 根因 (3 层)

### 表面症状
bash 命令的 `git branch --show-current` 返回 `develop`,而我以为在
`feature/410-...` 或 `chore/...` 分支;commit/push 行为出错。

### 直接原因
Bash 工具说明:"working directory persists between commands, but shell state
does not"。但实际观察:**某些 chained bash 命令 (含 heredoc / python -c <<PY ...
PY / multi-line) 之后,后续单独 Bash 调用的 pwd 会重置到 prompt 工作目录
(主仓库 `/home/lijian/Code/workspace`)**。

具体触发场景:
- 长命令含 `python3 <<'PY' ... PY` heredoc → 后续命令 pwd 回主仓库
- 长命令含 `sed -i.bak` + `python3` + `rm` 链 → pwd 重置
- Edit 工具 (绝对路径不受影响) ↔ Bash 工具 (相对路径) 混用 → 工作树跟 bash pwd 解耦

**矛盾点**:Edit 工具用绝对路径直达 slot-2 工作树,所以**文件确实改在 slot-2**;
但接下来的 Bash `git add docs/...` 用相对路径,git 跑在主仓库 cwd → "nothing to commit"
(主仓库无对应改动) OR sed 命令直接编辑了主仓库相同路径文件 (污染)。

### 元根因
1. **Bash 工具 cwd 持久化承诺与实际不一致**:
   工具说明声称 cwd 持久,但跨复杂命令实测不稳;不能依赖 1 次 `cd` 跨 10+ Bash 调用持久。
2. **slot 工作树跟主仓库 .git 共用**:
   git worktree 模型下,所有 worktree 共享同一 `.git`;相对路径解析依赖 bash cwd
   而非 git worktree 概念;cwd 错位时 git 在主仓库 cwd 跑 → 提交记录落主仓库分支。
3. **bash 跨命令状态隔离不可见**:
   shell state 不持久 (env vars / aliases 不跨命令);但 cwd "声明" 持久 →
   实际混合行为,debugging 困难。

## 预防 + 检测 + 恢复 SOP

### 预防 (每次 bash 调用 git 类命令前)

**铁律: 关键 git 操作 (add / commit / push / rebase) 前必须 `cd <绝对路径>` 同一行**。

```bash
# ❌ 危险: 假设 cwd 持久
git add docs/...
git commit -m "..."

# ✅ 安全: cd + 操作 同一 bash 调用
cd /home/lijian/Code/workspace-wt/.agent-pool/slot-N && git add docs/... && git commit -m "..."

# ✅ 更安全: 加 branch 校验防线
cd /home/lijian/Code/workspace-wt/.agent-pool/slot-N && \
  [ "$(git branch --show-current)" = "<expected-branch>" ] && \
  git add docs/... && git commit -m "..."
```

### 检测 (commit 后立即验证)

```bash
# git commit 后第一时间检查 commit 落在哪个分支
git log --oneline -1
# 期望: [chore/learnings-xxx aaaaaaa] commit message
# 异常: [develop xxxxxxx] commit message  ← 主仓库污染!
```

git commit 的 stdout `[<branch> <hash>]` 是 first signal。出现 `[develop ...]` /
`[main ...]` / `[staging ...]` / `[production ...]` 等保护分支立即停。

### 恢复 (主仓库 develop 已被污染)

```bash
# Step 1: 主仓库 reset 回 origin (clean drift)
cd /home/lijian/Code/workspace && git reset --hard origin/develop
# 验证 git log --oneline -1 = 远端最新 commit

# Step 2: cherry-pick 该 commit 到正确 slot 分支
cd /home/lijian/Code/workspace-wt/.agent-pool/slot-N
git cherry-pick <orphan-commit-sha>
# (push -u 后开 PR 即可)

# Step 3: 主仓库保护分支拒推已经救了 (CLAUDE.md §14 + branch protection),
# 不需要担心远端 develop 被污染;只需清本地
```

### 工具层保险 (推荐)

考虑给 bash 工具调用前置 `pwd-check.sh` hook 或在 `~/.bashrc` 加 PROMPT_COMMAND
检查 cwd,但代价 vs 收益不明显;靠上述 SOP 即可。

## 跨任务可复用经验

1. **不信 cwd 持久承诺**: 关键 git 操作前永远显式 `cd <abs-path> &&`
2. **git commit 后立即看 stdout 第一行**: `[<branch> <hash>]` 是免费的检测信号,不要忽略
3. **Edit 工具用绝对路径是好习惯但不够**: 文件改对了不代表 git 操作跑对位置
4. **主仓库保护分支 + branch protection 是真兜底**: 即使 commit 出错也只是
   本地 dirty,不会污染远端 (但 CLAUDE.md §14 铁律仍要求主仓库 clean,所以必须 reset)
5. **复杂 bash 链 (heredoc + sed + python) 后,下一个 git 命令必须重新 `cd`**:
   测试发现这是高风险触发场景,不要省略 cd

## 相关链接

- CLAUDE.md §14 主仓库工作目录只读 (铁律)
- CLAUDE.md § Agent 自报家门 (每轮启动判断当前位置)
- `.learnings/2026-05-19-main-repo-drift-meta-rootcause.md` (3 次连环踩坑 + UserPromptSubmit hook 兜底)
- `scripts/ops/hooks/main-repo-readonly-guard.sh` (hook 检测主仓库 dirty)
- PR #457 commit `9f87a38c` (第 1 次踩坑事故)
- PR #474 - "nothing to commit" 假象 (第 2 次,通过 cd 重新校正补救)
