你让 agent 把过去一小时的活儿撤了。它跑了 git reset --hard HEAD~3,报告「已回滚」。代码确实回来了,但是:数据库还多着 20 分钟前 migration 加的那个列;dist/ 里还是旧 bundle、Vercel 已经部上线了;Stripe webhook URL 在 dashboard 里被改过指到一个已经不存在的路径;PostHog 里 BILLING_V2_ENABLED 还开着。
「回滚」只撤 git 里有的——其他一切(生成产物、DB 状态、第三方配置、环境变量、feature flag、缓存)各有自己的生命周期。完整回滚是一份按域 checklist,不是一条 git 命令。下面拆解 agent 通常漏的 6 个域,加能 catch 的 prompt。
常见原因
按命中率从高到低:
1. Agent 只回了 git tracked 的代码
git reset --hard 回代码,其他都不动。Agent 自信地说”已回滚”——它眼里的”状态”是 repo,不是系统。
如何判断:回滚完磁盘上代码是目标 commit,但跑起来表现还是新代码——某处的输出/状态 ≠ 代码。
2. DB migration 已应用且非幂等
新 feature 加了列,agent 跑了 migration。现在代码回了但列还在——老代码读/写它不认识的 schema 可能直接挂。
如何判断:pnpm db:status 或 prisma migrate status 显示 migration 已应用。或老代码的 model 定义和在线 DB schema 不一致。
3. dist/、.next/、.svelte-kit/ 产物没重建
代码回了,但 dev server 还在服务缓存的编译产物——浏览器看到的是新行为。更糟:你的部署管道把 dist/ 推到了 CDN,CDN 还在服务它。
如何判断:代码 X、浏览器 Y。ls -la dist/ 文件比最新代码 commit 还新。
4. 第三方配置改了没回
新 feature 要改 Stripe webhook URL、Google OAuth redirect URI、Cloudflare DNS——这些完全在 repo 外。Agent 根本不知道。
如何判断:回滚后外部集成挂——因为它们在 call 已经不存在于回滚代码里的 URL。
5. 环境变量 / feature flag 还开着
NEW_FEATURE_ENABLED=true 还在 .env.production 或 PostHog/LaunchDarkly。新代码没了,flag 要么没用、要么被老代码读到崩——因为老代码不认识这个 flag。
如何判断:vercel env ls(或你平台对应命令)有的变量在回滚后的 .env.example 里找不到。
6. 缓存(CDN / Redis / 浏览器)还有新响应
Cloudflare 缓存了新 API 响应 1 小时;Redis 缓存了新计算值 24 小时。代码回了,用户在 cache 过期前还是看新数据。
如何判断:硬刷新 / 换浏览器 / curl 看到老的,但普通浏览器看新的——cache 层是差异。
最短修复路径
按收益从高到低。Step 1 是框架,2-6 是按域回滚。
Step 1:列出原改动触达的每个域
回滚前先做”blast radius 清单”:
为最近 3 个 commit,列出受影响的每个域:
1. Git 代码:哪些文件
2. 构建产物:哪些 dist/build 目录
3. DB:哪些 migration 应用了、什么 schema 变化
4. 环境变量:哪个 env 加/改了什么
5. Feature flag:哪个工具里新建/翻转了什么
6. 第三方配置:Stripe/OAuth/DNS 等的具体改动
7. 缓存:CDN/Redis/浏览器哪层可能还存着新状态
每个域给出精确回滚动作 + 对应命令。
你立刻能看出哪些域得在 git revert 之外另外处理。
Step 2:用 git revert,不要 git reset --hard
git reset --hard 破坏性,同分支别人的活儿会丢——用 revert 它新建反向 commit:
# 反向 revert 最近 3 个 commit
git revert HEAD~2..HEAD --no-edit
git push origin HEAD
然后部署反向后的代码让生产跟上。
Step 3:回滚 DB migration
migration 是非破坏性的(只加列/表)——老代码可能还能跑,schema 不动、停止使用即可。破坏性的(改名 / 删列)需要显式 down migration:
# Prisma
pnpm prisma migrate resolve --rolled-back <migration_name>
# 再建一个反向 migration
pnpm prisma migrate dev --name revert_<original_name>
# Drizzle / 原生 SQL
pnpm db:rollback # 如果框架有
# 没有就手写 undo migration
有 migration 前的 DB 备份的话,从备份恢复有时比手写 down migration 简单。
Step 4:重建并重部产物
# 本地
rm -rf dist .next .svelte-kit node_modules/.cache
pnpm install
pnpm build
# 推
vercel deploy --prod
# 或触发 CI 重部
# 清 CDN
curl -X POST "https://api.cloudflare.com/client/v4/zones/<zone>/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-d '{"purge_everything":true}'
别信”部署会自动 pick up revert”——强制干净重建 + cache purge。
Step 5:回第三方配置和 env 变量
每个外部系统走一遍,照着 checklist:
- Stripe webhook URL:https://app.example.com/api/webhooks/billing(原 /api/v2/webhook)
- Google OAuth redirect:https://app.example.com/auth/callback
- DNS:api.example.com CNAME
- PostHog flag BILLING_V2_ENABLED:关
- Vercel env vars 新增:BILLING_V2_API_KEY 删
- Cron 调度:hourly billing-sweep 停
这些手动回滚是 agent 漏得最多的部分。团队用 Terraform/Pulumi 管这块的话,git revert + terraform apply 就够;否则得在 dashboard 里点。
Step 6:必要时强制清缓存
# Cloudflare 全清
wrangler cache purge --zone <zone-id>
# Redis 特定 key(或 dev 直接 flush)
redis-cli --scan --pattern "billing:v2:*" | xargs redis-cli del
# 浏览器:让用户硬刷新,或在 HTML 里 bump 资源版本号
面向用户的 cache,TTL 短(分钟级)就等它自然过期;TTL 长才强制 invalidate。
预防建议
- 任何跨域风险改动前先做”rollback inventory”——每个可能被动的域都快照
- migration 做幂等 + 可逆——每个 up 都有测过的 down
- 风险发布用 feature flag——秒级关 flag,不需要回代码
- 第三方配置走 IaC(Terraform / Pulumi)——回滚 = git 操作
- 每个 feature 写「回滚 runbook」——agent 和人都按它走
- 不要把
git reset --hard "rolled back"当完整答案——每个域再核一次
相关阅读
- AI 回滚工作流
- Multi-agent 冲突
- Claude Code 新手入门
- Claude Code 工作流
- Claude Code 项目配置
- Claude Code 写了一堆没人用的 helper:6 个 over-engineering 触发 + YAGNI 强制
- Claude Code 误把密钥 commit 进 git:6 个来源 + 「先 rotate 后清史」处置
- Claude Code 不照审计报告做:6 个降为「建议」的原因 + 把报告当合同
- Claude Code 误解你的项目架构:6 个 generic prior 取胜 + 用「我们用 / 我们不用」清单 + canonical 锁死
- Claude Code 权限提示陷入循环
- Claude Code 跳过 / 削弱失败的测试:6 种作弊形态 + 「禁改测试」防御
- Claude Code 因额度耗尽中途停下:6 类 limit + 可恢复任务设计
- Claude Code 部分执行后卡死:6 种卡死形态 + 分清「上下文 / 工具挂 / 静默 abort」
- Claude Code 工具执行卡死无超时
- Claude Code MCP 调用反复超时
- Claude Code Bash 沙箱阻止预期命令 —— 排查与修复
- Claude Code 会话恢复后丢失先前工作记忆 —— 排查与修复
- Claude Code 自定义状态栏脚本报错或卡顿 —— 排查与修复
标签: #排查 #Claude Code #排查 #回滚