Claude Code 总删代码?用权限、Git 和分阶段流程管住它
Claude Code 在改代码时偶尔会覆盖、删除文件,甚至执行自己写的脚本把代码搞乱,逐步确认又很累。这篇文章把讨论里的经验整理成三层防护:权限收口、Git 兜底、任务与流程拆分,并说明各种做法的取舍和适用场景。
用 Claude Code 写代码,最让人崩溃的不是它写不出来,而是它"顺手"把你不想动的地方动了:删掉几个文件、把函数整段重写、跑一个自己刚生成的批量脚本,然后告诉你"已完成"。每次操作都弹确认又实在累,于是很多人干脆一路放行,风险随之放大。
下面把这类问题的成因、可行的防护手段和几种流程做法梳理一遍,重点是:不要指望靠一句提示词让它"别删代码",要靠环境和流程让它删不动、删了也能恢复。
它为什么会动你的代码
把 AI 编程工具当成一个"目标导向的执行者"来看,很多行为就说得通了:
- 倾向于整体重写而不是最小改动。让它改一个函数,它可能重排整个文件,diff 一大片,原有注释、边界处理被顺手抹掉。
- 权限给得太宽。默认放行 Bash 后,
rm、git reset --hard、git checkout --、覆盖写文件这类破坏性操作都能直接执行。 - 执行自己生成的脚本。让它批量修改,它写个 PowerShell 或 shell 脚本一次性跑完,脚本本身有 bug,结果比手工改还乱。
- 上下文被压缩或会话太长。聊到后面,早期定下的约束、目录结构、命名规则被稀释,开始"自由发挥",属性、接口张口就来。
- 任务粒度太大。一个大需求丢过去,中间没有检查点,等发现跑偏时已经改了很多文件。
第一层:把破坏性操作关进权限笼子
这是成本最低、收益最直接的一步。在 Claude Code 的 settings 里用 deny 和 ask 规则把高危命令挡掉,只放行日常需要的读写和构建命令。大致思路如下(具体字段与匹配语法以官方 permission settings 文档为准,不同版本可能有差异):
{
"permissions": {
"deny": [
"Bash(rm:*)",
"Bash(git reset --hard:*)",
"Bash(git checkout -- :*)"
],
"ask": [
"Bash(git push:*)",
"Bash(git commit:*)"
]
}
}
几点经验:
deny里的规则要按自己的技术栈调整。比如前端项目可能还要挡掉npm publish,数据库项目要挡掉带DROP的命令。- 不要一上来就把所有命令都设成
ask,确认弹窗太多会导致你条件反射地点同意,防护等于没有。只对真正不可逆的操作设ask。 - 临时需要放开时,用一次性授权或换一个受限目录,而不是改全局配置。
--dangerously-skip-permissions这类全放行模式,只适合在容器、临时目录或可随时丢弃的环境里用。 在放着正式代码的工作目录里长期开这个开关,等于把回滚能力也一起关掉了。
第二层:Git 是最后的保险
权限挡得住已知的危险命令,挡不住"它写了一堆错误代码还告诉你成功了"。这时候能不能一键回到干净状态,决定了你损失十分钟还是半天。
推荐做法:
- 开工前确认工作区干净。
git status有未提交改动时先 commit 或 stash,否则出事后分不清哪些是你的、哪些是它改的。 - 小步提交。每完成一个能验证的最小单元就提交一次,提交信息写清做了什么。AI 一次改十几个文件再一起提交,回滚粒度就没了。
- 大改动开新分支。跑偏了直接切回主分支,不用在 diff 里挑拣。
- 回滚前先看 diff。
git diff确认要丢弃的范围,再决定是git checkout单个文件还是整体重置。 - 别让它执行你没看过的批量脚本。要求它先把脚本内容打印出来,确认影响范围后再运行;能分步执行的,不要一次性跑完。
一个容易忽略的点:AI 有可能在你没注意的时候已经执行过回滚命令,把未提交的改动清掉了。所以"未提交的代码"本身就是高风险资产,重要的东西尽快落到 commit 里。
编辑器自带的时间线、本地历史也是有效的兜底手段,尤其在文件被整体覆盖、又没进版本控制的时候。但它只能救单个文件,替代不了 Git。
第三层:把任务拆成讨论、计划、执行、验收
前面两层是"别让它删"和"删了能恢复",这一层解决的是"少让它跑偏"。讨论里比较成熟的做法是把一次任务拆成几个阶段:
先计划,再动手
- 进入计划模式,让它只输出方案:要改哪些文件、每个文件改什么、依赖哪些现有实现、有哪些风险点。
- 你审核计划,觉得不对就让它改计划,这一步成本极低。
- 计划确认后再进入实际修改。有意外也能在计划阶段提前发现,而不是等代码改完。
把计划落成本地文档
讨论出来的方案写进本地 md 文件,作为后续编写和执行的依据。这样做的好处是:代码可以回滚,方案还在。会话被压缩、上下文丢了,重新开一个会话把文档喂进去就能接上。
文档里建议包含:目标、涉及的文件树、接口与数据结构约定、分步实现计划、验收标准。技术上可以要求它附上同技术栈的伪代码,你自己扫一眼就能发现明显不合理的地方。
分步实现,每步回头对齐
按计划里的 step 逐个实现,每完成一步就让它对照原计划 review:有没有偏离、有没有顺手改了不该改的地方。发现问题立刻收敛,而不是等到最后一起返工。
这套方法的代价很明确:更消耗 token,也更花你的时间。适合中大型改动、多人协作的仓库、或者你不太熟的代码库;如果只是改个文案、调个样式,直接让它动手更划算。
控制会话长度与任务粒度
- 单个讨论会话控制在五轮左右,把结论沉淀成文档后另开会话继续,尽量避免上下文被压缩后行为失准。
- 任务描述尽量具体到文件和函数,比如"只修改
src/utils/date.ts里的formatRange,不要动其他导出"。范围越窄,你越有把控感。 - 新任务开新会话,避免上一个任务的假设被带进来。
几种观点分歧怎么看
"换一个工具就好了。" 换工具能换掉一套默认行为,但风险结构没变:只要它拥有写文件和执行命令的权限、只要没有版本控制兜底,同样的问题会以另一种形式出现。工具选择可以看顺手程度,但权限和流程才是决定性的。
"我把需求文档写得很细,它照样放飞。" 这确实是常见情况:文档再细,模型在长会话里也会逐渐偏离,甚至凭空编造属性。文档的作用不是"保证不跑偏",而是跑偏之后你能快速判断偏在哪、并低成本重来。所以文档必须配合分步 review 使用,写完就撒手不管,效果有限。
"我从来没遇到过。" 通常是因为任务粒度小、改动范围窄、每次都在盯着看。这恰恰说明:风险跟使用方式强相关,而不是工具本身的固定属性。
"每次都确认太累了。" 这个抱怨是合理的。解法不是全部放行,而是把确认集中到少数真正不可逆的操作上,其余交给 Git 和计划文档兜底。
一份可执行的检查清单
- 开工前
git status干净,或在独立分支上作业 - settings 中已对
rm、git reset --hard、git checkout --等设deny或ask - 未在正式代码目录使用全放行模式
- 大改动先出计划,人工审核后再执行
- 计划与约定落成本地 md 文档
- 每个可验证单元完成后立即 commit
- 批量脚本先看内容再执行,能分步就不一次性跑
- 会话超过五轮左右就沉淀结论、另起会话
- 任务描述明确到文件和函数范围
小结
Claude Code 删代码这件事,靠提示词"恳求"它别删,效果有限;靠环境约束和流程设计,才是稳定的解法。优先级建议是:先把权限收口和 Git 小步提交做到位,这两步几乎不增加日常成本;再根据项目重要程度,决定要不要引入计划文档和分步 review。工具会持续更新,权限配置的具体写法请以官方最新文档为准。