Skip to content

恢复删除

概述

Git 提供了多种机制来恢复误删的提交、分支和文件。理解这些恢复机制可以帮助你在操作失误时挽回损失。

git reflog 查看操作历史

git reflog 是恢复操作的利器,它记录了 HEAD 的所有移动历史。

基本用法

bash
# 查看所有操作历史
git reflog

# 输出示例:
# e5f6g7h (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
# f6g7h8i HEAD@{1}: commit: Add feature C
# g7h8i9j HEAD@{2}: checkout: moving from feature to main
# h8i9j0k (feature) HEAD@{3}: commit: Add feature B
# i9j0k1l HEAD@{4}: checkout: moving from main to feature
# j0k1l2m HEAD@{5}: commit: Add feature A
# k1l2m3n HEAD@{6}: clone: from https://github.com/user/repo.git

查看特定分支的历史

bash
# 查看特定分支的操作历史
git reflog show main

# 查看特定分支的最近 10 条记录
git reflog show main -10

理解 reflog 输出

bash
# 输出格式
# <commit-hash> (<refs>) HEAD@{n}: <action>: <message>

# HEAD@{n} 表示第 n 次操作之前
# HEAD@{0} 是最近一次操作
# HEAD@{1} 是倒数第二次操作

reflog 配置

bash
# 查看默认过期时间
git config gc.reflogExpire
# 默认 90 天

# 查看未可达对象的过期时间
git config gc.reflogExpireUnreachable
# 默认 30 天

# 设置过期时间
git config gc.reflogExpire 180
git config gc.reflogExpireUnreachable 90

恢复已删除的提交

场景:误用 reset --hard

bash
# 1. 误操作
git reset --hard HEAD~3
# 丢失了 3 个提交

# 2. 查看操作历史
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# d4e5f6g HEAD@{1}: commit: Important commit  <-- 这是丢失的提交

# 3. 恢复到误操作前的状态
git reset --hard HEAD@{1}

# 或使用提交哈希
git reset --hard d4e5f6g

场景:误删分支后恢复提交

bash
# 1. 查看所有操作历史
git reflog

# 2. 找到分支删除前的提交
# 例如:e5f6g7h HEAD@{5}: checkout: moving from feature to main

# 3. 恢复提交
git checkout e5f6g7h

# 4. 创建新分支保存
git checkout -b recovered-feature

场景:恢复特定提交

bash
# 查找特定提交
git reflog | grep "commit message"

# 恢复
git cherry-pick <commit-hash>

# 或创建分支
git branch recovered-branch <commit-hash>

恢复已删除的分支

使用 reflog 恢复

bash
# 1. 查看操作历史
git reflog

# 输出示例:
# a1b2c3d HEAD@{0}: checkout: moving from feature to main
# b2c3d4e HEAD@{1}: commit: Last commit on feature  <-- feature 分支最后的提交

# 2. 找到分支最后的提交
# 查找 "moving from <branch-name>" 之前的提交

# 3. 恢复分支
git branch feature b2c3d4e

# 或使用 reflog 引用
git branch feature HEAD@{1}

完整恢复流程

bash
# 假设误删了 feature 分支

# 1. 查看操作历史
git reflog

# 2. 找到分支最后的提交
# 输出:
# abc1234 HEAD@{0}: branch: Deleted feature
# def5678 HEAD@{1}: commit: Feature work  <-- 这是 feature 最后的提交

# 3. 恢复分支
git branch feature def5678

# 4. 验证恢复
git log feature --oneline -5

恢复远程删除的分支

bash
# 如果分支曾经推送到远程

# 1. 查看远程引用
git remote show origin

# 2. 如果远程分支还存在
git fetch origin
git checkout -b feature origin/feature

# 3. 如果远程分支已删除,使用本地 reflog
git reflog
git branch feature <commit-hash>

git fsck 检查仓库

git fsck 用于检查仓库的完整性和一致性。

基本用法

bash
# 检查仓库
git fsck

# 输出示例:
# Checking object directories: 100% (256/256), done.
# Checking objects: 100% (1234/1234), done.

查找悬空对象

bash
# 查找悬空提交
git fsck --lost-found

# 输出示例:
# dangling commit a1b2c3d4e5f6...
# dangling blob b2c3d4e5f6g7...

# 查看悬空提交内容
git show a1b2c3d4e5f6

# 恢复悬空提交
git branch recovered-branch a1b2c3d4e5f6

悬空对象类型

bash
# dangling commit:悬空提交
# dangling blob:悬空文件内容
# dangling tree:悬空目录树

# 查看所有悬空对象
git fsck --unreachable

# 查看特定类型
git fsck --unreachable --no-reflogs

恢复悬空 blob

bash
# 查找悬空 blob
git fsck --lost-found

# 输出:
# dangling blob a1b2c3d4

# 查看内容
git cat-file -p a1b2c3d4

# 恢复到文件
git cat-file -p a1b2c3d4 > recovered-file.txt

恢复场景详解

场景 1:恢复误删的文件

bash
# 方法 1:从最新提交恢复
git checkout HEAD -- deleted-file.txt

# 方法 2:从特定提交恢复
git checkout a1b2c3d -- deleted-file.txt

# 方法 3:使用 restore
git restore --source=HEAD deleted-file.txt

场景 2:恢复误删的提交

bash
# 1. 查看操作历史
git reflog

# 2. 找到提交
# HEAD@{3}: commit: Important work

# 3. 恢复
git reset --hard HEAD@{3}

# 或 cherry-pick
git cherry-pick <commit-hash>

场景 3:恢复被覆盖的分支

bash
# 假设 feature 分支被其他分支覆盖

# 1. 查看 reflog
git reflog show feature

# 2. 恢复到之前的提交
git checkout feature
git reset --hard HEAD@{n}

场景 4:恢复 stash

bash
# 查看所有 stash
git stash list

# 恢复最近的 stash
git stash pop

# 恢复特定 stash
git stash apply stash@{2}

# 如果误删了 stash
git fsck --lost-found
# 查找 dangling commit
git show <commit-hash>
git stash apply <commit-hash>

场景 5:恢复 rebase 丢失的提交

bash
# 1. 查看 reflog
git reflog

# 2. 找到 rebase 前的提交
# HEAD@{5}: rebase finished: ...

# 3. 恢复
git reset --hard HEAD@{5}

预防措施

定期备份

bash
# 创建备份分支
git branch backup-$(date +%Y%m%d)

# 推送到远程
git push origin backup-$(date +%Y%m%d)

# 创建标签
git tag -a v1.0.0-backup -m "Backup before risky operation"

使用标签

bash
# 重要操作前打标签
git tag pre-reset

# 操作后如果需要恢复
git reset --hard pre-reset

保持 reflog

bash
# 不要频繁执行 git gc
# gc 会清理不可达对象

# 延长 reflog 保留时间
git config gc.reflogExpire 365
git config gc.reflogExpireUnreachable 180

安全操作习惯

bash
# 1. 危险操作前检查
git status
git log --oneline -5

# 2. 创建备份分支
git branch backup

# 3. 执行操作
git reset --hard HEAD~3

# 4. 如果出错,恢复
git reset --hard backup
git branch -d backup

恢复工具对比

方法适用场景优点缺点
reflog最近删除的提交/分支快速、简单有时间限制
fsck悬空对象可找回更老的对象需要手动识别
远程仓库已推送的内容可靠需要网络
备份分支主动备份最安全需要提前创建

总结

  • git reflog 记录所有 HEAD 移动历史
  • git fsck 可查找悬空对象
  • 恢复分支需要找到最后的提交
  • 定期备份重要分支和提交
  • 危险操作前创建备份分支

下一步

恭喜你完成了 Git 进阶篇的学习!建议继续学习: