Appearance
常见事故与恢复手册
本章记录了 Git 使用中最常见的"事故"场景及其恢复方法。
提交到错误分支
场景:在 main 上直接提交了应该在 feature 分支上的内容
bash
# 当前状态:main 上有不该有的提交 abc123
git log --oneline main
# abc123 feat: 新功能(错误地提交到了 main)
# def456 fix: 上一个正常提交
# 解决方案:
# 1. 在正确的分支上重建提交
git switch -c feature/new-feature # 创建应该有这些提交的分支
# feature/new-feature 现在包含那些提交
# 2. 在 main 上撤销提交
git switch main
git reset --hard HEAD~1 # 或 git reset --hard def456
# 如果 main 已推送:
git push --force-with-lease origin main合并了错误的分支
场景:将错误的 feature 分支合并到了 main
bash
# 如果还没 push:
git reset --hard ORIG_HEAD # ORIG_HEAD 保存了 merge 前的状态
# 或
git reset --hard HEAD~1
# 如果已 push(需要 revert 合并提交):
git log --oneline --merges -5
# abc123 Merge branch 'wrong-feature'
git revert -m 1 abc123 # -m 1 保留 main 侧的代码
git pushrevert 合并后无法再次合并
场景:revert 了合并提交后,bug 修复好了,但再次合并 feature 分支时,旧提交内容没有被引入
bash
# 问题原因:Git 认为 feature 的旧提交已被合并
# 解决方案:
# 方案1:revert the revert
git switch main
git revert <revert-commit-sha> # 撤销上次的 revert
git merge feature/bug-fixed # 现在可以合并新的改动
# 方案2:在 feature 分支上 rebase(推荐)
git switch feature/bug-fixed
git rebase main # 重建提交,新 SHA-1 避免"已合并"问题
git switch main
git merge feature/bug-fixed误执行 reset --hard
场景:不小心执行了 git reset --hard,丢失了未提交的改动
bash
# 坏消息:工作区改动(未提交)无法恢复!
# 如果是已提交的内容,可以通过 reflog 恢复
# 通过 reflog 找回
git reflog
# abc123 HEAD@{0}: reset: moving to HEAD~3 ← 误操作
# def456 HEAD@{1}: commit: 重要功能 ← 要恢复的位置
git reset --hard def456
# 或
git reset --hard HEAD@{1}预防措施:
bash
# 危险操作前先创建备份分支
git branch backup-before-reset
# 然后再执行 reset
# 如果有临时改动不想丢失,先 stash
git stash
git reset --hard HEAD~3
git stash pop误删分支
场景:删除了还有用的分支
bash
# 通过 reflog 找到分支最后的提交
git reflog | grep "feature/important"
# abc123 HEAD@{5}: checkout: moving from feature/important to main
# 重建分支
git branch feature/important abc123
git switch feature/important推送了敏感信息
场景:误将密码、API Key 等敏感信息推送到远程仓库
立即行动(按优先级):
- 立即吊销泄露的凭证(最重要!不要等 Git 操作完成)
bash
# 吊销 API Key、更换密码等
# 这是第一优先级,不管是否能从 Git 历史中删除- 从历史中删除敏感信息
bash
# 使用 git-filter-repo(推荐)
pip install git-filter-repo
# 替换敏感字符串
cat > replacements.txt << 'EOF'
my_secret_api_key==>REDACTED_API_KEY
my_db_password==>REDACTED_PASSWORD
EOF
git filter-repo --replace-text replacements.txt
# 或者删除包含敏感信息的文件
git filter-repo --path config/secrets.json --invert-paths- 强制推送
bash
git push origin --force --all
git push origin --force --tags- 通知所有协作者重新克隆
bash
# 历史已被重写,所有人必须重新克隆
rm -rf old-repo
git clone <url> new-repo- 请求 GitHub/GitLab 清除缓存(联系支持团队)
预防措施:
bash
# 使用 pre-commit 钩子检测敏感信息
# 工具:git-secrets, gitleaks, trufflehog
# 安装 gitleaks
brew install gitleaks
# 扫描当前仓库
gitleaks detect
# 作为 pre-commit 钩子
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
gitleaks protect --staged --redact -v
EOF
chmod +x .git/hooks/pre-commit仓库损坏的修复
场景:仓库出现损坏(如断电、磁盘错误)
bash
# 检查仓库完整性
git fsck
git fsck --full
# 常见错误及处理:
# "object file is empty":空对象文件
find .git/objects -size 0 -delete # 删除空对象文件
git fsck # 再次检查
# "loose object is corrupt":对象损坏
# 尝试从远程恢复
git fetch origin --all
# 极端情况:克隆到新目录
cd ..
git clone <remote-url> repo-recovered
# 如果有未推送的提交,尝试恢复
# 1. 找到未损坏的提交
git fsck --unreachable 2>&1 | grep "dangling commit"
# 2. 检出并恢复
git cat-file -p <commit-sha>force push 导致同事代码丢失
场景:force push 覆盖了同事已推送但你还没拉取的提交
bash
# 从同事那里获取丢失的提交 SHA-1
# 让同事运行:git reflog | head -20
# 在你的仓库中获取那些 SHA-1
git fetch origin
# 如果已被覆盖,让同事推送到临时分支
git push origin def456:refs/heads/rescue-branch
# 你获取并合并
git fetch origin rescue-branch
git merge origin/rescue-branch
# 之后正确推送
git push --force-with-lease origin main
# 预防措施:
# 1. 始终使用 --force-with-lease 而不是 --force
# 2. 不要对共享分支(main、develop)进行 force push
# 3. 在 force push 前通知团队误将大文件提交
场景:不小心提交了大文件(如视频、压缩包)
bash
# 如果刚刚提交,还没 push:
git reset --soft HEAD~1 # 撤销提交,保留改动
rm large-file.mp4 # 删除大文件
echo "*.mp4" >> .gitignore # 加入 .gitignore
git add .gitignore
git commit -m "chore: 添加大文件到 .gitignore"
# 如果已经 push,需要清理历史(参考仓库瘦身章节)
git filter-repo --path large-file.mp4 --invert-paths
git push --force --all紧急修复:无法访问某个提交
bash
# 通过各种方式找到提交
git log --all --oneline # 所有分支的历史
git reflog --all # 所有引用的操作历史
git fsck --unreachable # 不可达对象(孤立提交)
# 找到后创建分支保存
git branch rescue abc123
# 如果需要合并到当前分支
git cherry-pick abc123快速参考
| 事故 | 解决命令 |
|---|---|
| 提交到错误分支 | git reset HEAD~1 + 在正确分支 cherry-pick |
| 合并错误分支(未 push) | git reset --hard ORIG_HEAD |
| 合并错误分支(已 push) | git revert -m 1 <merge-sha> |
| 误 reset --hard | git reflog + git reset --hard HEAD@{n} |
| 误删分支 | git branch <name> <sha> |
| 推送敏感信息 | 立即吊销凭证 + git-filter-repo + force push |
| 仓库损坏 | git fsck + 从远程恢复 |
| 丢失提交 | git reflog + git branch rescue <sha> |