部落格

AI 刪除了資料庫:7 分鐘復原計畫

Markdown

資料遭刪除後該怎麼做:停止代理程式、記錄事件,並使用 git reflog、PITR、快照和檔案復原。附範例與防護措施。

閱讀全文

重點摘要

AI 代理程式剛剛刪除了你的資料庫、檔案,甚至整個正式環境。最初的 7 分鐘,將決定你能否復原資料,還是永遠失去它。本手冊列出每分鐘該執行的具體命令。先停止代理程式,再記錄事件,接著復原。不要慌張——照著檢查清單做。

你可以在文件中找到使用 Ailoot 的實用資訊。

第 1 分鐘該做什麼:立刻停止,不要慌張

重點摘要

立即停止破壞性寫入者,包含代理停止後仍執行的子程序。不要重啟,也不要結束可能仍開啟刪除檔的無關程序。覆寫與 SSD discard/TRIM 可能讓復原不可能,不能保證成功;改受損副本前,先把證據與存活資料保存到獨立、已驗證裝置。

如果這種事發生在你身上,第一件事就是停止代理程式。不要自行嘗試復原它的操作,不要叫它「全部還原」,也不要執行新的提示。代理程式接下來的每個動作,都可能覆寫仍存有資料的磁碟區塊。

  1. 關閉代理程式的終端機

    立即以 Ctrl+C 中斷危險指令,不要等刪除完成。停止代理不一定會停子指令、遠端工作或資料庫查詢,應辨識並取消真正寫入者;若仍破壞資料,必要時升級終止。保留可能有可復原開啟檔案的無關程序。

  2. 請勿重新啟動筆電

    已刪資料可能仍可復原,但取決於儲存、資料庫行為、SSD discard/TRIM 與後續寫入。盡量減少受影響磁碟寫入,不要假定位元組仍存在。

  3. 請勿關閉已開啟的程序

    保留仍開啟刪除檔的無關程序,因為可能透過檔案描述符復原;這不適用破壞性寫入者,應先停止,不能為保留 handle 而讓刪除繼續。

  4. 開始錄製螢幕

    記錄確切時間、受影響路徑與可見指令輸出;錄影或複製日誌應存到獨立已驗證裝置,不寫受損磁碟。復原前先保存追蹤、未追蹤、忽略檔及 Git 中繼資料。

接下來用 6 分鐘復原。開始吧。

第 2~3 分鐘:精確記錄出錯情況

重點摘要

先診斷,再復原。如果不清楚「刪了什麼、誰刪的、何時刪除,以及用了哪些命令」,你就只能盲目復原,還可能破壞仍然完好的資料。開啟新的終端機視窗(不是代理程式正在執行的那個),執行 git status、git log --since 和 ps aux | grep claude。立即複製 ~/.claude/projects/ 資料夾——其中包含代理程式完整的工作階段記錄,可能有助於復原。

開啟新的終端機視窗。不是代理程式正在執行的那個,而是另一個視窗。依序執行以下三個步驟。

1. 精確記錄 git 儲存庫中的變更:

git status
git log --since="30 minutes ago" --all --oneline

已刪追蹤檔可能仍在 index 或提交中,但任何 restore 前先保存工作樹,包含未追蹤與忽略檔;原地還原可能覆蓋存活編輯,應在獨立副本檢查及復原。

2. 檢查正在執行的代理程式程序:

ps aux | grep -i claude
ps aux | grep -i cursor

辨識真正仍執行危險寫入的程序,名稱匹配本身不足。停止寫入者並驗證已停止,保留持有有用開啟檔的無關程序;正常終止無效且破壞繼續時,可能需要強制終止。

3. 儲存代理程式工作階段記錄:

Claude Code 將 JSONL 工作階段存放在 ~/.claude/projects/。Cursor 則存放在 ~/.cursor/。現在就立即複製一份:

cp -r ~/.claude/projects /external/incident-evidence/claude-projects

將 /external/incident-evidence/ 換成獨立已驗證掛載裝置上既有證據目錄,不能寫受影響磁碟或覆蓋既有證據。這個資料夾保存了與代理程式的完整對話——它執行了哪些命令、如何回覆,以及執行順序。這是調查事件的主要來源,也可能讓你從代理程式掌握的上下文中復原已刪除的檔案(見步驟 4)。

第 4 分鐘:git reflog——最好的機會

重點摘要

Reflog 可找出從分支歷史消失的提交,但不保存未提交工作檔。先將存活資料與 Git 中繼資料保存到獨立裝置,再在複製儲存庫檢查,將驗證提交復原到另一個 worktree;不要先重設受損工作樹。

git reflog 在紀錄仍保留時記下本機參照移動,過期與 pruning 依設定不同,不可達物件可能移除;不是所有歷史提交的保證封存。下方步驟應在獨立裝置保存的儲存庫副本執行。

步驟 1. 檢視記錄:

git reflog --all

你會看到類似這樣的清單:

1a2b3c4 HEAD@{0}: reset: moving to HEAD~3
9z8y7x6 HEAD@{1}: commit: working version of the dashboard
5w4v3u2 HEAD@{2}: commit: added admin panel

找出代理程式造成損害之前的時間點。每一筆記錄都是該時間點儲存庫狀態的「快照」。

步驟 2:復原到獨立工作樹。

將儲存庫與存活工作複製到獨立裝置後,在保存副本執行。把值換成 reflog 中確認過的確切提交 SHA,選未使用分支名與目的地:

RECOVERY_COMMIT='replace-with-verified-commit-sha'
git worktree add -b recovery-check ../recovery-check "$RECOVERY_COMMIT"

查看 ../recovery-check,與保存的未提交檔比對後才複製回去。它另行 checkout,不重設受損工作樹。Linked worktree 共用複製儲存庫物件,因此是復原工作區,不是獨立備份。詳見 git-worktree 官方文件。

如果 reflog 也已遭清除(代理程式成功執行了 git gc):

git fsck --lost-found

這個命令會找出不再連結到任何分支的「遺失」提交和 blob(檔案物件)。它們會出現在 .git/lost-found/commit/ 和 .git/lost-found/other/。若要從中還原檔案:

git cat-file -p <SHA1-blob> > recovered-file.ext

git reflog 無法協助的情況:

  • 檔案只存在工作目錄中,沒有提交或 stash → reflog 找不到它
  • 已經過了 90 天(標準的 gc.reflogExpire),而且執行過 git gc
  • 整個儲存庫遭到刪除(rm -rf .git)——此時需要 Time Machine 或快照

第 5 分鐘:從備份還原資料庫

重點摘要

PostgreSQL 時間點復原(PITR)可以將資料庫還原到 7~35 天期間內的任何一秒。Yandex Cloud Managed Postgres、AWS RDS、Supabase Pro,以及 Coolify 中透過本機 pg_dump cron 工作都支援這種做法。關鍵條件是 PITR 必須在事件發生前啟用;事後無法補開。務必還原至新的執行個體,絕不要覆蓋正在運作的資料庫,避免回復操作再毀掉更多資料。如果未啟用 PITR,請使用最新的快照。

資料庫遭到 DROP DATABASE、DROP TABLE 或 DELETE FROM ... WHERE ...(沒有 WHERE 子句)刪除。該怎麼辦?

步驟 1. 確認你的服務供應商是否提供 PITR:

服務供應商PITR 時間範圍還原方式
AWS RDS1~35 天(可設定)aws rds restore-db-instance-to-point-in-time --restore-time 2026-05-28T14:30:00Z
Yandex Cloud Managed Postgres7 天(預設)在主控台從備份還原並指定時間
Supabase Pro7 天(僅限 Pro+)UI:Database → Backups → Restore
Coolify + 本機 pg_dump依 cron 排程而定pg_restore -d new_db backup.dump

步驟 2. 還原至新的執行個體,而非舊的:

絕不要覆蓋正在運作的資料庫。從備份建立新的執行個體,接著將應用程式切換至該執行個體。如果出了問題,你可以將 DNS 切回原設定。

步驟 3. 如果沒有啟用 PITR,請使用最新的快照:

# AWS RDS,列出快照:
aws rds describe-db-snapshots --db-instance-identifier my-db

# 從快照還原:
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier my-db-restored \
  --db-snapshot-identifier rds:my-db-2026-05-28-12-00

Supabase 的注意事項:2026 年有不少人遇到這個問題:啟用 PITR 後,每日備份就會停止建立。這種行為違反直覺,最後可能完全沒有備份。請檢查 Dashboard → Database → Backups,確認 PITR 已啟用,而且有可供還原的快照。

第 6 分鐘:Time Machine、lsof 和磁碟快照

重點摘要

如果檔案是從磁碟刪除,而不是從 git 或資料庫刪除,有三種實用的復原方式。macOS 上可以使用 Time Machine 的每小時快照(前提是筆電曾連接 Time Capsule 或外接硬碟)。Linux 上執行 sudo lsof | grep deleted,可以取回程序仍開啟的檔案(成功率 95%);透過 /proc/PID/fd/N 複製檔案。遇到關鍵情況時,先用 dd 建立整個分割區的快照,再用 extundelete 或 photorec 復原。

macOS——Time Machine:

# 列出快照:
tmutil listbackups

# 從最新備份還原檔案:
tmutil restore /Volumes/Backup/.../my-project/file.tsx ~/projects/my-project/file.tsx

Time Machine 每小時建立快照,保留一小時快照一天、每日快照一週,並無限期保留每週快照。如果筆電連接 Time Capsule 或外接硬碟,你的專案就能以每小時為單位復原。

Linux——檔案已刪除,但程序仍開啟著它:

# 找出程序仍開啟的所有「已刪除」檔案:
sudo lsof | grep deleted

# 你會看到類似以下的行:
# node 12345 user 24w REG 8,1 4096 1234567 /path/to/deleted/file.txt (deleted)

# 直接從 /proc/PID/fd/N 複製檔案:
sudo cp /proc/12345/fd/24 ~/recovered-file.txt

如果程序尚未關閉,成功率約為 95%。適用於 ext4、xfs、btrfs。

macOS——使用 lsof 的對應方式:

lsof | grep deleted

複製檔案比較困難(因為沒有 /proc/),但可以用 lldb:

lldb -p 12345
(lldb) memory read --outfile recovered.txt --binary 0xADDRESS 0xSIZE

整顆磁碟的快照(Linux,最後手段):

sudo dd if=/dev/sda1 of=/external/disk-image.img bs=4M status=progress

這會將整個分割區儲存為映像檔。接著用 extundelete 或 photorec 復原。復原成功的機率取決於刪除後寫入磁碟的資料量。如果完全沒有寫入,成功率為 80~90%。如果已經運作了一小時,成功率為 20~30%。

第 7 分鐘:如果沒有備份怎麼辦

重點摘要

沒有備份、git reflog 是空的,而且磁碟已被新資料覆寫。還有兩種最後手段:聯絡服務供應商的支援團隊(AWS、Yandex Cloud 和 Google Cloud 有時會從內部儲存復原資料),或透過 S3 版本控制還原(若已啟用,所有版本都仍實際存在)。

選項 1——服務供應商支援:

AWS、Yandex Cloud、Google Cloud 和 DigitalOcean 有時會從內部儲存復原資料,即使客戶遭遇重大故障也一樣,付費方案尤其如此。建立支援工單,提供事件發生的確切時間,並附上狀態截圖。保留自動備份的大型供應商最常能透過這種方式提供協助。成功率為 40~60%;等待回覆的時間是 24~72 小時。

選項 2——S3 版本控制:

如果檔案位於 S3(或 Yandex Object Storage),而且已啟用版本控制,所有版本都實際存在;它們只是被標記為「已刪除」。

# AWS——列出版本:
aws s3api list-object-versions --bucket my-bucket --prefix files/

# 還原版本:
aws s3api copy-object \
  --bucket my-bucket \
  --copy-source my-bucket/files/data.json?versionId=ABC123 \
  --key files/data.json

重要注意事項: Claude Code 不會永久保留工作階段。舊的 JSONL 檔案會在幾週後自動刪除。若要確保發生災難時手上有一個月的 JSONL 歷史,請每週用簡單的 cron 工作將 ~/.claude/projects/ 複製到外接硬碟:

# 在 crontab 中設定每週日 03:00 執行:
0 3 * * 0 rsync -av ~/.claude/projects/ /external/claude-history-backup/

這是免費的,而且能在「所有東西都不見了、沒有備份,reflog 也是空的」時救你一命。

確保這種事不再發生的 7 條規則

重點摘要

以下 7 條規則可避免 AI 代理程式刪除你的資料庫或程式碼。破壞性操作前先使用 Plan Mode。用經測試 hooks 偵測部分危險指令字串,並搭配強制權限限制。提供唯讀資料庫使用者給代理程式。每次編輯檔案後自動提交。用隔離的沙盒資料夾進行實驗。每小時用 restic 建立磁碟快照。將 JSONL 工作階段封存到外接硬碟。

1. 任何破壞性操作前都使用 Plan Mode。 在 Claude Code 中:

claude --plan

代理程式會在執行操作之前先建立計畫。你可以檢查計畫,看到 DROP TABLE users 時就取消。沒有 Plan Mode,代理程式會自行決定並在幾毫秒內執行。詳情請見Claude Code 的 Plan Mode 指南。

2. Hooks 是額外警報線。 使用經測試的 PreToolUse hook,從 stdin 讀事件 JSON,偵測高風險時 exit 2。下方完整範例涵蓋 Bash、Write 與 Edit,但不是安全邊界,也可能漏掉間接操作;資料庫與 sandbox 權限仍應嚴格限制。

3. 為代理程式建立唯讀 DB 使用者。 建立一個沒有 DROP、TRUNCATE 或 DELETE 權限的獨立使用者:

CREATE USER claude_readonly WITH PASSWORD 'xxx';
GRANT CONNECT ON DATABASE myapp TO claude_readonly;
GRANT USAGE ON SCHEMA public TO claude_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_readonly;

代理程式真的需要寫入時,再手動切換到不同使用者。唯讀使用者足以處理日常任務(資料分析、報表、儀表板)。

4. 將確認過的變更記錄到 Git。 在 .claude/settings.json 中,PostToolUse hook 可以在 Write 和 Edit 之後顯示提醒:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "printf '%s\\n' '請檢查差異,並只手動提交已議定的檔案。' >&2"
          }
        ]
      }
    ]
  }
}

這個範例只顯示提醒,不會暫存檔案或建立提交。請檢查差異,並只手動提交已議定的檔案。reflog 不會儲存尚未提交的變更。

5. 為實驗準備沙盒專案。 絕對不要讓代理程式在含有真實客戶資料的專案中工作。建立獨立的 ~/sandbox-projects/ 資料夾,其中放置專案複本和合成資料。用它測試新的提示、代理程式或 MCP 伺服器。即使測試出錯,也不會造成損害。

6. 每小時用 restic 建立磁碟快照。

# 安裝:
brew install restic  # macOS
sudo apt install restic  # Linux

# 建立儲存庫:
restic init --repo /external/backups

# 備份目前的專案:
restic --repo /external/backups backup ~/projects

# 設定 cron 每小時執行:
crontab -e
# 加入:
0 * * * * restic --repo /external/backups backup ~/projects

保留 7 天的每小時備份、4 週的每日備份,隨時都能還原到過去任何時間點。免費,而且只需 10 分鐘即可設定完成。

7. 封存 Claude Code JSONL 工作階段。 上文已經提過,但仍要另外列為一條規則:安排每週用 rsync 將 ~/.claude/projects/ 備份到外接硬碟。免費,而且在 crontab 中加一行就能完成。

可直接使用、用來封鎖危險命令的 hooks

重點摘要

下方 PreToolUse 警報線只檢查部分 Bash 字串與敏感 Write/Edit 路徑,讀 stdin JSON、匹配時 exit 2。它可能漏掉間接或混淆操作,只補充 sandbox 與受限憑證;合併至既有設定,測試後才使用。

將以下項目合併至 .claude/settings.json,不要取代既有 hooks:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/check-risk.py\""
          }
        ]
      }
    ]
  }
}

建立 .claude/hooks/check-risk.py,內容如下:

import json
import re
import sys
from pathlib import Path

try:
    event = json.load(sys.stdin)
    tool = event["tool_name"]
    data = event["tool_input"]
    blocked = False
    if tool == "Bash":
        command = data["command"]
        blocked = bool(re.search(
            r"drop\s+(database|table)|truncate\s+table|"
            r"delete\s+from.*where\s+1|rm\s+-rf|"
            r"git\s+reset\s+--hard|git\s+push.*(--force|-f)|"
            r"chmod\s+-R\s+777",
            command, re.IGNORECASE | re.DOTALL))
    elif tool in ("Write", "Edit"):
        path = Path(data["file_path"]).resolve()
        blocked = (".git" in path.parts or path.name.startswith(
            (".env", "credentials", "secrets")))
except (ValueError, KeyError, TypeError, OSError):
    print("BLOCKED: invalid hook input", file=sys.stderr)
    sys.exit(2)

if blocked:
    print("BLOCKED: high-risk command or sensitive path", file=sys.stderr)
    sys.exit(2)
sys.exit(0)

Hook 從 stdin 讀官方 JSON 事件,檢查 tool_input.command 或 tool_input.file_path,匹配時 exit 2,涵蓋 Write 與 Edit。先測無害允許 fixture 與阻擋 fixture,確認 Python 與設定的腳本確實啟動。

這是字串警報線,可能漏掉重排旗標、腳本、別名、混淆、其他工具及間接寫入,也可能誤擋引號內例子。它不變更 OS/資料庫權限。正式憑證應放在代理環境外,使用唯讀資料庫角色與強制 sandbox,保護 hook 設定不被修改。詳見官方輸入與結束碼參考。

刻意例外操作應先審查,再以適當受限帳戶於代理外執行。Shell 環境變數不是有文件支持的 hook 停用介面,hooks 也不管一般終端機指令。

何時該授予 AI 權限,何時不該

重點摘要

在含有真實資料的專案中,絕對不要對代理程式使用 --dangerously-skip-permissions 旗標。在這種 YOLO 模式下,所有防護都會停用,代理程式可以執行任何 Bash 命令、未經確認就寫入檔案,而且啟動的子代理程式也會繼承 YOLO,無法覆寫。只有在沙盒資料夾中,使用虛擬資料測試新 MCP 伺服器或提示時,才使用 YOLO。其他情況請透過 .claude/settings.json 設定明確的 allow 和 deny 規則,精確控制權限。

Anthropic 將 --dangerously-skip-permissions 旗標(也稱為 YOLO 模式)列為「可信任環境」的選項。以 2026 年的現況來看,這是直接引發災難的途徑。不要求代理程式確認,代表它可以:

  • 不經確認執行任何 Bash 命令
  • 不經詢問就寫入檔案
  • 呼叫子代理程式,而子代理程式也會繼承 YOLO,無法撤銷

第三點最令人擔憂。如果你用 YOLO 啟動主要代理程式,它的子代理程式也會是 YOLO,而且你無法覆寫。一個提示就可能讓 10 個平行代理程式接連執行,對系統為所欲為。

規則:

情況可以使用 YOLO 嗎?
在沙盒資料夾測試新的 MCP 伺服器✅ 可以
使用虛擬資料測試新的提示✅ 可以
處理真實專案檔案❌ 不可以
任何會碰到資料庫的命令❌ 絕對不可以
部署至正式環境❌ 絕對不可以
管理基礎架構(AWS、Yandex Cloud)❌ 絕對不可以

替代方案——精確設定權限。 在 .claude/settings.json 中:

{
  "permissions": {
    "allow": [
      "Bash(git status:*)",
      "Bash(git log:*)",
      "Bash(npm run build:*)",
      "Read(*)",
      "Edit(src/**)"
    ],
    "deny": [
      "Bash(rm:*)",
      "Bash(git push:*)",
      "Edit(.env)",
      "Edit(prisma/migrations/*)"
    ]
  }
}

代理程式會知道哪些操作允許、哪些不允許。你不必每次都按「是」或「否」——代理程式可以快速工作,而你則能控制權限範圍。

下一步:收藏這份 7 分鐘檢查清單

重點摘要

現在就把本指南加入書籤。災難發生時,打開頁面,依序照著 10 點檢查清單操作。這能替你省下 30 分鐘的慌亂,也能避免不小心覆寫仍可能復原的資料。復原完成後,再回來設定 7 條預防規則,避免下週又發生災難。

檢查清單:「AI 把東西刪掉了——我該怎麼辦?」

  1. 立即停止真正破壞性寫入者,驗證子程序與遠端操作已停止
  2. 不重啟,保留持有刪除檔的無關程序
  3. 將事件時間與指令證據記錄到獨立已驗證裝置
  4. 將存活檔案、Git 中繼資料與相關工作階段日誌複製到該獨立裝置
  5. 在保存儲存庫副本查看 git reflog --all,將已驗證提交復原到獨立 worktree
  6. 如果 git 無法協助——執行 git fsck --lost-found
  7. 資料庫:使用 PITR(AWS/Yandex/Supabase)或最新快照
  8. 檔案:Mac 使用 Time Machine,Linux 使用 lsof
  9. 最後手段:服務供應商支援 + S3 版本控制
  10. 復原後,設定本指南中的 7 條預防規則

接下來——全面防護:

開啟 Ailoot。

更多詳情

常見問題:AI 刪除了資料庫:7 分鐘復原計畫

應等代理目前的指令完成再停止嗎?

不應。立即停止破壞性寫入者,確認子程序、遠端或資料庫操作也已停止。保留可能持有可復原刪除檔的無關程序;只停代理,可能仍有別的寫入者。

能用 git reset --hard 開始復原嗎?

先把存活的追蹤、未追蹤、忽略檔與 Git 中繼資料保存到獨立裝置。在複製儲存庫檢查,將已驗證提交復原到獨立 worktree;原地 hard reset 可能摧毀尚存未提交修改。

所有文章