AI 智能体自主改代码,快是快,可一旦方向错了,几十秒就能改出一片狼藉。很多人下意识找撤销按钮——遗憾的是,截至社区在 0.157.1 版本的讨论与官方口径,Codex 没有内置的 undo 命令,git 才是那个 undo。这不是缺陷陈述,是使用约定:改动都落在 git 仓库里,回退本来就归版本控制管。这篇给一条固定的恢复顺序:先停手,再盘点,然后回退,最后处理 git 管不到的副作用;自主执行的风险为什么必须配回退手段,见沙箱机制一篇,出乱之后的隔离预防见worktree 隔离一篇。
第一步:停手,别在坏结果上继续叠加
发现改坏了,第一反应决定损失大小。继续在对话里说改回去,agent 会基于当前已坏的状态继续打补丁,错上加错,几轮之后连哪里是原始状态都说不清。正确动作是先中断:交互会话里按 Esc 打断当前执行,让正在跑的步骤停下来;后台或云端任务先停任务再处理。停手之后,工作区就冻结在已坏但不再恶化的状态,这是所有回退动作的前提。事前防线也值得摆在一起看:审批与沙箱决定 agent 动手前有多少道闸,防线怎么配见审批机制一篇。
第二步:盘点改动,git status 与 git diff
回退之前先看清它到底改了什么,凭印象回退容易误伤自己刚写的代码。git status 列出哪些文件被动过、哪些是新文件;git diff 逐行展示改动内容,对照任务描述看哪些在预期内、哪些是意外。盘点时留意两类容易漏的东西:一是 agent 新建的文件,未跟踪状态在 status 里单独一列;二是它顺手改的周边文件——格式化、调整导入路径这类自作主张的小动作,diff 里逐行过才看得见。改动里有需要保留的部分吗?多数情况有——方向错了不代表每一行都错,盘点清单就是后面取舍的依据。
第三步:回退,restore、stash 与 reflog
按需求选工具。全部不要:git restore 放弃工作区改动,回到最近一次提交的状态,干净利落,适合整个推翻重来。部分保留:git stash 把改动整体收起来,再挑有用的部分重新应用,或者手工把需要的片段拷出来。已提交才发现问题:git revert 生成一笔反向提交,历史清楚,适合已经推送的分支;更早期的历史梳理用 git reflog 找回还够得着的提交点。这几条命令可以代办给 agent 执行,但建议自己动手——版本控制是你对仓库状态的最终控制权,交出去就没了。分支组织与回退策略的关系,分支策略一篇有更系统的展开。
第四步:侧效应,命令跑过的不归 git 管
git 只管文件,管不到已经发生的副作用,这部分要手工清点。数据库 migration:agent 跑过的迁移要在数据库里回滚或补一个反向迁移,这类动作不在任何回退机制的覆盖范围内。已推送到远端的内容:push 出去的分支、发出的 PR,撤是另一套流程,越早处理越省事。环境类副作用:装过的依赖、改过的配置、脚本跑出来的缓存与临时文件,逐项核对清掉。这一步最容易犯的错是以为回退了就全结束了——文件回到原样,环境还停留在被改过的状态,下次跑起来行为怪异,根子在这。各版本对回退能力的覆盖范围有差异,截至发稿版本,以官方更新日志为准。想让团队把这套顺序固化,可以让 DeepSeek 把四步整理成一页应急卡片,再让豆包出几道改坏了怎么办的情景题给新人练手。
| 副作用类型 | 具体表现 | 处理方式 |
|---|---|---|
| 数据库 migration | agent 跑过的迁移已改动库结构 | 在数据库里回滚,或补一个反向迁移 |
| 远端内容 | 已 push 的分支、已发出的 PR | 走另一套撤销流程,越早处理越省事 |
| 环境改动 | 装过的依赖、改过的配置 | 逐项核对后清掉 |
| 临时产物 | 脚本跑出来的缓存与临时文件 | 同样逐项核对清理 |
代码回退速查
- 没有 undo 命令,git 就是 undo,先停手再动手
- Esc 中断执行,别在坏状态上继续对话叠加补丁
- 回退前先 status 与 diff 盘点,凭印象回退容易误伤
- 全弃用 restore,暂存用 stash,已提交用 revert,深处用 reflog
- migration、push、装依赖等侧效应 git 管不到,手工清点
关于代码回退的三问三答
- Codex 有没有内置的撤销命令?截至 0.157.1 的官方口径,没有专门 undo 命令,回退走 git;后续版本是否增加,以官方更新日志为准。
- 回退之后对话要重新开吗?建议 /new 另起,把正确的需求重新描述一遍;旧会话上下文里装着错误方向的来龙去脉,继续用容易被带偏。
- 怎么预防改坏?大任务前先 commit 留一个干净回退点,配合审批模式与沙箱档位控制动手范围,并行任务再加 worktree 隔离。


