OA0
OA0 是一个探索 AI 的社区
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  emergency-rescue:开发者灾难恢复与系统营救工具

emergency-rescue:开发者灾难恢复与系统营救工具

 
  npl ·  2026-02-02 11:58:56 · 18 次点击  · 0 条评论  

名称: emergency-rescue
描述: 应对开发者灾难。适用于有人强制推送覆盖了 main 分支、在 git 中泄露了凭证、磁盘空间耗尽、杀错了进程、损坏了数据库、破坏了部署、锁定了 SSH 访问、变基后丢失提交,或遇到任何其他需要立即、冷静、逐步恢复的“糟糕”时刻。
元数据: {"clawdbot":{"emoji":"🚨","requires":{"anyBins":["git","bash"]},"os":["linux","darwin","win32"]}}


紧急救援工具箱

为开发者一天中最糟糕的时刻提供逐步恢复流程。每个部分都遵循相同的模式:诊断 → 修复 → 验证。默认情况下,命令是非破坏性的。破坏性步骤会特别标注。

当出现问题时,请在下方找到您的情况并按顺序执行步骤。

何时使用

  • 有人强制推送覆盖了 main 分支的历史记录
  • 凭证被提交到公共仓库
  • 变基或重置操作销毁了您需要的提交
  • 磁盘已满,一切无法工作
  • 某个进程占用了所有内存或无法终止
  • 数据库迁移中途失败
  • 需要立即回滚部署
  • SSH 访问被锁定
  • 生产环境 SSL 证书过期
  • 您不知道哪里出了问题,但系统已损坏

Git 灾难

强制推送覆盖了 main(或任何共享分支)

有人运行了 git push --force 并覆盖了远程历史记录。

# 诊断:在任何拥有旧状态的机器上检查引用日志
git reflog show origin/main
# 查找最后一个已知的良好提交哈希值

# 修复(如果您本地有旧状态):
git push origin <good-commit-hash>:main --force-with-lease
# --force-with-lease 比 --force 更安全:如果远程再次更改,它会失败

# 修复(如果您本地没有旧状态):
# GitHub/GitLab 会暂时保留强制推送的引用

# GitHub:检查审计日志中的“推送”事件或使用 API
gh api repos/{owner}/{repo}/events --jq '.[] | select(.type=="PushEvent") | .payload.before'

# GitLab:检查服务器上的引用日志(需要管理员权限)
# 或者从任何 CI 运行器或团队成员的本地克隆恢复

# 验证:
git log --oneline -10 origin/main
# 确认历史记录看起来正确

变基或硬重置后丢失提交

您运行了 git rebasegit reset --hard,提交消失了。

# 诊断:您的提交并没有消失。Git 会将所有内容保留 30 天以上。
git reflog
# 找到变基/重置之前的提交哈希值
# 查找类似 "rebase (start)" 或 "reset: moving to" 的条目

# 修复:重置回灾难前的状态
git reset --hard <commit-hash-before-disaster>

# 修复(替代方案):拣选特定的丢失提交
git cherry-pick <lost-commit-hash>

# 修复(如果引用日志为空——罕见,通常意味着不同的仓库):
git fsck --lost-found
# 在 .git/lost-found/commit/ 中查找悬空的提交
ls .git/lost-found/commit/
git show <hash>  # 检查每一个

# 验证:
git log --oneline -10
# 您的提交应该回来了

提交到了错误的分支

您在 main 分支上进行了提交,但这些提交本应在功能分支上。

# 诊断:检查您当前的位置和提交内容
git log --oneline -5
git branch

# 修复:在当前位置创建功能分支,然后重置 main
git branch feature-branch          # 创建指向当前提交的分支
git reset --hard HEAD~<N>          # 将 main 分支向后移动 N 个提交(⚠️ 破坏性)
git checkout feature-branch        # 切换到新分支

# 修复(更安全的替代方案,使用拣选):
git checkout -b feature-branch     # 创建并切换到新分支
git checkout main
git reset --hard origin/main       # 将 main 重置为远程状态
# 您的提交安全地保留在 feature-branch 上

# 验证:
git log --oneline main -5
git log --oneline feature-branch -5

合并出错(到处都是冲突,结果错误)

合并产生了错误的结果,您想重新开始。

# 修复(合并尚未提交——仍处于冲突状态):
git merge --abort

# 修复(合并已提交但未推送):
git reset --hard HEAD~1

# 修复(合并已被推送):创建一个还原提交
git revert -m 1 <merge-commit-hash>
# -m 1 表示“保留第一个父提交”(合并前您的分支)
git push

# 验证:
git log --oneline --graph -10
git diff HEAD~1  # 查看更改内容

Git 仓库损坏

Git 命令失败,出现“bad object”、“corrupt”或“broken link”错误。

# 诊断:检查仓库完整性
git fsck --full

# 修复(如果远程仓库完好——最常见情况):
# 首先保存任何未提交的工作
cp -r . ../repo-backup

# 重新克隆并恢复本地工作
cd ..
git clone <remote-url> repo-fresh
cp -r repo-backup/path/to/uncommitted/files repo-fresh/

# 修复(无需重新克隆的修复):
# 删除损坏的对象并重新获取
git fsck --full 2>&1 | grep "corrupt\|missing" | awk '{print $NF}'
# 对于每个损坏的对象:
rm .git/objects/<first-2-chars>/<remaining-hash>
git fetch origin  # 从远程重新下载

# 验证:
git fsck --full  # 应报告无错误
git log --oneline -5

凭证泄露

密钥提交到 Git(API 密钥、密码、令牌)

凭证存在于 Git 历史记录中。每一秒都很重要——自动化扫描器会监控公共 GitHub 仓库以寻找泄露的密钥。

# 步骤 1:立即撤销凭证
# 首先执行此操作,然后再清理 Git 历史记录。
# 凭证在公开推送的那一刻就已经泄露了。

# AWS 密钥:
aws iam delete-access-key --access-key-id AKIAXXXXXXXXXXXXXXXX --user-name <user>
# 然后创建新的密钥对

# GitHub 令牌:
# 访问 github.com → Settings → Developer settings → Tokens → Revoke

# 数据库密码:
# 立即在数据库中更改密码
# ALTER USER myuser WITH PASSWORD 'new-secure-password';

# 通用 API 令牌:
# 在提供商的仪表板中撤销,生成新的令牌

# 步骤 2:从当前分支中移除
git rm --cached <file-with-secret>    # 如果整个文件都是密钥
# 或者编辑文件以移除密钥,然后:
git add <file>

# 步骤 3:添加到 .gitignore
echo ".env" >> .gitignore
echo "credentials.json" >> .gitignore
git add .gitignore

# 步骤 4:从 Git 历史记录中移除(⚠️ 重写历史记录)
# 选项 A:git-filter-repo(推荐,使用 pip install git-filter-repo 安装)
git filter-repo --path <file-with-secret> --invert-paths

# 选项 B:BFG Repo Cleaner(适用于大型仓库,速度更快)
# 从 https://rtyley.github.io/bfg-repo-cleaner/ 下载
java -jar bfg.jar --delete-files <filename> .
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# 步骤 5:强制推送清理后的历史记录
git push origin --force --all
git push origin --force --tags

# 步骤 6:通知所有协作者重新克隆
# 他们的本地副本在引用日志中仍然包含密钥

# 验证:
git log --all -p -S '<the-secret-string>' --diff-filter=A
# 应该不返回任何内容

.env 文件被推送到公共仓库

# 步骤 1:撤销该 .env 文件中的所有凭证。全部撤销。立即执行。

# 步骤 2:移除并忽略
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit -m "Remove .env from tracking"

# 步骤 3:从历史记录中移除(参见上面的凭证移除部分)
git filter-repo --path .env --invert-paths

# 步骤 4:检查暴露了哪些内容
# 列出 .env 中的每个变量:
git show HEAD~1:.env 2>/dev/null || git log --all -p -- .env | head -50
# 轮换每一个值。

# 预防:添加预提交钩子
cat > .git/hooks/pre-commit << 'HOOK'
#!/bin/bash
if git diff --cached --name-only | grep -qE '\.env$|\.env\.local$|credentials'; then
    echo "ERROR: Attempting to commit potential secrets file"
    echo "Files: $(git diff --cached --name-only | grep -E '\.env|credentials')"
    exit 1
fi
HOOK
chmod +x .git/hooks/pre-commit

密钥在 CI/CD 日志中可见

# 步骤 1:立即撤销凭证

# 步骤 2:如果可能,删除 CI 运行/日志
# GitHub Actions:
gh run delete <run-id>
# 或者:Settings → Actions → delete specific run

# 步骤 3:修复流水线
# 永远不要回显密钥。对它们进行掩码处理:
# GitHub Actions:echo "::add-mask::$MY_SECRET"
# GitLab CI:如果变量在设置中标记为“Masked”,则会被掩码

# 步骤 4:审计暴露了哪些内容
# 检查日志输出中是否存在以下模式:
# AKIAXXXXXXXXX (AWS)
# ghp_XXXXXXXXX (GitHub)
# sk-XXXXXXXXXXX (OpenAI/Stripe)
# 任何包含密码的连接字符串

磁盘空间耗尽紧急情况

系统或容器磁盘已满

一切无法工作——构建失败、日志无法写入、服务崩溃。

# 诊断:什么占用了空间?
df -h                          # 哪个文件系统已满?
du -sh /* 2>/dev/null | sort -rh | head -20    # 最大的顶级目录
du -sh /var/log/* | sort -rh | head -10        # 日志膨胀?

# 快速解决方案(可立即安全运行):

# 1. Docker 清理(通常是首要原因)
docker system df               # 查看 Docker 磁盘使用情况
docker system prune -a -f      # 移除所有未使用的镜像、容器、网络
docker volume prune -f          # 移除未使用的卷
docker builder prune -a -f      # 移除构建缓存
# ⚠️ 这将移除所有未使用的 Docker 数据。如果可以重新拉取/重建,则是安全的。

# 2. 包管理器缓存
# npm
npm cache clean --force
rm -rf ~/.npm/_cacache

# pip
pip cache purge

# apt
sudo apt-get clean
sudo apt-get autoremove -y

# brew
brew cleanup --prune=all

# 3. 日志轮转(立即生效)
# 截断(而非删除)大型日志文件以立即释放空间
sudo truncate -s 0 /var/log/syslog
sudo truncate -s 0 /var/log/journal/*/*.journal  # systemd 日志
find /var/log -name "*.log" -size +100M -exec truncate -s 0 {} \;
# 截断会保留文件句柄,因此服务不会中断

# 4. 旧的构建产物
find . -name "node_modules" -type d -prune -exec rm -rf {} + 2>/dev/null
find . -name ".next" -type d -exec rm -rf {} + 2>/dev/null
find . -name "dist" -type d -exec rm -rf {} + 2>/dev/null
find /tmp -type f -mtime +7 -delete 2>/dev/null

# 5. 找到真正的罪魁祸首
find / -xdev -type f -size +100M -exec ls -lh {} \; 2>/dev/null | sort -k5 -rh | head -20
# 显示超过 100MB 的文件,按大小排序

# 验证:
df -h  # 检查可用空间是否增加

Docker 特定的磁盘已满

# 诊断:
docker system df -v

# 常见原因:
# 1. 构建产生的悬空镜像
docker image prune -f

# 2. 累积的已停止容器
docker container prune -f

# 3. 构建缓存(通常是最大的)
docker builder prune -a -f

# 4. 旧容器的卷
docker volume ls -qf dangling=true
docker volume prune -f

# 核选项(⚠️ 移除所有内容):
docker system prune -a --volumes -f
# 您将需要重新拉取所有镜像并重新创建所有卷

# 验证:
docker system df
df -h

进程紧急情况

端口已被占用

# 诊断:什么占用了端口?
# Linux:
lsof -i :8080
ss -tlnp | grep 8080
# macOS:
lsof -i :8080
# Windows:
netstat -ano | findstr :8080

# 修复:终止进程
kill $(lsof -t -i :8080)           # 优雅终止
kill -9 $(lsof -t -i :8080)       # 强制终止(如果优雅终止无效)

# 修复(Windows):
# 从 netstat 输出中找到 PID,然后:
taskkill /PID <pid> /F

# 修复(如果是残留的 Docker 容器):
docker ps | grep 8080
docker stop <container-id>

# 验证:
lsof -i :8080  # 应该不返回任何内容

进程无法终止

# 诊断:
ps aux | grep <process-name>
# 记下 PID

# 升级阶梯:
kill <pid>                # SIGTERM(优雅关闭)
sleep 5
kill -9 <pid>             # SIGKILL(无法捕获,立即终止)

# 如果 SIGKILL 无效,可能是僵尸进程或内核卡住的进程:
# 检查是否为僵尸进程:
ps aux | grep <pid>
# 状态 "Z" = 僵尸。父进程必须回收它:
kill -SIGCHLD $(ps -o ppid= -p <pid>)
# 或者终止父进程

# 如果确实卡在内核中(状态 "D"):
# 只有重启才能解决。进程卡在 I/O 系统调用中。

# 批量清理:终止所有匹配名称的进程
pkill -f <pattern>          # 优雅终止
pkill -9 -f <pattern>      # 强制终止

内存不足(OOM 终止)

# 诊断:您的进程是否被 OOM 终止?
dmesg | grep -i "oom\|killed process" | tail -20
journalctl -k | grep -i "oom\|killed" | tail -20

# 检查当前内存使用情况:
ps aux --sort=-%mem | head -20        # 内存消耗最高的进程
free -h                                 # 系统内存概览

# 修复:立即释放内存
# 1. 终止最大的消费者(如果安全)
kill $(ps aux --sort=-%mem | awk 'NR==2{print $2}')

# 2. 丢弃文件系统缓存(安全,无数据丢失)
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

# 3. 禁用交换区颠簸(如果交换区已满)
sudo swapoff -a && sudo swapon -a

# 预防:设置内存限制
# Docker:
docker run --memory=512m --memory-swap=1g myapp

# Systemd 服务:
# 添加到 [Service] 部分:
# MemoryMax=512M
# MemoryHigh=400M

# Node.js:
node --max-old-space-size=512 app.js

# 验证:
free -h
ps aux --sort=-%mem | head -5

数据库紧急情况

迁移失败(部分应用)

# 诊断:数据库处于什么状态?
# 检查哪些迁移已运行:

# Rails:
rails db:migrate:status

# Django:
python manage.py showmigrations

# Knex/Node:
npx knex migrate:status

# Prisma:
npx prisma migrate status

# 原始 SQL — 检查迁移表:
# PostgreSQL/MySQL:
SELECT * FROM schema_migrations ORDER BY version DESC LIMIT 10;
# 或者:SELECT * FROM _migrations ORDER BY id DESC LIMIT 10;

# 修复:回滚失败的迁移
# 大多数框架会跟踪迁移状态。回滚到最后一个良好状态:

# Rails:
rails db:rollback STEP=1

# Django:
python manage.py migrate <app_name> <previous_migration_number>

# Knex:
npx knex migrate:rollback

# 修复(手动):如果框架对状态感到困惑:
# 1. 检查迁移实际做了什么
# 2. 手动撤销部分更改
# 3. 从迁移表中删除迁移记录
# 4. 修复迁移代码
# 5. 重新运行

# 验证:
# 再次运行迁移并确认其干净地应用
# 检查受影响的表/列是否正确存在

意外删除了表或数据库

```bash

PostgreSQL:

如果您配置了 WAL 归档/时间点恢复:

pg_restore -d mydb /backups/latest.dump -t dropped_table

如果不存在备份,检查事务是否仍处于打开状态:

(仅当您尚未提交时有效)

只需在 SQL 会话中运行 ROLLBACK;。

MySQL:

18 次点击  ∙  0 人收藏  
登录后收藏  
0 条回复
关于 ·  帮助 ·  PING ·  隐私 ·  条款   
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
耗时 17 ms
Developed with Cursor