使用Git恢复带有历史记录的已删除文件

24
如何在 git 中恢复意外删除的文件和文件夹,以下是情景:
  1. 不小心删除了一个文件夹,其中有一个文件,同时还对其他文件进行了一系列更改。
  2. 现在,将所有更改推送到主仓库。 所以此次推送中包含已删除的文件夹和其他更改后的文件。
  3. 此后又进行了几次推送。
现在,我能否恢复已删除的文件并保留其历史记录,然后将其重新推送到仓库中?

1
Git没有“文件历史”。Git有“提交历史”。恢复文件后,您的历史记录会显示“提交K删除了一些文件,稍后提交R生成了与之前相同名称和相同内容的新文件。”这是最接近的。使用下面Ryan的答案来找回文件。 - torek
如果您没有使用git删除它们,您可以重置您的工作区来获取它们。您确定它们被删除了吗? - osowskit
@osowskit 你说的 "if you did not use git to remove" 是什么意思?我的问题本身是 "如果我删除了文件并推送了被删除的文件,如何恢复?" - Venu
谢谢。我建议包括您使用的git命令,以澄清这不仅仅是在客户端上删除。我会还原提交以避免重写历史记录。 - osowskit
4个回答

18

通过Git复制文件保留历史记录的帮助,您需要在文件被删除之前复制该文件。

我将在此处写一个完整的示例。首先,我将准备一些测试存储库:

git init
echo "test content" > file.txt
git add file.txt
git commit -m "start"
echo "test content 2" >> file.txt
git commit -am "next commit"
rm file.txt
git commit -am "Delete file, lose history"

现在我们有一个没有该文件的测试存储库。恢复带有提交历史记录的文件的过程如下:创建一个存在该文件的分支。然后制作两个拥有历史记录的该文件副本。然后合并回主分支,只会有其中一个副本在合并时被删除。

请确保在以下示例中使用您自己的提交哈希而不是190112b

git checkout 190112b -b before-deletion
git mv file.txt file1.txt
git commit -m "Move file (1)"
SAVED=`git rev-parse HEAD`
git reset --hard "HEAD^"
git mv file.txt file2.txt
git commit -m "Move file (2)"
git merge $SAVED
git commit -a -n

好的,现在在这个分支中我们有两个文件的副本。每个副本都保留了历史记录。现在当我们将其合并回主分支时,一个文件将消失(或将有错误的历史记录),另一个文件将保留历史记录。

git checkout master
git merge before-deletion
git commit -a -n
git rm file1.txt
git mv file2.txt file.txt
git commit -m "recovery finished"

就是这样。


@RodrigoElias 很高兴听到这个消息! :) - Janek_Kozicki
它出现在几个地方:第二个块 git merge $SAVED。我得到了一个 CONFLICT (rename/rename): Rename "file.txt"->"file2.txt" in branch "HEAD" rename "file.txt"->"file1.txt" in " ...。我使用的是 git 2.7.4。 - Richard
运行得很好。我只是忽略了警告。谢谢! - buzztr
你能在每个git命令之前添加注释吗?我不知道这个例子的具体情况和应该改变什么。例如,如果删除文件的提交不是HEAD之前的提交呢? - Alechan
尝试了许多不同的方法后,最终这个解决方案成功地恢复了历史记录。感谢分享。 - Ali Azhar
显示剩余3条评论

16

当然,只需从包含该文件的提交中查找它。如果删除该文件的提交是您当前已检出的任何内容的最新提交,则为 HEAD^(上次提交):

git checkout HEAD^ -- path/to/file

然后您可以提交并推送它。


3
你可以用提交的SHA值替换HEAD^,这也可以起作用。 - Peter Reid
11
我尝试过了,但它并没有为我恢复历史记录。 - waynix
4
@Ry-:我已经拿回了文件,但是历史记录丢失了。但是当我在文件上执行git blame时,我只能看到我的名字,而看不到原始提交者的名字。 - waynix
4
这对我来说没有保留历史记录;我只看到文件历史记录中的最新提交。顺便说一下,我是使用提交哈希检出的。 - aggregate1166877
1
这对我没有保留历史记录。 - OSGI Java
显示剩余4条评论

7

遇到了类似的情况,将可能的解决方法粘贴在这里。
之前有一个文件被删除了,现在我需要恢复它。
步骤如下:1. 定位删除该文件的提交记录 2. 从该提交记录中恢复该文件。

  1. git log --all --stat --diff-filter=D -- test.log(假设文件名为test.log)
  2. git restore --source aec723390^ test.log(假设第一步的输出结果是 "aec723390",注意 ^ 符号)

这与手动重新创建完全相同的文件有什么不同吗?根据这个描述,在git restore之后,文件仍然是未跟踪的,可以假设与从备份中将文件复制到目录中的情况相同。额外的历史跟踪是从哪里来的?git restore是否提供了一些额外的历史跟踪功能,而仅仅从头开始重新创建文件则没有? - undefined

-1
假设您当前在主分支上,一个简单的解决方案是找到您想要删除的文件的最后提交的GIT SHA1(使用类似gitk的工具有助于此)。
运行以下命令:
git checkout <GIT SHA1 value>

将文件内容复制到记事本(或任何文本编辑器)中

运行命令

git checkout master

使用记事本的内容重新创建文件


1
这会同时恢复文件的历史记录吗? - Venu
是的,假设文件与相同名称位于相同位置,则应该这样。 - ted-k42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接