# Worktree 场景下 `.git/MERGE_HEAD` 检测要用 `git rev-parse --git-dir`

**日期**：2026-05-18
**场景**：PR #426 merge develop 解冲突后 commit，pre-commit hook 把 merge commit 里跨多 commit 带的多个 migration 当作"单 commit 多迁移"违规拦下来。修 hook 让 merge commit 跳过 migration count，但**第一次修错了**——硬编码 `.git/MERGE_HEAD` 路径，worktree 场景下找不到。

## 不直观的发现

git worktree（`git worktree add`）下：
- worktree 根目录的 `.git` 是 **file**（不是 directory），内容形如 `gitdir: /<main-repo>/.git/worktrees/<wt-name>`
- 所有 `MERGE_HEAD` / `REBASE_HEAD` / `CHERRY_PICK_HEAD` / `MERGE_MSG` 等中间状态文件**不在** worktree 的 `.git/`，**而在** `/<main-repo>/.git/worktrees/<wt-name>/`

```bash
# 在 worktree 里
$ ls -la .git
-rw-rw-r-- 1 user user 59 May  9 13:53 .git  ← file 不是 directory!
$ cat .git
gitdir: /home/chentao/Code/workspace/.git/worktrees/slot-3
$ git rev-parse --git-dir
/home/chentao/Code/workspace/.git/worktrees/slot-3
```

如果 hook / 脚本硬编码 `${ROOT_DIR}/.git/MERGE_HEAD` 检查 merge 状态，在 main worktree 上会工作（`.git` 是 dir），但在 git worktree 下**永远找不到**（`.git` 是 file，不能 cd 进去）。

## 解决

**永远用 `git rev-parse --git-dir`** 拿真实 git dir 路径：

```bash
# ❌ 错（worktree 下失效）
if [ -f "${ROOT_DIR}/.git/MERGE_HEAD" ]; then
  echo "in merge"
fi

# ✅ 对（worktree + main 都工作）
GIT_DIR_PATH="$(git rev-parse --git-dir)"
if [ -f "${GIT_DIR_PATH}/MERGE_HEAD" ]; then
  echo "in merge"
fi
```

同样适用 `REBASE_HEAD` / `CHERRY_PICK_HEAD` / `BISECT_LOG` / `MERGE_MSG` 等所有 git 中间状态文件检测。

## 配套发现：merge commit 跟 single-commit hook 的冲突

CLAUDE.md「数据库」段规定 `每次提交最多一个迁移文件`。但 **merge commit 必然跨越多个 commit**——如果 source branch 里多个 commit 各带一个迁移（合规），merge 进来一次 staged 就是多个迁移，触发"≤ 1"规则误判。

这是 hook 设计盲点：把 "single commit ≤ 1 migration" 错误推广到 "any staged state ≤ 1 migration"。

**修复**（同步加进 .githooks/pre-commit）：

```bash
GIT_DIR_PATH="$(git rev-parse --git-dir)"
if [ -f "${GIT_DIR_PATH}/MERGE_HEAD" ] || [ -f "${GIT_DIR_PATH}/MERGE_MSG" ]; then
  echo "pre-commit: merge commit，跳过 migration count 检查"
else
  bash "${ROOT_DIR}/scripts/ops/check-migration-count.sh"
fi
```

## 何时会再遇到

- 项目用 agent pool slot（每 slot 是一个 git worktree）开发，commit 时 hook 检测 git 中间状态
- 写新 hook 检测 rebase / cherry-pick / bisect / am 状态
- worktree 上做 merge / rebase / cherry-pick 等多步操作 → hook 误判

## 防御措施

1. **新 hook 永远用 `git rev-parse --git-dir`**，禁止硬编码 `.git/xxx`
2. **设计 commit-time 校验时考虑 merge commit 边界 case**：staged 状态 ≠ single commit 改动
3. 加 CI 检查搜 `.githooks/` `scripts/` 里硬编码 `.git/MERGE_HEAD` 等模式，提醒用 `git rev-parse --git-dir`

## 参考

- 详见本仓库 `.githooks/pre-commit` 顶部新增的 worktree-aware merge 检测段
- `docs/standards/10-agent-pool.md` — agent pool worktree 机制
