---
url: https://ain.hmgf.hxcn.space/ai/ai-file-deletion-defense-202605.md
description: 从真实删文件事故出发，分层解释 trash、规则文件、Git 提交点和恢复流程分别能防什么、不能防什么。
---

# AI 删文件防御与 Git 兜底

> 下午让 Codex 给我写代码，遇到一个问题让它修复，我开始刷抖音，一抬头，AI 跟我说这个文件夹好像是空的，我一看我去，桌面上的文件都没了，我看一下 D 盘，直接给我清空了。
>
> 我写的论文，年后要发论文，没备份也没了。用恢复工具能扫描出来结构，能扫描出来文件大小，但是二进制全是 0，恢复之后不可打开。
>
> 太绝望了，提醒大家，用编程工具权限不要给那么高，也不会对你的数据负责。
>
> 相关 X 链接：
>
> * https://x.com/Astronaut\_1216/status/2054935258487996598
> * https://x.com/Astronaut\_1216/status/2054943034937389214

看完这类事故，很多人会立刻补两样东西：一条"不要用 rm"的规则，或者一个"反正还有 Git"的心理安慰。两样都不够，因为 `trash`、规则文件、Git、远程仓库、额外备份，本来就在不同层上工作。

这一篇只做一件事：把防护层和兜底层分开讲清楚。前者回答"怎样让模型少删"，后者回答"删了之后怎么退"。两者都要有，顺序不能反。

## 第一层：将不可逆删除改为回收站删除

很多人第一反应是在 `AGENTS.md` 或 `CLAUDE.md` 里加一句：

```text
删除文件时使用 trash，不要直接使用 rm。
```

或者更激进一点，在 shell 里做别名：

```bash
alias rm='trash'
```

这类做法当然有意义，但意义非常具体：**把一部分"手滑式删除"改成可恢复的删除**。如果模型老老实实照着你给的命令习惯走，它原本会直接删掉文件，现在会把文件移进垃圾桶，你至少还有撤回窗口。

这个思路适合放在仓库规则里，也适合放在个人 shell 环境里。不同系统里，你可能用的是 `trash`、`trash-put`、macOS 的同类工具，甚至是你自己的包装脚本。关键是行为语义：先进入垃圾桶，给自己留一个撤回窗口。

## 这一层的局限

问题在于，alias 和规则文件从来都算不上硬隔离。

alias 方面。Bash 官方手册明确写了：alias 默认只在**交互式 shell** 展开；非交互式 shell 除非显式打开 `expand_aliases`，否则不会替换。很多 Agent 调命令时，并不一定跑在你平时手敲命令的那个交互式环境里。也就是说，你在终端里 `rm` 被替换成了 `trash`，不代表模型通过脚本、子 shell 或工具调用发出的 `rm` 也会自动替换。

规则文件也一样。`AGENTS.md`、`CLAUDE.md` 确实有用，但它们是文本约束。模型可能遵守，也可能漏掉，还可能在上下文漂移、任务切换、工具调用链很长的时候绕开。给 `rm` 戴垃圾桶头盔，和给 AI 上儿童锁差不多。能挡掉一部分意外，但挡不住所有路线。

## 模型绕开的方式，至少有这几类

如果你只把防线押在"别用 rm"，那模型真要删的时候，办法并不少。最常见的绕法至少有四类：

### 1. 直接调用绝对路径

```bash
/usr/bin/rm -rf some-dir
```

如果你只做了 `alias rm='trash'`，这种写法根本不会碰你的 alias。

### 2. 用移动代替删除

```bash
mv some-dir /dev/null
```

这条命令本身未必在所有系统上都成立，但它代表的是同一类思路：**绕过 `rm` 这个词本身，换一条文件系统路径做破坏性处理**。你限制的是命令名，它走的是另一套操作语义。

### 3. 在脚本或解释器里删

```python
import os
import shutil
from pathlib import Path

os.remove('notes.md')
Path('draft.txt').unlink()
shutil.rmtree('old-build')
```

Python 官方文档里，`os.remove()` / `os.unlink()` 用于删文件，`os.rmdir()` 用于删空目录，`shutil.rmtree()` 则可以直接删掉整个目录树。只要模型能写脚本、能运行脚本，你限制 shell 命令名并不能挡住解释器层面的删除。

### 4. 重写后提交"空结果"

还有一类不那么显眼：它没有直接删文件，但会把文件内容大面积覆盖，或者把本来该保留的区块替换成空内容，再把结果当成"修复完成"交给你。对恢复来说，这和误删差别不大。

这里要记住的是：**"使用 trash，不用 rm"只是第一层缓冲。**

## 第二层：Git 解决的是"回到上一个可确认状态"

到了这里，Git 的角色就清楚了：它负责把你带回一个明确、可核对、可恢复的版本。

这一层的重点，是你有没有把 Git 用成工作流。

### 开工前建立分支

别让 AI 直接在你当前唯一的工作分支上乱跑。切一个专门分支，至少把这次实验的改动圈起来。

```bash
git switch -c ai/delete-defense-202605
```

如果你更习惯旧命令，也可以：

```bash
git checkout -b ai/delete-defense-202605
```

这样做的价值很直接：后续回退、比较、丢弃都会干净很多。

### 修改前检查工作区状态

每次把任务交给模型前，确认一眼仓库当前状态，别把旧改动和新改动混在一起。

```bash
git status --short
git diff
```

如果一开始就堆着一批未提交文件，模型一旦误删或误改，事后很难分清哪些是旧问题，哪些是这次引入的。

### 关键节点一定要 commit

Git 能兜底的前提，是你手里有可以退回的提交点。最怕的是模型跑了半小时，期间没留任何 savepoint，结果一次性全丢。

一个实用做法是：

* 改动前留一个"起跑点"；
* 跑完一个大步骤留一个"中间点"；
* 准备交卷前留一个"候选结果点"。

命令很普通，但必须真做：

```bash
git add -A
git commit -m "wip: before ai edits"
```

中途如果你验证过一个阶段性结果，也可以继续：

```bash
git add -A
git commit -m "wip: ai pass 1 verified"
```

不要等到"全部做完再一起提交"。你等的这段时间，恰好是最可能把退路一起丢掉的时间。

### AI 修改后的 diff 检查

模型跑完任务，别急着信它那句"已完成"。先把 diff 看完。

```bash
git diff
git diff --staged
```

大删文件、大覆盖、奇怪重排、误动无关目录，这些东西在 diff 里通常比在自然语言回复里明显得多。

如果你看到它改了不该改的地方，别急着让它继续补救。这时最要紧的是保住现场，回退还是局部修，等 diff 看清再定。

## 真出事了，怎么用 Git 回来

### 恢复某个文件到当前提交版本

```bash
git restore path/to/file
```

### 恢复整个工作区的未提交改动

```bash
git restore .
```

### 从某个历史提交里捞回文件

```bash
git restore --source=<commit> path/to/file
```

老一点的写法也可以：

```bash
git checkout <commit> -- path/to/file
```

### 分支彻底跑偏了，直接回到前一个提交点

```bash
git log --oneline
git reset --hard <commit>
```

这一步要谨慎，因为它会丢掉当前工作区的未保存改动。它适合你已经确认"当前这一坨都不要了"的时候。

### `.git` 一起没了怎么办

这时候要冷静一点：**本地 Git 已经帮不了你。**

如果模型删的不只是业务文件，还把 `.git` 目录一起干掉，本地版本历史就没了。你能指望的只剩几种外部退路：

* 远程仓库还在，可以重新 clone；
* 还有别的本地副本、网盘快照、系统备份；
* 再不行才轮到文件恢复工具。

所以 Git 的正确定位是"版本化兜底"。它能救的，是已经进过版本控制、也有提交点可退的内容。

## 第三层：把规则文件当成活文档来维护

`CLAUDE.md / AGENTS.md` 要当活文档维护。

这句话比"写不写规则"本身更重要。很多人第一次被模型坑过后，会补一句规则；第二次、第三次又换别的坑，因为旧规则没人回头整理，新的坑也没人写进流程里。久而久之，规则文件要么太空，要么太乱。

更实用的做法是：每次翻车后，不只是让模型道歉，还要把这次纠正规则整理回文档。比如：

```text
- 删除文件前必须先说明目标路径和原因。
- 涉及批量删除、重命名、移动目录时，先展示拟执行命令，再等待确认。
- 除非用户明确要求，不要执行 commit / push / merge。
- 运行脚本前，先解释脚本会触碰哪些路径。
```

这类规则不能保证零事故，但会让后续同类错误变少。它的价值在于持续纠偏。

## 用户经验：别把它们当基准评测，但也别装没看见

下面这些内容都只按用户公开经验来写，不当成实验室 benchmark，也不当成模型厂商的正式结论。它们的价值在于提醒你：误删、误覆盖、奇怪行为，在不同模型上都可能出现。

### Qwen

有用户在 LINUX DO 里直接写过：让 Qwen 3.5 Plus 去修 Git 错误，结果"直接删库了"，还补了一句"codex 倒是靠谱很多，从来没有乱改我的文件"。这显然只是个人使用感受，但它至少说明一件事：你不能因为模型换了名字，就默认删文件风险自动消失。

### DeepSeek

另一位用户记录的是 DeepSeek V4 Pro (max) 在一次 `edit` 操作里，把两个相同字段之间的几千行代码整段覆盖掉。第一次模型自己发现并修了一次，第二次直接交卷，用户后来的结论是：不敢再让它碰这个项目了。

还有一篇长文本格式保留的体验贴提到：在某些 docx 转 markdown 的场景里，DeepSeek 是唯一把多个换行保留下来的，速度也快；但同一位用户后来又补了一句，某些场景下 DeepSeek 的理解能力还是不够。一个模型可能在某个局部任务里表现不错，但不代表你就该给它高权限。

### MiMo

MiMo 这边，公开帖子里既有"第一次尝试就拉了"的吐槽，也有更细一点的格式保留体验：有用户说 Qwen 和 MiMo 对 `	` 处理得不好，MiMo 速度快，但网页端没有"不思考"模式；也有人在分析项目时碰到离谱回答，清空上下文再问一次才恢复正常。

这些经验合在一起，只能说明一件事：**只要模型拥有改文件权限，工作流和回退路径就得先建好，模型偏好反而该往后放。**

## 一套更稳的"AI 改代码前"动作顺序

把这篇文章压成一份可执行清单，顺序可以这样：

### 1. 轻量防护

* 在 `AGENTS.md` / `CLAUDE.md` 里写清楚删除规则。
* 能用 `trash` / `trash-put` / 包装脚本的地方接上。
* 对批量删除、移动目录、执行脚本设置额外确认。

### 2. Git 起跑动作

```bash
git switch -c ai/safe-edit
git status --short
git add -A
git commit -m "wip: clean base before ai"
```

### 3. 让模型每跑一段就停一次

* 大改前说计划；
* 改完就看 diff；
* 通过一个阶段就留一个 commit；
* 不要让它一路静默跑完全程。

### 4. 问题发生后的现场保全

```bash
git diff
git status
git restore path/to/file
```

先把现场收住，再决定要不要继续让它修。

### 5. 事后把规则补回文档

* 这次是删文件，就补删除规则；
* 这次是误提交，就补 Git 规则；
* 这次是脚本误伤，就补脚本执行范围。

这样做几轮之后，文档才会真的长成团队的防翻车手册。

## 把顺序固定下来

用 `trash` 和确认规则减少直接误删，再用 Git 留分支、提交点和 diff，后面把翻车经验补回 `AGENTS.md` 或 `CLAUDE.md`。如果项目真的重要，再往外补远程仓库、系统快照和额外备份。

顺序固定下来，AI 就算走偏，你手里也还有回头路。
