# Rebase 替代 merge：绕过 pre-commit hook 对 merge commit staged 范围的"误伤"

**日期**: 2026-04-29
**类别**: Git 工作流 / pre-commit hook / 工具链兼容
**严重度**: 中（阻塞 PR 合并，但有干净绕行）

## 现象

合并 PR #155（`fix/deploy-parallel`）时分支落后 develop，需本地解 yml + md 冲突。冲突解完执行 `git commit` 完成 merge，pre-commit hook 报 TS5107 退出（`moduleResolution=node10` deprecated）。

冲突文件**根本不包含** `*.service.ts`，但 hook 仍触发了 `assert-access-check.ts`。

## 根因（两层叠加）

### 1. 工具链层（已开 Gitea Issue #176）

`testing/scripts/tsconfig.json` 用了 `moduleResolution: "node10"`，新版 ts-node 拒绝加载，触发即抛 TS5107。**任何**经此 ts-node 入口的脚本都失败。

### 2. Hook 设计层（本 learning 重点）

`.githooks/pre-commit` 用 `git diff --cached --name-only -- 'backend/src/**/*.service.ts'` 决定是否跑 service 校验。

**对于 merge commit，`git diff --cached` 的范围 ≠ "你这次写的代码"**，而是从分叉点到 HEAD 的两侧 diff 全集，包括 develop 上已经 review 过、合并过的别人的代码。

本案中 develop 已合入的 #157（IAM）改了两个 service.ts。merge develop 进 PR 分支后，这两个文件出现在 staged，hook 把它们当成"本次改动"，触发了 ts-node 校验，撞上工具链 bug。

## 解决（绕行）

**rebase 替代 merge**：

```bash
# 不要：
git merge origin/develop  # staged 含 develop 历史所有 diff

# 改用：
git rebase origin/develop  # 只重放 PR 自己的 commit
# 解冲突 → git rebase --continue
git push --force-with-lease origin <branch>
```

rebase 重放每个 commit 时，staged 只包含**该 commit 自己的 diff**，不含 develop 历史里别人的 service.ts。Hook 看到 staged 不命中 `*.service.ts`，跳过 ts-node 校验，commit 顺利通过。

PR 在 Gitea 端最终走 squash merge，丢弃所有 merge/rebase commit，不影响最终历史形态——所以从结果看 rebase 和 merge 没区别，但**本地 commit 阶段的 hook 行为差很多**。

## 启示

### 1. PR 解冲突优先 rebase 不用 merge

- 历史更线性
- 本地 commit staged 范围只含 PR 自己的 diff，规避 hook 对 merge commit 的"过度热心"
- Gitea/GitHub 最终 squash 也会丢弃 merge commit，rebase 没有副作用
- force-push 在 PR 分支（非保护分支）完全 OK，用 `--force-with-lease` 防覆盖别人的提交

### 2. 写 pre-commit hook 时警惕 merge commit 语义

`git diff --cached` 在 merge commit 上是"两侧 diff 全集"。如果 hook 想检查"作者实际 touched 的文件"，应改用 `git diff --cached HEAD^1` 或检测是否在 merge 状态（`.git/MERGE_HEAD` 存在）后跳过。但更可靠的解法是把校验放到 CI 端跑，不依赖客户端 hook。

### 3. 客户端 hook 工具链 bug 在 AI-first 工作流里会潜伏很久

AI 走 Gitea/GitHub API 合并是服务器端操作，不跑客户端 hook。本仓库高频 AI 合并下，客户端 hook 的工具链 bug（如本次 ts-node TS5107）只有人工本地 commit 时才暴露。建议把 hook 关键校验镜像到 CI workflow，避免单点故障。

## 关联

- Gitea Issue #176：tsconfig `moduleResolution: node10` 修复工单
- PR #155：触发本次发现的 PR
- PR #157：带进 service.ts 的"无辜第三方"
