1. Codex 自动回滚代码的排查思路:先分清 git restore、IDE 本地历史还是工具链触发
你让 Codex 改一个功能,回头一看工作区被清空了,git status干净得像刚 clone 下来,这种体验确实让人血压升高。我先把结论放前面:Codex 本身不会主动执行git restore .,真正触发回滚的通常是三类来源——命令行工具链里的 git 操作、IDE 的本地历史机制、以及 Codex 在自动运行模式下调用 shell 时产生的副作用。这篇就按「先定位来源,再复现验证」的顺序,把 Codex 自动回滚代码怎么排查讲清楚,涉及 git restore、Android Studio Local History、Codex 的 endpoint 与 auth.json 配置,最后用 TaoToken 接入来复现整个链路。
先说清楚 Codex 是什么、能做什么、适合谁。Codex 是 OpenAI 推出的编码代理工具,可以在本地仓库里读写文件、执行命令、跑测试,适合单人项目或小团队做功能迭代。它的工作方式是「读上下文 → 生成 patch → 应用改动」,如果开了自动运行(auto-run / full-auto),它会直接执行 shell 命令而不逐条问你。问题就出在这里:当它判断「当前工作区太乱,需要回到干净状态」时,可能调用git restore .或git checkout .,而这两个命令会把你未提交的改动全部丢掉。
我踩过的坑是这样的:同时开了好几个 Codex 窗口,一个窗口在改 A 功能,另一个窗口在改 B 功能,两个窗口共享同一个工作区。窗口 B 觉得工作区有「不属于自己任务」的改动,就执行了一次git restore .,把窗口 A 的成果一起抹掉了。这不是 Codex 的 bug,而是多窗口并发 + 自动运行 + 共享工作区的组合问题。
排查的核心逻辑是时间线对齐:先确定回滚发生的时间点,再去看这个时间点前后有哪些进程动过 git。具体分三步走。第一步,看 git 的 reflog,git reflog --date=iso会列出 HEAD 的每一次移动,如果回滚是通过git reset或git checkout触发的,reflog 里会有记录。第二步,看 IDE 的 Local History,Android Studio 和 IntelliJ 系都会在.idea之外维护一份本地历史,路径在系统缓存目录里,即使 git 被清空,Local History 也可能保留改动。第三步,看 Codex 的会话日志,它执行过的 shell 命令通常会记录在会话文件或终端输出里,搜restore、checkout、reset就能找到元凶。
这里有个容易忽略的点:git restore .和git checkout .只影响已跟踪文件的未提交改动,未跟踪的新文件不会被删。所以如果你发现新写的文件还在、老文件的改动没了,基本可以锁定是 restore/checkout 类操作。反过来,如果连新文件都没了,那可能是git clean -fd或者更暴力的操作,排查方向要换。
还有一个隐蔽来源是工具链的格式化或 lint 自动修复。有些项目配了 pre-commit hook 或保存时自动格式化,如果 Codex 触发了这些 hook,而 hook 里又调用了git stash或git checkout,也会造成「代码被回滚」的假象。排查时用git config --list | grep hook和查看.git/hooks/目录,确认有没有自定义脚本。
定位清楚来源之后,才能谈修复。如果是 Codex 自动运行触发的,最直接的办法是关掉 auto-run,改成逐条确认;如果是多窗口并发,就给每个窗口分配独立的工作区或分支;如果是 hook 触发的,就改 hook 逻辑。下面几节我会给出可复制的 git 配置、Android Studio Local History 的检查步骤,以及把 Codex 接到 TaoToken 后如何复现验证。
2. TaoToken 前置准备:把 Codex 的 endpoint 与 auth.json 改到 TaoToken
在复现回滚问题之前,得先让 Codex 能稳定跑起来。很多同学卡在第一步:Codex 默认走 OpenAI 官方 endpoint,网络和额度都不太可控。这里我用 TaoToken 作为接入层,把 Codex 的请求指向https://taotoken.net/api,这样既能复现问题,也方便观察 Codex 到底发了哪些命令。
TaoToken 是一个大模型 API 聚合服务,支持 OpenAI 兼容协议,Codex、Claude Code、Cline 这类工具都能接。它的作用是统一 endpoint 和鉴权,你不用在每个工具里分别配 key。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api ,注意 API 地址不带 UTM 参数。
Codex 的配置分两块:一块是auth.json,存 API Key;一块是config.toml,存 endpoint 和模型。默认路径在用户目录下的.codex/里。Linux/macOS 是~/.codex/,Windows 是C:\Users\你的用户名\.codex\。先确认这个目录存在,不存在就手动建。
auth.json的格式很简单,就是一个 JSON 对象,字段名是OPENAI_API_KEY。注意这里虽然叫 OPENAI,但填的是 TaoToken 的 key,因为 Codex 走的是 OpenAI 兼容协议。key 在 TaoToken 控制台的 API Keys 页面生成,地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。生成后复制,粘贴到auth.json里。
config.toml里要改的是model_provider和base_url。Codex 支持自定义 provider,把 base_url 指向 TaoToken 的 API 地址,模型 ID 填你想要的,比如gpt-5-codex或claude-sonnet-4-5。这里有个细节:Codex 的 TOML 配置里,provider 的wire_api要设成chat或responses,取决于模型,不确定就先用chat。
配置改完之后,用codex --version确认版本,再用一个简单 prompt 测试连通性。如果返回正常,说明接入成功。这一步很重要,因为后面复现回滚问题时,你需要确认 Codex 确实在执行命令,而不是因为网络问题卡住了。
顺便说一句,如果你用的是 Claude Code 而不是 Codex,配置方式类似,但文件是~/.claude/settings.json,字段是ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN。Claude Code 的接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面有完整的配置示例。
配置好之后,建议先在一个测试仓库里跑,别直接上生产项目。测试仓库里放几个文件,做几次提交,然后让 Codex 改点东西,观察它的行为。这样即使触发回滚,损失也可控。
3. 可复制配置:git 快照规范 + Codex config.toml + auth.json 三件套
这一节给出可以直接复制的配置片段。先说 git 侧的防护,再说 Codex 侧的三件套(Base URL + Key + Model ID)。
git 侧的核心思路是:在任何 AI 编辑之前,先打快照。这样即使 Codex 执行了git restore .,你也能从快照 tag 恢复。下面这段是<INSTRUCTIONS>规范,可以放到项目的AGENTS.md或 Codex 的指令文件里,让它每次改代码前先执行。
<INSTRUCTIONS> ## Git snapshots before any AI edits (REQUIRED) 在对仓库进行任何代码/文件修改(包括 apply_patch、格式化、自动修复等)之前,必须先创建一个快照提交并打 tag。 执行顺序固定如下: 1) git add -A 2) git commit -m "snapshot before AI" 3) git tag ai-pre-<timestamp> ### timestamp 规范 - 使用本地时间,格式:YYYYMMDD-HHMMSS,例如:ai-pre-20260209-141530 ### 例外处理 - 如果工作区没有变更导致 git commit 失败,则使用 git commit --allow-empty -m "snapshot before AI" 再继续第 3 步。 </INSTRUCTIONS>光有规范还不够,Codex 不一定每次都遵守。更稳的做法是在 git 层面加一层保护:配置git config让 restore 类操作需要确认,或者用 alias 把危险命令包一层。下面这段是 git 配置,可以复制到~/.gitconfig或项目级.git/config。
[alias] # 安全版 restore,先 stash 再 restore,避免直接丢改动 safe-restore = "!f() { git stash push -u -m \"pre-restore-$(date +%Y%m%d-%H%M%S)\"; git restore \"$@\"; }; f" # 查看最近的回滚痕迹 rollback-log = "reflog --date=iso --pretty=format:'%h %gd %gs'" [core] # 禁止自动 gc 在关键时刻清理对象 autogc = false [gc] auto = 0这段配置的作用是:git safe-restore会先把改动 stash 起来再 restore,即使 restore 了也能从 stash 找回;git rollback-log快速看 reflog;关掉自动 gc 避免对象被清理。
接下来是 Codex 的三件套。auth.json路径~/.codex/auth.json:
{ "OPENAI_API_KEY": "sk-你的TaoToken密钥" }config.toml路径~/.codex/config.toml:
model = "gpt-5-codex" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" wire_api = "chat" env_key = "OPENAI_API_KEY"这里三个关键字段:base_url指向 TaoToken 的 API 地址,env_key指定从环境变量读 key(也可以直接读 auth.json),wire_api选chat。模型 ID 按你实际用的填,TaoToken 支持的模型列表在控制台能看到。
如果你用的是 Claude Code,配置换成~/.claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "sk-你的TaoToken密钥", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }三件套配齐后,用codex exec "echo hello"或类似命令测试。如果 Codex 能正常返回,说明 Base URL、Key、Model ID 都对上了。这一步是后面复现验证的前提。
4. 验证请求与成功结果:复现回滚并确认来源
配置好之后,开始复现。目标是让 Codex 在一个可控的测试仓库里触发回滚,然后确认是哪个环节干的。
先建测试仓库:
mkdir codex-rollback-test && cd codex-rollback-test git init echo "line 1" > a.txt echo "line 2" > b.txt git add -A git commit -m "init"然后制造一些未提交的改动:
echo "uncommitted change in a" >> a.txt echo "new file" > c.txt git status此时a.txt有未提交改动,c.txt是未跟踪文件。现在开一个 Codex 会话,让它改点东西。用codex进入交互模式,输入类似「帮我把 b.txt 的内容改成 hello」的 prompt,并开启 auto-run。观察 Codex 执行了哪些命令。
如果 Codex 执行了git restore .,你会看到a.txt的改动消失,但c.txt还在(因为 restore 不影响未跟踪文件)。这就是典型的 restore 特征。此时用git reflog --date=iso看 HEAD 有没有移动,如果没移动,说明是工作区级别的 restore,不是 reset。
git reflog --date=iso git status如果 reflog 没有异常,但改动没了,基本锁定是git restore .或git checkout .。接下来去 Codex 的会话日志里搜。Codex 的会话文件通常在~/.codex/sessions/下,按时间排序找最近的:
ls -lt ~/.codex/sessions/ | head grep -r "restore\|checkout\|reset" ~/.codex/sessions/ | tail -20如果搜到了git restore .,元凶确认。如果没搜到,那可能是 IDE 或 hook 触发的,进入下一步。
Android Studio Local History 的检查步骤:在 Android Studio 里右键项目根目录 → Local History → Show History,会弹出一个时间线窗口。左侧是时间点,右侧是文件差异。找到回滚发生前后的时间点,对比差异,就能看到哪些文件被改了。Local History 的存储路径在系统缓存里,Windows 是%LOCALAPPDATA%\Google\AndroidStudio<版本>\LocalHistory,macOS 是~/Library/Caches/Google/AndroidStudio<版本>/LocalHistory,Linux 是~/.cache/Google/AndroidStudio<版本>/LocalHistory。
Local History 的局限是保留时间有限,默认几天到两周,而且不是所有文件都记录。如果回滚发生得早,可能已经过期。所以它只能作为辅助手段,不能当主力恢复方案。
成功复现的标志是:你能明确说出「这次回滚是 Codex 在 X 时间执行了git restore .导致的」,并且能从快照 tag 或 stash 里恢复改动。下面给一个恢复示例:
# 从快照 tag 恢复 git tag | grep ai-pre git checkout ai-pre-20260209-141530 -- . # 或者从 stash 恢复 git stash list git stash pop验证请求是否走 TaoToken 的方法:在 Codex 会话里执行一个需要调用模型的 prompt,同时看 TaoToken 控制台的请求日志。如果日志里有对应的请求记录,说明 endpoint 配置正确。这一步能排除「Codex 因为网络问题没真正执行」的干扰。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
复现过程中会遇到几类典型报错,逐个说清楚。
401 Unauthorized:最常见,key 不对或没读到。检查auth.json里的OPENAI_API_KEY是不是 TaoToken 的 key,有没有多余空格。如果用的是环境变量方式,确认echo $OPENAI_API_KEY有输出。Codex 读 key 的顺序是 auth.json 优先,其次环境变量。401 还有一种可能是 key 过期或被禁用,去 TaoToken 控制台确认 key 状态。
local proxy failed / connection refused:Codex 尝试连本地代理但失败。检查config.toml里的base_url是不是写成了http://localhost:xxxx,应该改成https://taotoken.net/api。如果系统里配了全局代理环境变量(HTTP_PROXY、HTTPS_PROXY),Codex 可能会走代理,导致连接失败。临时清掉这些变量再试:
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY codex exec "test"reading choices / unexpected response format:Codex 收到的响应格式和预期不符。通常是wire_api设错了。如果模型走的是 chat completions 协议,wire_api要设chat;如果走 responses 协议,设responses。改完重启 Codex 会话。还有一种可能是模型 ID 写错,TaoToken 返回了错误结构,去控制台核对模型 ID。
OAuth / login required:Codex 提示需要登录。这是因为 Codex 默认走 OpenAI 的 OAuth 流程,但你已经改成 API Key 方式了。检查config.toml里有没有preferred_auth_method = "apikey",没有就加上。如果还是提示 OAuth,删掉~/.codex/下的auth.json重新生成,确保格式正确。
git restore 后改动找不回:如果没打快照也没 stash,试试git fsck --lost-found,有时候 git 对象还在,能捞回来。Android Studio 的 Local History 也可以试,但别抱太大希望。最坏情况就是重写,所以快照规范一定要提前配。
多窗口并发冲突:两个 Codex 窗口改同一个仓库,互相覆盖。解决办法是给每个窗口分配独立分支:
git worktree add ../feature-a feature-a git worktree add ../feature-b feature-b每个 worktree 是独立工作区,互不干扰。Codex 在各自目录里跑,就不会出现 A 窗口 restore 掉 B 窗口改动的情况。
Codex 不遵守快照规范:即使写了<INSTRUCTIONS>,Codex 也可能跳过。这时候用 git hook 强制。在.git/hooks/pre-commit里加检查,或者在 Codex 的配置里把 auto-run 关掉,改成逐条确认。关 auto-run 的方法是在config.toml里设approval_policy = "on-request"或类似字段,具体看 Codex 版本。
排查的核心是先定位来源,再对症下药。401 和 proxy 是配置问题,reading choices 是协议问题,OAuth 是鉴权方式问题,restore 是行为问题。分清楚之后,解决起来就快了。
6. 长期编码与 Agent 场景:用 Coding Plan 稳定跑 Codex
如果你只是偶尔用 Codex 改改代码,按上面的配置就够了。但如果你像我一样,长期用 Codex 做功能迭代,甚至跑 Agent 任务,那建议上 Coding Plan。它的好处是额度稳定、endpoint 固定,不会因为临时额度问题中断会话。Coding Plan 的入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面有套餐说明。
长期跑 Codex 的经验是:把快照规范固化到项目里,别指望每次手动打 tag。可以在项目根目录放一个AGENTS.md,把<INSTRUCTIONS>写进去,Codex 每次启动会读。再配合 git hook 做双保险。这样即使 Codex 抽风执行了 restore,也能从快照恢复。
另一个经验是给 Codex 划定工作区。用git worktree或者单独的 clone,别让它和你的主工作区混在一起。Codex 在独立目录里跑,即使回滚也只影响那个目录,主工作区安全。这个习惯能省掉很多麻烦。
模型选择上,Codex 类任务用gpt-5-codex或claude-sonnet-4-5都行,前者对代码补全更友好,后者对长上下文理解更好。在 TaoToken 控制台可以切换模型,不用改代码。模型对话功能在 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,可以用来测试不同模型的表现。
最后说一个实用技巧:在 Codex 会话开始前,先手动执行一次快照命令,把当前状态存下来。这样即使 Codex 不遵守规范,你也有个兜底。命令很简单:
git add -A && git commit -m "snapshot before AI" && git tag ai-pre-$(date +%Y%m%d-%H%M%S)跑完再开 Codex,心里踏实。回滚了就从 tag 恢复,几秒钟的事。这套流程我用了几个月,再没出现过代码被清空的情况。