在Git仓库中查找并恢复已删除文件的方法
技术背景
在使用Git进行版本控制时,有时会不小心删除文件,或者在某些提交中误删了文件。Git提供了多种方法来查找并恢复这些已删除的文件,以确保数据的完整性和项目的正常进行。
实现步骤
1. 查找删除文件的提交
可以使用以下命令找到最后一个影响给定文件路径的提交,由于该文件不在HEAD提交中,那么前一个提交必定是删除它的提交:
1
| git rev-list -n 1 HEAD -- <file_path>
|
2. 恢复文件
方法一:使用^
符号
1
| git checkout <deleting_commit>^ -- <file_path>
|
或者使用单行命令:
1
| git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"
|
如果使用zsh且启用了EXTENDED_GLOB
选项,^
符号可能无法工作,可以使用~1
代替:
1
| git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"
|
方法二:通过git log
查看删除文件的提交
1
| git log --diff-filter=D --summary
|
记录所需的提交哈希,例如e4e6d4d5e5c59c69f3bd7be2
,然后从该提交的前一个提交(~1
)恢复删除的文件:
1
| git checkout e4e6d4d5e5c59c69f3bd7be2~1 path/to/file.ext
|
方法三:恢复文件夹中所有删除的文件
1
| git ls-files -d | xargs git checkout --
|
方法四:恢复最新HEAD提交中存在的已删除文件
1
| git checkout HEAD -- path/to/file.ext
|
方法五:使用git-bisect
1 2 3 4
| git bisect start git bisect bad git bisect good <some commit where you know the file existed> git bisect run '[ -e foo.bar ]'
|
找到删除文件的提交后,可以使用git-revert
撤销更改:
1 2
| git bisect reset git revert <the offending commit>
|
或者回退一个提交并手动检查:
1 2 3 4
| git checkout HEAD^ cp foo.bar /tmp git bisect reset cp /tmp/foo.bar .
|
方法六:使用别名
可以设置别名来简化恢复操作,例如:
1
| git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- $1)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- $1)~1 | grep '^D' | cut -f 2); }; f'
|
使用时:
1
| git restore my_deleted_file
|
方法七:使用GUI工具(如WebStorm)
在WebStorm中,右键单击包含已删除文件的路径,选择Git -> Show History,在历史记录中找到删除文件的提交,双击文件名即可恢复。
方法八:结合coreutils工具
1 2
| git log --raw | grep -B 30 $'D\t.*deleted_file.c' git checkout <rev>^ -- path/to/refound/deleted_file.c
|
方法九:恢复特定提交中删除的多个文件
1 2
| git show <rev> --diff-filter=D --summary --name-only --no-commit-id | xargs git checkout <rev>^ -- git show <rev> --diff-filter=D --summary --name-only --no-commit-id | xargs git reset HEAD
|
方法十:处理悬空提交
1 2
| git fsck --lost-found git reset --hard <commit id>
|
方法十一:使用git restore
命令(Git 2.23及以上)
1 2
| git log --diff-filter=D --oneline -- path/to/file | cut -f -d ' ' git restore --source=4711174^ path/to/file
|
3. 不同场景下的恢复方法
文件/文件夹从工作树中删除但尚未提交
- 如果尚未对更改进行索引(
git add
),可以恢复目录内容:
1
| git restore -- path/to/folder_OR_file
|
1
| git reset -- path/to/folder_OR_file
|
然后执行:
1
| git restore path/to/folder_OR_file
|
文件/文件夹在过去的某个提交中被删除
- 使用
git log --diff-filter=D --summary
获取文件/文件夹被删除的提交详细信息; - 使用
git checkout $commit~1 path/to/folder_OR_file
恢复删除的文件/文件夹,其中$commit
是在步骤1中找到的提交的sha值。
核心代码
以下是一些核心代码示例:
1 2 3 4 5 6 7 8
| # 查找删除文件的提交 git rev-list -n 1 HEAD -- <file_path> # 恢复文件 git checkout <deleting_commit>^ -- <file_path> # 恢复文件夹中所有删除的文件 git ls-files -d | xargs git checkout -- # 恢复最新HEAD提交中存在的已删除文件 git checkout HEAD -- path/to/file.ext
|
最佳实践
- 定期备份重要文件和提交记录,以防止数据丢失。
- 在进行重要操作前,先创建一个新的分支,以便在出现问题时可以轻松回滚。
- 使用别名来简化常用的恢复命令,提高工作效率。
常见问题
1. ^
符号在zsh中无法工作怎么办?
如果使用zsh且启用了EXTENDED_GLOB
选项,^
符号可能无法工作,可以使用~1
代替。
2. git restore
命令是实验性的,是否可以放心使用?
git restore
命令在Git 2.23及以上版本中是实验性的,虽然可以使用,但在重要项目中建议先在测试环境中进行验证。
3. 如果文件被删除后又进行了多次提交,是否还能恢复?
可以恢复,只要通过git log
等命令找到删除文件的提交,然后从该提交的前一个提交恢复文件即可。