> ## Documentation Index
> Fetch the complete documentation index at: https://aicoding.cscitech.top/llms.txt
> Use this file to discover all available pages before exploring further.

# 05-diff测试与回滚

> 用逐文件审查、测试矩阵和可控回滚，把 Codex 的代码修改变成可验证、可恢复的工作闭环。

## 用途

这一页解决一个很具体的问题：Codex 已经改完代码，接下来怎样确认改动正确，怎样测试，怎样在失败时止损。

核心顺序只有一句话：

> **先保护现场，再看 diff；先测最小路径，再扩大测试；确认无误后才 commit；没有明确授权就不 push。**

本页不把“模型说完成了”当成完成标准。

完成标准必须有证据：

* 你知道当前所在目录和分支。
* 你知道哪些文件被改了，以及每个文件为什么被改。
* 你有一组与改动相匹配的测试结果。
* 失败时能判断是代码、环境、测试还是数据问题。
* 你能只撤销 Codex 的改动，不误伤自己的未提交工作。
* 你能解释为什么允许 commit，以及为什么暂时不 push。

命令、参数和 Codex 界面会随版本变化。

遇到差异时，以本机 `codex --help`、会话中的 `/help`、项目测试脚本和官方文档为准。

参考资料包括 `参考/codex/06-first-task.md`、`参考/codex/15-permissions.md`、`参考/codex/26-git-github.md` 和 `参考/codex/35-cheatsheet.md`。

***

## 01 先保护当前工作

### 先确认路径

不要在不知道当前目录的情况下执行恢复命令。

```bash theme={null}
pwd
git rev-parse --show-toplevel
git branch --show-current
git status --short --branch
```

Windows PowerShell 可以使用：

```powershell theme={null}
Get-Location
git rev-parse --show-toplevel
git branch --show-current
git status --short --branch
```

预期结果类似：

```text theme={null}
E:/work/shop
main
## main...origin/main
```

如果 `git rev-parse --show-toplevel` 报错，当前目录不是 Git 仓库。

先不要让 Codex 批量修改，先回到正确项目目录，或明确建立 Git 仓库。

### 记录基线

在任务开始前保存一份基线信息。

```bash theme={null}
git status --short
git diff --stat
git log -1 --oneline
```

工作区干净时，`git status --short` 没有输出。

有输出时，先把每一行的含义弄清楚，再决定是否继续。

例如：

```text theme={null}
 M src/cart.ts
?? notes/try.txt
```

这表示 `src/cart.ts` 有未暂存修改，`notes/try.txt` 是未跟踪文件。

它们可能是你自己的工作，不一定是 Codex 产生的。

### 未提交变更保护原则

如果开始任务前已经有未提交变更，默认不要直接让 Codex在同一工作区大范围修改。

更稳妥的选择有三种：

1. 先保存当前变更，再开始新任务。
2. 从当前状态建立临时分支，把任务隔离开。
3. 使用新的 `git worktree` 或临时副本。

不要为了得到“干净状态”而直接运行：

```bash theme={null}
git reset --hard
```

也不要随意运行：

```bash theme={null}
git clean -fd
```

前者会丢弃已跟踪文件的未提交改动，后者会删除未跟踪文件。

两者都不是普通的“清理一下”。

### 先保存补丁

如果已有修改，但暂时不能 commit，可以先导出补丁。

```bash theme={null}
git diff > ../before-codex.patch
git diff --staged > ../before-codex-staged.patch
```

预期：上级目录出现补丁文件。

补丁不是完整备份，未跟踪文件不会自动进入 `git diff`。

需要保护未跟踪文件时，先单独复制或使用压缩备份。

```bash theme={null}
tar -czf ../before-codex-files.tgz notes/try.txt
```

Windows 可以直接复制到项目外目录：

```powershell theme={null}
Copy-Item notes/try.txt ..\before-codex-try.txt
```

### 建立检查点

如果当前修改已经确认是应该保留的工作，可以提交一个明确的检查点。

```bash theme={null}
git add -A
git diff --cached --check
git commit -m "chore: 保存 Codex 任务前检查点"
```

预期结果类似：

```text theme={null}
[feature/cart 1a2b3c4] chore: 保存 Codex 任务前检查点
 3 files changed, 42 insertions(+), 8 deletions(-)
```

检查点的目的不是发布功能，而是让你拥有一个已知可恢复位置。

提交信息要说明用途，不要使用含糊的 `update` 或 `test`。

如果当前未提交工作混杂了别人的内容，先不要替别人 commit。

应先询问负责人，或建立副本、worktree，再继续。

***

## 02 让 Codex 在可控范围内工作

启动 Codex 前，明确任务的文件范围、测试命令和禁止事项。

可以直接使用下面的提示词：

```text theme={null}
请先读取相关文件和已有测试，不要修改无关文件。
只处理 src/cart.ts 和 tests/cart.test.ts。
先说明计划，得到确认后再修改。
完成后展示 git diff，并运行最小必要测试。
不要 commit、不要 push、不要删除文件、不要访问生产服务。
如果测试失败，请分类说明原因并停止扩大修改范围。
```

对陌生项目，先使用只读或较严格的权限模式。

```bash theme={null}
codex --sandbox read-only --ask-for-approval on-request
```

确认理解范围后，再按项目实际需要使用工作区可写模式：

```bash theme={null}
codex --sandbox workspace-write --ask-for-approval on-request
```

进入会话后可以查看状态：

```text theme={null}
/status
```

参考输出可能包含：

```text theme={null}
Sandbox: workspace-write
Approval: on-request
Workspace directories:
  E:/work/shop
```

本地开发通常保持 `workspace-write` 加 `on-request`。

不要在宿主机日常项目中使用 `--yolo` 或完全访问模式。

联网、安装依赖、访问工作区外目录、发送外部请求，必须单独确认。

***

## 03 先看总览 diff

Codex 完成一次修改后，第一件事不是 commit，而是查看工作区状态。

```bash theme={null}
git status --short
git diff --stat
git diff --name-status
```

三条命令分别回答：

* 哪些文件处于修改、新增、删除或重命名状态。
* 每个文件改了多少行。
* 文件的状态变化是什么。

预期示例：

```text theme={null}
 M src/cart.ts
 M tests/cart.test.ts
?? tests/fixtures/cart-empty.json
```

```text theme={null}
 src/cart.ts                 | 18 ++++++++++++++----
 tests/cart.test.ts          | 24 ++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 5 deletions(-)
```

注意：`git diff --stat` 默认不统计未跟踪文件的内容。

所以看到 `??` 时，必须打开该文件逐行检查，不能只看 stat。

### 使用 `/diff`

在 Codex 交互会话中，可以输入：

```text theme={null}
/diff
```

这通常用于快速查看当前 Git 差异。

不同版本是否显示未跟踪文件、显示方式和菜单名称可能不同。

终端中的 `git diff` 仍然是可靠的本地依据。

### 查看完整未暂存 diff

```bash theme={null}
git diff --no-ext-diff --find-renames --find-copies
```

这里关闭外部 diff 工具，避免输出被第三方程序改变。

需要查看暂存区差异时使用：

```bash theme={null}
git diff --cached
```

需要比较某个检查点和当前工作区：

```bash theme={null}
git diff HEAD
```

需要只看某个文件：

```bash theme={null}
git diff -- src/cart.ts
```

需要查看某一段上下文更多的差异：

```bash theme={null}
git diff -U80 -- src/cart.ts
```

### 预期 diff 示例

```diff theme={null}
diff --git a/src/cart.ts b/src/cart.ts
index 19a4c11..83b7e21 100644
--- a/src/cart.ts
+++ b/src/cart.ts
@@ -8,7 +8,15 @@ export function addItem(cart, item) {
-  cart.items.push(item);
+  if (!item.id || item.quantity <= 0) {
+    throw new Error("invalid item");
+  }
+
+  const existing = cart.items.find((entry) => entry.id === item.id);
+  if (existing) {
+    existing.quantity += item.quantity;
+    return cart;
+  }
+
+  cart.items.push({ ...item });
   return cart;
 }
```

阅读时记住：

* `-` 是旧内容。
* `+` 是新内容。
* 没有前缀的行只是上下文。
* `@@ -8,7 +8,15 @@` 表示修改附近的行号范围。
* 文件头部的 `a/` 和 `b/` 是 Git 的旧路径和新路径。

***

## 04 按文件审查，而不是只看总结

总览 diff 只能发现范围异常。

真正的审查要逐文件完成。

建议顺序如下：

1. 配置和依赖文件。
2. 业务逻辑文件。
3. 数据库、迁移和接口文件。
4. 测试文件。
5. 文档、生成文件和临时文件。

### 第一问：文件是否在允许范围

把实际文件列表和任务中的范围逐一对照。

```bash theme={null}
git diff --name-only
```

预期只出现计划内文件。

如果任务只要求改 `src/cart.ts`，却出现：

```text theme={null}
package-lock.json
.env.example
.github/workflows/release.yml
```

应先暂停。

逐项确认这些文件是否确实由依赖、配置或测试要求产生。

不清楚原因时，不要为了“让 diff 变干净”直接删除文件。

先让 Codex 解释，或手动检查生成原因。

### 第二问：每处修改是否服务于需求

逐段阅读新代码，问自己：

* 这几行解决了哪个验收条件？
* 是否加入了未要求的重构？
* 是否改变了公共接口、错误类型或返回格式？
* 是否改变了日志、权限、缓存或事务行为？
* 是否把用户输入直接送进命令、SQL 或 HTML？

任何无法解释的新增依赖、网络请求、环境变量或权限变更，都应列为阻塞项。

### 第三问：删除是否有理由

删除行比新增行更值得警惕。

重点查看：

* 异常处理是否被删掉。
* 鉴权和权限检查是否被绕过。
* 超时、重试、事务回滚是否被删掉。
* 测试夹具、锁文件和配置是否被删掉。
* 注释删除后是否失去关键约束。

### 第四问：输入和边界是否仍然成立

至少检查以下输入：

* 空值、空数组和缺失字段。
* 类型错误和超大数值。
* 重复请求和并发请求。
* 未登录用户和无权限用户。
* 超时、断网、服务端 4xx 和 5xx。
* 旧数据、脏数据和数据库迁移前的数据。

### 第五问：测试是否真的覆盖改动

新增一个测试文件不代表覆盖了新逻辑。

打开测试代码，确认它断言了行为，而不是只断言函数“能运行”。

例如下面的断言有实际意义：

```ts theme={null}
expect(addItem(cart, { id: "a", quantity: 2 }).items).toEqual([
  { id: "a", quantity: 2 },
]);
```

而下面的测试可能过于空泛：

```ts theme={null}
expect(() => addItem(cart, item)).not.toThrow();
```

如果 `item` 是无效输入，这个测试反而可能掩盖问题。

***

## 05 逐文件审查命令

### 只审一个业务文件

```bash theme={null}
git diff -- src/cart.ts
```

预期：只输出 `src/cart.ts` 的未暂存修改。

### 只审一个测试文件

```bash theme={null}
git diff -- tests/cart.test.ts
```

### 查看新增文件

未跟踪文件不会出现在普通 `git diff` 内容中。

先查看文件状态：

```bash theme={null}
git status --short --untracked-files=all
```

再用项目已有工具或直接打开文件检查。

如果要让 Git 显示新增文件的完整差异，可以先只暂存这个文件：

```bash theme={null}
git add --intent-to-add -- tests/fixtures/cart-empty.json
git diff -- tests/fixtures/cart-empty.json
```

`--intent-to-add` 会让 Git 知道路径，但不把完整内容放进暂存区。

不确定时先看状态，避免把整个目录暂存。

### 显示空白问题

```bash theme={null}
git diff --check
```

预期：没有输出且退出码为 `0`。

如果看到类似：

```text theme={null}
src/cart.ts:14: trailing whitespace.
```

先修复空白，再继续审查。

### 检查已暂存内容

当你准备分批提交时，使用：

```bash theme={null}
git add -p
```

每个代码块逐一选择 `y`、`n` 或 `s`。

然后查看：

```bash theme={null}
git diff --cached --stat
git diff --cached --check
git diff --cached
```

预期暂存区只含准备提交的部分。

***

## 06 测试矩阵：让测试和风险对应

不要只写“已测试”。

把修改映射到测试层级，并记录实际命令和结果。

| 测试层级  | 目标                | 典型命令                                           | 何时必须跑         |
| ----- | ----------------- | ---------------------------------------------- | ------------- |
| 格式与空白 | 发现格式、尾随空格、语法风格问题  | `git diff --check`、`npm run format:check`      | 每次修改后         |
| 静态检查  | 发现类型、lint、导入和规则问题 | `npm run lint`、`npm run typecheck`             | 改逻辑、类型、导入时    |
| 单元测试  | 验证函数和边界行为         | `npm test -- cart`、`pytest tests/test_cart.py` | 改纯函数或模块时      |
| 集成测试  | 验证模块之间的契约         | `npm run test:integration`                     | 改 API、数据库、消息时 |
| 构建检查  | 验证产物能生成           | `npm run build`                                | 改构建、依赖、前端时    |
| 手工冒烟  | 验证关键用户路径          | 启动项目后按验收步骤操作                                   | 改界面或流程时       |
| 安全回归  | 验证权限、输入、敏感数据边界    | 项目安全测试命令                                       | 改鉴权、支付、日志时    |

命令必须以项目实际脚本为准。

先查看 `package.json`、`pyproject.toml`、`Makefile` 或项目 README，不要凭记忆编造命令。

### 一个最小测试矩阵示例

假设本次修改是“购物车合并重复商品”。

| 场景    | 输入                 | 预期结果       | 测试方式 |
| ----- | ------------------ | ---------- | ---- |
| 新商品   | `id=a, quantity=2` | 新增一项，数量为 2 | 单元测试 |
| 重复商品  | 已有 `a=1`，再加 `a=2`  | 仍一项，数量为 3  | 单元测试 |
| 数量为零  | `quantity=0`       | 拒绝并报错      | 单元测试 |
| 负数    | `quantity=-1`      | 拒绝并报错      | 单元测试 |
| 缺少 id | `id=""`            | 拒绝并报错      | 单元测试 |
| 并发请求  | 同一商品同时添加           | 不产生错误重复项   | 集成测试 |
| 页面流程  | 用户点击加购             | 页面数量和后端一致  | 手工冒烟 |

### 测试顺序

先运行便宜且能快速定位的检查：

```bash theme={null}
git diff --check
npm run lint
npm test -- cart
```

再运行耗时检查：

```bash theme={null}
npm run typecheck
npm run test:integration
npm run build
```

预期结果可能是：

```text theme={null}
PASS tests/cart.test.ts
Tests: 5 passed, 5 total
```

以及：

```text theme={null}
Build completed successfully
```

不要把“命令返回成功”误认为所有风险都已覆盖。

检查命令是否真的执行了目标测试，是否因为配置、筛选器或缓存而跳过。

***

## 07 失败分类：先判断，再修复

测试失败时不要立刻让 Codex“大改一遍”。

先保存完整输出：

```bash theme={null}
npm test -- cart 2>&1 | tee ../cart-test.log
```

PowerShell 可以使用：

```powershell theme={null}
npm test -- cart 2>&1 | Tee-Object ..\cart-test.log
```

然后按类别分类。

### A 类：代码逻辑失败

特征：断言结果与预期不符，堆栈指向本次改动。

例子：

```text theme={null}
Expected: 3
Received: 2
```

处理方式：

* 找到第一个失败断言。
* 对照 diff 检查状态更新和边界条件。
* 补充一个能复现失败的测试。
* 只修复相关逻辑，再重跑同一测试。

### B 类：类型或静态规则失败

特征：编译器、lint 或类型检查报错，通常在测试运行前出现。

例子：

```text theme={null}
TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
```

处理方式：

* 检查接口变更是否超出需求。
* 不要用 `any`、禁用规则或忽略错误来掩盖问题。
* 确认所有调用方和测试已同步更新。

### C 类：环境或依赖失败

特征：找不到命令、端口被占用、依赖下载失败、运行时版本不匹配。

例子：

```text theme={null}
command not found: pytest
EADDRINUSE: address already in use
```

处理方式：

* 记录 Node、Python、数据库和工具版本。
* 先确认依赖是否按项目说明安装。
* 不要未经确认升级锁文件或全局工具。
* 环境问题解决后，重新运行原命令。

### D 类：测试数据或服务失败

特征：连接数据库、外部 API、认证服务或测试容器失败。

例子：

```text theme={null}
Connection refused 127.0.0.1:5432
401 Unauthorized
```

处理方式：

* 确认使用的是测试服务，不是生产服务。
* 检查测试账号和最小权限凭据。
* 不要把真实令牌写入代码、日志或提交。
* 将“未执行”与“失败”分开记录。

### E 类：基线或测试本身失败

特征：修改前同一测试就失败，或测试断言与当前需求矛盾。

处理方式：

* 在检查点上复跑同一命令。
* 用 `git show HEAD:path/to/file` 检查基线内容。
* 记录“基线已失败”，不要把旧问题算到本次改动上。
* 修改测试前先确认需求和团队约定。

### 失败后的提示词

```text theme={null}
测试命令失败，请先不要修改代码。
请把失败归类为逻辑、静态检查、环境依赖、测试数据服务或基线问题。
指出第一个失败位置，说明它与本次 diff 的关系。
只提出一个最小修复方案，仍然不要 commit 或 push。
```

***

## 08 测试失败时的事故止损

当失败范围不明时，先停止 Codex 的后续修改。

可以按 `Esc` 中断当前动作，或关闭会话中的自动继续流程。

然后执行：

```bash theme={null}
git status --short
git diff --stat
git diff > ../failure-state.patch
```

保存三类信息：

* 最后一次成功的测试命令。
* 第一个失败的命令和完整输出。
* 失败发生前后的 diff。

如果程序正在运行并可能影响外部服务，立即停止本地进程。

不要继续点击重试，尤其是支付、写库、发消息和部署操作。

如果可能已经触及共享环境：

1. 记录时间、命令、分支和请求编号。
2. 立即通知负责人或值班人员。
3. 暂停进一步发布和推送。
4. 检查是否产生重复写入或外发数据。
5. 使用服务自身的撤销、备份或补偿流程。

Git 只能恢复文件和提交历史，不能撤回已经发送的邮件、已经执行的数据库写入或已经发布的版本。

***

## 09 未提交改动的回滚

回滚前先保存证据，再决定范围。

### 回滚单个文件

确认该文件的所有未提交修改都属于本次任务后，才使用：

```bash theme={null}
git restore --source=HEAD -- src/cart.ts
```

预期：该文件恢复到 `HEAD` 版本，其他文件不变。

再次检查：

```bash theme={null}
git status --short
git diff -- src/cart.ts
```

### 回滚多个指定文件

```bash theme={null}
git restore --source=HEAD -- src/cart.ts tests/cart.test.ts
```

路径必须明确，不要在不清楚范围时使用 `.`。

### 回滚全部未暂存改动

```bash theme={null}
git restore --source=HEAD -- .
```

这会丢弃所有已跟踪文件的未暂存修改。

执行前必须确认：

* 当前目录正确。
* 没有同事的未提交工作。
* 已导出补丁或已有检查点。
* 未跟踪文件不需要保留。

它不会自动删除未跟踪文件。

### 取消暂存但保留文件修改

如果只是误把文件放进暂存区：

```bash theme={null}
git restore --staged -- src/cart.ts
```

预期：文件从暂存区移除，但工作区内容仍保留。

同时取消暂存并恢复内容：

```bash theme={null}
git restore --staged --worktree -- src/cart.ts
```

这条命令会同时丢弃该文件的暂存和工作区修改，使用前必须再次核对路径。

### 未跟踪文件的处理

`git restore` 不会恢复或删除未跟踪文件。

先查看：

```bash theme={null}
git status --short --untracked-files=all
```

确认文件确实是本次生成且不需要后，才可以单独删除。

```bash theme={null}
rm -- tests/fixtures/generated.json
```

Windows PowerShell：

```powershell theme={null}
Remove-Item tests\fixtures\generated.json
```

不要使用 `git clean -fd` 作为第一反应。

***

## 10 已提交改动的回滚

已经 commit 的改动不应靠删除提交来“假装没发生”。

共享分支上，优先创建新的反向提交。

### 查看要撤销的提交

```bash theme={null}
git log --oneline --decorate -5
git show --stat --oneline <commit>
```

预期：先确认提交 SHA、作者、文件和改动内容。

### 使用 `git revert`

```bash theme={null}
git revert <commit>
```

预期：Git 创建一个新的提交，内容抵消指定提交。

如果打开编辑器，保留默认的 revert 信息，或写清原因。

然后检查：

```bash theme={null}
git log --oneline -3
git show --stat HEAD
git status --short
```

### 处理 revert 冲突

如果提示冲突，不要继续提交半成品。

```bash theme={null}
git status
git diff
```

解决冲突后：

```bash theme={null}
git add <resolved-file>
git revert --continue
```

如果确认不应继续：

```bash theme={null}
git revert --abort
```

预期：回到 revert 开始前的状态。

`git revert` 适合已经进入共享历史的提交。

不要对共享分支使用 `git reset --hard` 配合强制推送来改写历史。

***

## 11 checkpoint 与临时分支

### 什么时候建立 checkpoint

以下情况建议在任务前建立检查点：

* 将修改多个业务文件。
* 会改依赖、配置或数据库迁移。
* 任务可能需要多轮试错。
* 需要让 Codex 运行自动修复。
* 你无法快速判断改动是否正确。

检查点可以是一个本地 commit，不代表要 push。

```bash theme={null}
git add -A
git diff --cached --check
git commit -m "chore: checkpoint before cart change"
```

预期：当前分支多一个明确的本地提交，工作区回到干净状态。

### 使用临时分支

```bash theme={null}
git switch -c codex/cart-validation
```

旧版本 Git 可使用：

```bash theme={null}
git checkout -b codex/cart-validation
```

建议分支名包含任务主题，不要使用 `test` 这种无法追踪的名称。

确认分支：

```bash theme={null}
git branch --show-current
git status --short --branch
```

预期：当前分支为 `codex/cart-validation`。

在临时分支完成修改、测试和审查。

满意后再由人决定是否合并或开 PR。

### 使用 worktree 隔离

如果主工作区有未提交工作，可以创建新的 worktree：

```bash theme={null}
git worktree add ../shop-codex -b codex/cart-validation
cd ../shop-codex
git status --short --branch
```

预期：新目录位于独立分支，原目录的未提交文件不被改变。

任务结束后，先确认分支已合并或不再需要，再移除 worktree：

```bash theme={null}
git worktree remove ../shop-codex
git worktree prune
```

不要在仍有未保存工作时移除 worktree。

***

## 12 何时允许 commit

commit 是保存一组经过审查的历史，不是“让 Codex 停止输出”的按钮。

满足以下条件后才允许 commit：

* 路径和分支确认无误。
* `git status` 中没有意外文件。
* 已查看总览 stat 和完整 diff。
* 已按文件解释每个新增、修改和删除。
* `git diff --check` 通过。
* 与改动对应的测试已运行并记录结果。
* 失败项已修复，或得到明确的豁免说明。
* 没有密钥、令牌、个人数据和临时产物。
* 没有把生成物、缓存和日志误加入。
* commit 不包含与任务无关的工作。

提交前再次检查：

```bash theme={null}
git status --short
git diff --check
git diff --stat
git diff
```

然后精确暂存：

```bash theme={null}
git add -- src/cart.ts tests/cart.test.ts
git diff --cached --check
git diff --cached --stat
git diff --cached
```

最后再提交：

```bash theme={null}
git commit -m "fix: merge duplicate cart items"
```

预期：commit 只包含已审查的两个文件。

如果 `git diff --cached` 里出现无关文件，先取消暂存：

```bash theme={null}
git restore --staged -- path/to/unrelated-file
```

不要用 `git add .` 代替逐项审查，尤其是仓库中存在日志、构建产物或本地配置时。

***

## 13 如何避免误推送

commit 和 push 是两个不同决定。

本地 commit 只是写入当前仓库历史。

push 会把提交发送到远端，可能触发 CI、部署和通知。

### 推送前确认三件事

```bash theme={null}
git branch --show-current
git remote -v
git log --oneline --decorate -3
```

预期：你能说出当前分支、远端仓库和将要发送的提交。

查看远端差异：

```bash theme={null}
git fetch origin
git log --oneline origin/main..HEAD
git diff --stat origin/main...HEAD
```

如果当前分支不是明确的任务分支，暂停推送。

如果本来只想开 PR 分支，却发现当前是 `main`，不要直接 push。

### 使用 dry-run

```bash theme={null}
git push --dry-run origin codex/cart-validation
```

预期：Git 显示将更新哪个远端分支，但不会真正发送对象。

`--dry-run` 不能代替实际审查，它只验证推送计划。

### 防止推错分支

推送时明确写出源分支和目标分支：

```bash theme={null}
git push origin HEAD:refs/heads/codex/cart-validation
```

只有明确授权后，才考虑推送到指定远端。

不要把 `git push` 交给未经审查的自动流程。

尤其不要使用：

```bash theme={null}
git push --force
```

`--force-with-lease` 比强推更能避免覆盖新提交，但仍会改写远端历史，不能作为日常默认。

主干、保护分支和团队仓库应遵守项目的 PR 流程。

合并、发布和生产部署都应由负责人明确放行。

### 推送后确认

推送完成后检查：

```bash theme={null}
git status --short --branch
git log -1 --oneline --decorate
```

再到远端页面确认分支和提交号一致。

推送超时不要马上重复执行。

先查询远端：

```bash theme={null}
git ls-remote --heads origin codex/cart-validation
git log -1 --oneline --decorate
```

这样可以避免第一次其实成功、第二次又重复操作。

***

## 14 一次完整演练

下面是一条适合第一次练习的闭环。

### 第一步：确认并保存检查点

```bash theme={null}
cd path/to/project
git status --short --branch
git switch -c codex/demo-change
git add -A
git diff --cached --check
git commit -m "chore: checkpoint before demo change"
```

预期：位于新分支，工作区干净。

### 第二步：提出范围明确的任务

```text theme={null}
只修改 src/cart.ts 和 tests/cart.test.ts。
给重复商品合并逻辑补上输入校验。
先读取代码和测试，再修改。
禁止改 package.json、配置文件和其他目录。
完成后展示 diff，运行 lint 和购物车单元测试。
不要 commit、不要 push。
```

### 第三步：查看文件范围

```bash theme={null}
git status --short
git diff --name-status
git diff --stat
```

预期只有计划中的业务文件和测试文件。

### 第四步：按文件检查

```bash theme={null}
git diff -- src/cart.ts
git diff -- tests/cart.test.ts
git diff --check
```

确认测试覆盖正常输入、重复输入和非法输入。

### 第五步：运行矩阵中的检查

```bash theme={null}
npm run lint
npm test -- cart
```

如果通过，继续运行项目要求的类型检查或构建。

如果失败，先保存日志并按失败分类，不要直接提交。

### 第六步：决定保留或回滚

逻辑正确、测试通过：保留工作区，准备暂存。

逻辑错误且整轮都不要：

```bash theme={null}
git restore --source=HEAD -- src/cart.ts tests/cart.test.ts
```

只有某个文件错误：只恢复那个文件。

### 第七步：精确 commit

```bash theme={null}
git add -- src/cart.ts tests/cart.test.ts
git diff --cached --check
git diff --cached --stat
git commit -m "fix: validate duplicate cart items"
```

### 第八步：停止在本地

如果用户没有明确要求推送，流程在本地 commit 结束。

输出提交号、测试命令和未验证项，等待下一步授权。

***

## 15 验收清单

提交或交给同事审查前，逐项打勾：

### 工作区与保护

* [ ] 我确认了项目根目录。
* [ ] 我确认了当前分支。
* [ ] 我知道任务开始前是否已有未提交变更。
* [ ] 重要任务已有 checkpoint、补丁或独立 worktree。
* [ ] 我没有使用未经确认的 `reset --hard` 或 `clean -fd`。

### Diff 审查

* [ ] 我看过 `git diff --stat`。
* [ ] 我看过 `git diff --name-status`。
* [ ] 我按文件查看了完整 diff。
* [ ] 我检查了新增文件，而不只依赖 `git diff`。
* [ ] 每一处修改都能对应需求或测试。
* [ ] 删除、依赖、配置和权限变化都有明确理由。
* [ ] `git diff --check` 通过。

### 测试

* [ ] 我运行了格式或空白检查。
* [ ] 我运行了相关 lint 或类型检查。
* [ ] 我运行了直接相关的单元测试。
* [ ] 需要时运行了集成测试、构建和手工冒烟。
* [ ] 我记录了命令、结果和测试环境。
* [ ] 我区分了失败、跳过、未执行和环境阻塞。

### 回滚与提交

* [ ] 我知道未提交改动如何用 `git restore` 恢复。
* [ ] 我知道已提交改动如何用 `git revert` 撤销。
* [ ] 我没有把别人的未提交修改一起提交。
* [ ] 暂存区只包含本次任务文件。
* [ ] commit 信息能说明实际变更。
* [ ] 没有密钥、令牌、`.env`、个人数据、日志和缓存。

### 推送边界

* [ ] 用户明确要求了 push，或项目流程明确授权了 push。
* [ ] 我确认了远端、目标分支和待推送提交。
* [ ] 我执行过 `git push --dry-run` 或等价检查。
* [ ] 我没有使用 `--force`。
* [ ] 我没有让 Codex 自动合并主干或发布生产。
* [ ] 推送后核对了远端分支和提交号。

***

## 小结

审 diff 不是看一眼绿色和红色，而是逐文件回答“为什么改、改对了吗、是否漏了边界”。

测试不是越多越好，而是要覆盖这次修改真正影响的路径。

失败不是一个笼统的“没通过”，应先区分逻辑、静态检查、环境、服务数据和基线问题。

未提交改动优先用精确路径的 `git restore`，已提交改动优先用新的 `git revert`。

复杂任务在改前建立 checkpoint 或临时分支，主工作区有个人修改时使用 worktree 隔离。

只有 diff、测试、敏感信息和范围都验收通过，才允许 commit。

没有明确推送授权时，commit 留在本地；推送前再次确认远端、分支和提交，绝不把 merge、发布或强推交给自动流程。

参考资料：`参考/codex/06-first-task.md`、`参考/codex/15-permissions.md`、`参考/codex/26-git-github.md`、`参考/codex/35-cheatsheet.md`。

动态信息以本地 `codex --help`、会话 `/help`、项目文档和官方文档为准。
