×−+
安全网:Git 与回退第 4 课 · Codex 教程
第 4 课 · SAFETY NET

安全网:
改坏了也退得回去

Codex 改的是你电脑上的真文件,而它没有"撤销上一步"的按钮。这不可怕:只要养成"动手前存个档"的习惯,再学会审阅面板里的几种退法,改坏了随时能退回去,而且不会顺手把你自己的改动也一起丢掉。

约 30 分钟 10 节 · 4 个动手练习 章末测验 形式参考 luongnv89/claude-howto · 事实依据 OpenAI 官方文档
存档任务前提交
a1c2
Codex 动手改文件、跑测试
你来审审阅面板
存档任务后提交
5d2e
下一个任务从新存档出发
审出问题:只撤坏的那块,或退回存档
像打游戏存档:每个任务前后各存一次(Git 提交)。中间改坏了,最坏也就是回到上一个存档点。
入门先用起来 原理弄懂为什么 实战动手练 深入进阶与避坑

时间紧就看第 1、3 节和第 5 节的沙盘:记住"先提交再动手"和"只撤坏的那一块",就不会吃大亏。

01入门

Codex 没有"撤销上一步"

写文档时按一下撤销,刚才那几个字就回来了。Codex 没有这样的按钮:它改完的文件就在你硬盘上,想退回去,得靠 Git。

打一个比方:Codex 像一位手脚很快的装修师傅,直接在你家里动工。他没有"时光倒流"的本事,但你可以在他进门前拍一张全屋照片(Git 提交)。哪里弄坏了,照着照片恢复就行;照片拍得越勤,损失越小。

官方文档里的斜杠命令列表没有 /undo、/rewind 这类命令。想要一个撤销按钮的人很多,社区里专门有人提了需求(openai/codex#9203),但到本课核对时,官方文档里还没有撤销命令。

你手里有的五样安全网

Git 检查点任务前后各提交一次。最可靠的一张网,别的几样都建立在它上面。
第 2、3 节
审阅面板里的 Revert丢掉没提交的改动,可以整体丢、按文件丢、按一小块丢。
第 4 节
Last turn 视图只看 Codex 最近一轮改了什么,方便找出"是哪一块坏的"。
第 4 节
/fork把对话复制一份,换个思路再试,原来的对话不动。
第 8 节
Worktree给 Codex 一份独立的项目副本去折腾,不碰你手头的文件。
第 8 节 · 第 12 课
记住一句话

这五样里,只有 Git 检查点能保证"一定退得回去"。审阅面板的 Revert 也是按 Git 算的:项目不是 Git 仓库,审阅面板就用不了(App 会提示你先建一个仓库)。

02入门

够用就好:四个 Git 词

Git 是记录文件每一次变化的工具。不用全学会,这一课只要四个词。它们是 Git 自己的命令,和 Codex 无关,在哪个项目里都一样用。

commit 提交
存一个档。把现在所有文件的样子记下来,以后随时能回到这一刻。任务前后各存一次,这就是"检查点"。
git add -A
git commit -m "开工前存档"
branch 分支
另开一条线。在分支上改,主线(通常叫 main)不受影响。试砸了,整条分支不要就是了。
git switch -c fix-pagination
restore 还原文件
把文件改回去。丢掉某个文件里还没暂存的修改(没暂存过的话,就是回到上次提交时的样子)。丢了就找不回来,用之前先确认里面没有你想留的东西。
git restore src/pages/Orders.tsx
stash 先收起来
收进抽屉。把还没想好的改动先收起来,工作区变干净;之后再拿出来接着改。注意:新建的、还没被 Git 跟踪的文件默认不收,要加 -u。
git stash        # 收起来
git stash pop    # 拿回来

还有一个常听到的说法:"工作区干净",意思是 git status 显示没有任何没提交的改动。这时候你的每一处改动都已经存了档。

这些命令可以在 App 的集成终端里自己敲(第 2 课),也可以直接让 Codex 帮你执行。要写 .git 文件夹的命令(提交、stash、切分支),默认档位下它会先停下来请你批准(第 3 课),第 9 节细说。

练一练:这种时候用哪个

03原理

官方的习惯:任务前后各留一个检查点

官方文档在好几处反复说同一件事:在任务开始前和结束后各建一个 Git 检查点,这样随时能退回去。把它拆开,就是下面四步。

1开一条功能分支别直接在 main 上让它改。一个任务一条分支,试砸了整条丢掉。
2工作区弄干净先把你手头的改动提交,或者至少 git stash 收起来,让 git status 显示干净。
3交给 Codex,小步走一次一件事,做完一件审一件。改动越小,出了问题越好退。
4审完再提交跑过验证、看过改动,满意了再提交。这次提交就是下一个任务的起点。

为什么第 2 步最要紧

官方在安全那一页说得很直接:在功能分支上工作,把任务交给 Codex 之前保持 git status 干净,这样 Codex 的改动更容易单独拎出来、退回去。反过来,如果你自己还有一堆没提交的改动,Codex 的改动就会和它们混在一起,退的时候很难只退它的。第 4 节会看到这到底有多麻烦。

同一页还有两条建议:勤提交,这样可以一小步一小步地往回退;把 Codex 的改动当成同事提的 PR 对待:跑有针对性的验证、看 diff、在提交说明里写清楚为什么这样改,方便以后查。

提交也可以交给 Codex

直接说"把这次改动提交一下,提交说明写清楚改了什么"。它会用 git commit,默认档位下会弹出批准卡片,你点"允许一次"就行(原因见第 9 节)。

04原理

审阅面板怎么退,为什么会误伤

审阅面板不只是用来看的,也能退:整体、按文件、按一小块(代码块,英文叫 hunk)三种粒度。但它是按 Git 算的,这一点决定了它会不会误伤你。

1审阅UnstagedLast turnStage allRevert all
2src/pages/Orders.tsx+4−3Revert
3
@@ 导出按钮StageRevert
- <Button onClick={() => exportCsv(rows)}>
+ <Button>
在窗口里的位置:审阅面板
  1. 1整体审阅面板标题栏里的 Revert all / Stage all,一次处理整份改动。
  2. 2按文件单独暂存、取消暂存或 Revert 一个文件。
  3. 3按代码块一个文件里连在一起的一段改动。只撤这一块,同一文件的其他改动不受影响。

界面示意:按钮的样子和位置以你的 App 为准,三种粒度和按钮名称来自官方文档。

按 Git 算,是什么意思

审阅面板显示的是你这个 Git 仓库的状态,不只是 Codex 改的。默认的 Unstaged 视图里是所有还没暂存的改动:Codex 的、你手改的、别的程序改的。它分不清哪行是谁写的。

所以在 Unstaged 里点 Revert all,你自己没暂存的改动会一起没掉;按文件 Revert 一个你和 Codex 都改过的文件,你那部分也会一起没掉。防误伤最简单的办法:先把你自己的改动提交了。提交过的东西不再出现在 Unstaged 里,怎么 Revert 都碰不到它。

Last turn:只看 Codex 最近一轮

把审阅面板切到 Last turn,就只剩 Codex 最近一轮改的内容,你的手改不会混进来。找"是哪一块坏的",从这里下手最快。

但要注意"最近一轮"四个字:Codex 每回你一条消息就算一轮。它改坏了东西之后你又让它做了别的,Last turn 就换成了新一轮的内容,之前那块坏的得切回 Unstaged 去找。发现问题要趁早。

Last turn 里能不能直接点某一块的 Revert,文档没写,以你的 App 为准;不行就记下是哪一块,切回 Unstaged 对同一块点 Revert。

Revert 丢掉的东西找不回来

Revert 就是把改动扔掉,扔之前看清楚这一块里有没有你想留的。拿不准就先提交一次,或者先 git stash 收起来。

05实战

时间线沙盘:五种退法,谁留下、谁没了

"修复分页 bug"这个对话里,Codex 修分页时顺手把"导出 CSV"按钮弄坏了。选一个发现问题的时刻,再选一种退法,看看每一处改动各自的下场。

1 什么时候发现导出坏了(点时间线上的节点)
2 选一种退法
结果

示意:文件和提交号是虚构的;每种退法的效果按 Git 的规则推算。

看出规律了吗

按代码块撤最准;按文件撤只在这个文件里全是要丢的东西时才安全(这里 Orders.tsx 还有 Codex 改对的分页参数,所以怎么按文件撤都会撤多);Revert all 和回到检查点都是"一锅端";/fork 根本不动文件。打开"先提交你自己的两处",再点一遍,误伤就少了一大半。

06实战

练一练:该用哪种退法

5 个场景,每个选一种最合适的做法。选完会看到解析。

07实战

演练:只退坏的那一块,再让它重修

你手头有一处没提交的改动,又让 Codex 去修分页,结果它把导出按钮弄坏了。跟着走一遍:用 Last turn 找到那一块,只撤它,告诉 Codex,最后留一个检查点。中途有两处要你自己点。

画面为教学示意:文件名、提交号和 Codex 说的话都是虚构的;审阅面板的视图名称、三种退法的粒度、.git 受保护要批准,与官方文档一致;在 Last turn 视图里直接按块 Revert 是示意。

08深入

换条路再试:/fork 和 Worktree

有时候不是"改坏了",而是"想换个思路试试,又不想丢掉现在这条"。这时候用的不是 Revert,而是分出一条新路。

/fork:把对话复印一份

在输入框里打 /fork,App 会把当前这个本地对话复制到一个新的本地对话,或者一个新的 worktree 里。原来的对话一字不动,你可以在新对话里走另一条路,两边对比。

要分清:fork 复制的是对话,不是文件的"存档"。分到新的本地对话时,两个对话还是在同一个项目文件夹里干活,已经改坏的文件不会因为 fork 自己变回去。想让文件互不干扰,就分到 worktree。

官方的建议是:同一个问题尽量留在同一个对话里,这样推理的来龙去脉都在;真的分岔了再 fork。另外,App 里也能从更早的一条消息分叉对话(入口以你的 App 为准);命令行里是输入框为空时连按两次 Esc(第 14 课讲)。两种都只分叉对话,不会把文件改回去。

Worktree:给 Codex 一张单独的工作台

打个比方:你在自己的桌子上干活,另外复印一整套项目放在隔壁桌,让 Codex 在那边随便折腾。两张桌子上的文件互不影响,但共用同一本"存档记录"(同一个 .git)。

  • 只能在 Git 仓库里用,底层就是 Git 自带的 worktree 功能。
  • 新建对话时,在输入框下方打开 Worktree 开关,再选从哪个分支开始。
  • 做得满意,可以用对话标题栏里的 Hand off 把对话和改动一起转回 Local(你自己的项目文件夹),或者用 Create branch here 把它变成一条分支;不满意,这张桌子上的东西不要就是了,你本地的文件一点没动。
做法对话文件适合
在原对话里接着说同一段同一个项目文件夹还是同一个问题,想保留来龙去脉
/fork 到本地对话复制一份,原对话不动还是同一个项目文件夹,改动不会退回想换个问法,本地接着干
/fork 到 worktree复制一份,原对话不动在一份独立的 worktree 副本里想换个做法,又不想碰本地文件
新对话选 Worktree全新独立副本,从你选的分支开始大胆试验,或者和你手上的活并行

Worktree 的其他细节,比如被 .gitignore 忽略的 .env 不会自动带过去、怎么清理、保留几个,第 12 课细讲。

09深入

让 Codex 帮你用 Git,以及几个进阶做法

Git 命令不熟,可以直接让 Codex 执行。但有几件事你得心里有数。

它碰 Git 时为什么常要你批准

默认档位下,项目文件夹可写,但里面的 .git、.codex、.agents 三个文件夹是只读的,连里面的所有东西都算。Git 把提交记录、暂存区、stash 都存在 .git 里,所以提交、stash、切分支、回到某个提交这类命令都要写 .git,默认档位下通常会弹出批准卡片(除非你在这次对话里已经选过更大的批准范围)。这是好事:动存档记录的操作,本来就该你点头。

说清楚退哪些、别碰哪些

"帮我撤掉"太含糊,它可能把整个工作区都还原了,连你的手改一起。更好的说法:"只撤掉你这一轮对 Orders.tsx 的改动,README.md 是我改的,不要动"。批准卡片上的命令也要看一眼:带 .(整个目录)、--hard 的,都是一锅端。

反过来,你自己 Revert 了或者手改了它的代码,要告诉它一声。官方提示过:不说的话,它在下一轮可能又把你的修改覆盖掉。

给进阶的人

  • 回到某个提交是最狠的一招。比如回到任务前的检查点:那之后所有没提交的改动都没了,那之后的提交也不在这条分支上了。只在你确定整段都不要时用。(其实 Git 还能从 git reflog 里把丢掉的提交找回来,但别把它当常规手段。)
  • 补丁式工作流。官方安全建议里提到:比起让它直接改已跟踪的文件,更稳妥的是以补丁的形式往来(git diff 导出、git apply 应用),并且勤提交,一小步一小步地回退。
  • 提交前让它自己再审一遍。输入 /review,选 Review uncommitted changes,它会列出按优先级排好的问题,不会改你的文件。
  • 暂存也能挡一下,但别指望它。同一个文件可以同时有已暂存和未暂存的部分,审阅面板会把它同时显示在 Staged 和 Unstaged 里,这是 Git 的正常行为。各个视图里的 Revert 具体撤到哪一步,文档没有写细,要紧的东西还是直接提交最稳。
旧教程对照
  1. "输入 /undo 撤销 Codex 上一步":现在官方的斜杠命令列表里没有这个命令。改用 Git 检查点和审阅面板的 Revert。
  2. "(命令行)连按两次 Esc 就能回到过去":文档里它的作用是编辑上一条消息、从那里分叉对话,没说会把文件改回去。文件还是要靠 Git。
  3. "thread / task":现在都叫对话(chat),/fork 复制的就是一个对话。
审阅面板里出现了 Codex 没改过的文件?
正常。审阅面板按 Git 的状态显示,你自己改的、别的工具改的,只要没提交都会出现。只想看 Codex 最近一轮改的,切到 Last turn。
同一个文件在 Staged 和 Unstaged 里都出现了
也正常:这个文件一部分改动已经暂存,另一部分还没有。Git 本来就能这样表示,官方文档专门说明过。
按 ⌘Z 能撤销 Codex 的改动吗?
别指望它。App 的快捷键表里 ⌘Z(Windows 上是 Ctrl+Z)写的是"撤销上一个 App 操作",文档没有说它能撤销 Codex 对文件的改动。退文件请用审阅面板或 Git。
我的项目还不是 Git 仓库,怎么办?
审阅面板要求项目在 Git 仓库里,App 会提示你创建一个。建议开工前就初始化,并且先提交一次,这就是你的第一个检查点。在 Codex 里直接说"帮我初始化 Git 仓库并做第一次提交"也行。
撤掉之后,Codex 下一轮会不会又改回去?
有可能,它不一定知道你撤了。官方建议:你 Revert 了或者改了它的代码,就告诉它一声,比如"我撤掉了你对导出按钮的改动,这部分别再动"。
Worktree 被自动清理了,里面的改动还在吗?
Codex 自己管理的 worktree 在删除前会存一份快照;你之后打开那个对话,可以选择恢复。清理规则第 12 课讲。
10检验

小测验

8 道题,每题选完会立刻看到解析。