在Git存储库中查找并恢复已删除的文件


2802

假设我在Git存储库中。我删除一个文件并提交更改。我继续工作并做出更多承诺。然后,我发现需要还原该文件。

我知道我可以使用检出文件git checkout HEAD^ foo.bar,但我真的不知道何时删除该文件。

  1. 找到删除给定文件名的提交的最快方法是什么?
  2. 将文件恢复到我的工作副本中最简单的方法是什么?

我希望我不必手动浏览日志,为给定的SHA签出整个项目,然后手动将该文件复制到我的原始项目签出中。


39
请注意,前面的注释回答的是标题中的问题,而不是正文中的问题-包括找出何时删除文件。
avdgaag 2011年

8
为了找到一个提交文件被删除中:git log --diff-filter=D -- path/to/file
titaniumdecoy



54
如果已删除@hhh,但该删除尚未进行或提交,它将取消git checkout deletedFile删除。这不是这里要问的问题;这个问题是关于如何恢复一个其删除操作已多次提交的文件。deletedFile
马克·阿默里

Answers:


3149

查找影响给定路径的最后一次提交。由于该文件不在HEAD提交中,因此此提交必须已将其删除。

git rev-list -n 1 HEAD -- <file_path>

然后,使用caret(^)符号在提交之前检出版本:

git checkout <deleting_commit>^ -- <file_path>

或者在一个命令中,如果$file有问题的文件。

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

如果您正在使用zsh并启用了EXTENDED_GLOB选项,则插入符号将不起作用。您可以~1改用。

git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"

94
棘手的是使用^后缀检出提交。谢谢。
Christian Oudard 2010年

4
出于某种原因,这在zsh中不起作用。 ± git checkout $(git rev-list -n 1 HEAD "spec/Sporkfile_example.rb")^ -- "spec/Sporkfile_example.rb" zsh: no matches found: b71c152d8f38dcd23ad7600a93f261a7252c59e9^ 我改用bash,但效果很好。
zoras

20
从Windows命令行我得到了一个错误。error: pathspec <filename> did not match any file(s) known to git.。解决的办法是使用git bash。
donturner 2012年

56
我相信@zoras zsh在'^'上有自己的扩展名,但是您可以使用'〜1'的替代语法:〜X git checkout <deleting-commit>~1 -- <file-path> 允许您在指定的提交之前指定X个提交,因此〜1是之前的提交,〜2是之前的两次提交,等等
Nils Luxton 2012年

22
在Windows cmd提示符下,该^字符为转义字符!因此,在cmd上,您必须键入^^命令告诉cmd您需要单个文字^,并且不要在其后转义其他内容。对许多人来说,发生的^是空格后面是空格。因此,cmd认为您正在转义空格-这只会产生空格字符。因此,当git获得cli参数时,它看到SHA1不是 SHA1^。真烦人。~不是逃脱字符,所以这仍然有效。(PS。如果您认为Google员工会需要此信息,请对此评论进行投票)
Alexander Bird

875
  1. 使用git log --diff-filter=D --summary得到所有已删除的文件和文件删除了提交;
  2. 使用git checkout $commit~1 path/to/file.ext恢复删除的文件。

$commit您在步骤1中找到的提交值在哪里?例如e4cf499627


10
很好奇,〜1是什么意思?
tommy heng

7
@tommy-代字号将为您提供命名提交的第n个孙代。有关更多详细信息,请参见book.git-scm.com/4_git_treeishes.html
罗伯特·蒙提亚努

5
到目前为止,这是最简单直观的方法。git log -- *PartOfMyFileName*。感谢$commit~1
bgs 2013年

3
git checkout $commit~1 filename语法非常适合单个文件,也适用于整个目录。即:从sha 12345恢复./images中所有已删除的图像:git checkout 12345~1 images。感谢您的回答!
noinput 2014年

34
@Alexar $commit~1意味着您应该添加提交的名称。像1d0c9ef6eb4e39488490543570c31c2ff594426c在哪里$commit
尤金(Eugene)2015年

319

要恢复文件夹中所有已删除的文件,请输入以下命令。

git ls-files -d | xargs git checkout --

1
文件从哪里传送到哪里?我没看到变化。
William Grand

21
这可能是最简单的方法。它变本加厉git,甚至使最简单的任务变得多么困难。
jww

git checkout-[file]将还原[file]中的更改。管道将[file]替换为已删除文件的名称。
Manu 2015年

6
ls-files子命令是很方便,但似乎并没有工作与已删除的文件git rm即上演,更不用说承诺,这是什么OP问。
MarkHu '17

这适用于还原已删除的文件,但是如何更新已更改的文件并显示在 M myChangedFile之后git checkout
libby

124

我遇到了这个问题,希望还原刚刚删除但尚未提交更改的文件。万一您发现自己处于这种情况下,您需要做的只是以下几点:

git checkout HEAD -- path/to/file.ext


93

如果您疯了,请使用git-bisect。这是做什么的:

git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>

现在该运行自动化测试了。'[ -e foo.bar ]'如果foo.bar存在,则shell命令将返回0 ,否则返回1。的“运行”命令git-bisect将使用二进制搜索来自动找到测试失败的第一个提交。它从给定范围的一半开始(从好到坏),并根据指定测试的结果将其切成两半。

git bisect run '[ -e foo.bar ]'

现在您处于删除它的提交。从这里,您可以跳回到未来,并用于git-revert撤消更改,

git bisect reset
git revert <the offending commit>

或者您可以返回一次提交并手动检查损坏:

git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .

2
你能详细说明git bisect run '[ -e foo.bar ]'吗?
avdgaag

如果不能自动检查好坏,也可以手动使用。请参见bisect手册页。
乔希·李

1
@avdgaag的git bisect run告诉Git的运行以下单词“跑”,其中的命令必须返回指令自动平分0good版本(见git help bisect详情)。这'[ -e foo.bar ]'是一个标准表达式,用于测试文件foo.bar是否确实存在(该实现通常在文件中/usr/bin/[,通常是硬链接到/usr/bin/test),并且使用单引号将所有内容都作为单个命令行参数。
Mikko Rantalainen

好点子。我尝试了这种方法,并在删除之前确定了提交,但没有实际删除文件的提交。在另一项测试中,它在删除之前确定了2次提交。
Michael Osofsky '19

疯?也许。但是bisect是帮助查找错误所在的好方法,因此无论如何它都是一种宝贵的技能。因此,尽管此处可能不是“正确”或最“正确”的方式,但这仍然是一个好主意,绝对值得+1!
Pryftan

77

基于bonyiii答案(已投票)和我自己有关“ 将参数传递给Git别名命令 ” 的答案,我得到了我最喜欢的别名:

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'

我丢失了一个文件,在几次提交之前被误删除了?
快:

git restore my_deleted_file

避免危机。

警告,带有Git 2.23(2019年第三季度)的实验命令名为git restore(!)。
因此,重命名此别名(如下所示)。


Robert Dailey 在评论中建议使用以下别名:

restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"

jegan增加的评论

为了从命令行设置别名,我使用了以下命令:

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 

7
这将恢复整个提交,而不仅仅是请求的文件。
丹尼尔·邦

5
这是我的别名,效果非常好:restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"
void.pointer 2014年

1
@RobertDailey看起来很棒!我在答案中包括了您的别名,以提高可见性。
VonC 2014年

1
为了从命令行设置别名,我使用了以下命令:git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\""
jegan

2
Expansion of alias 'restore' failed; '!git' is not a git command
莫里森

54

如果知道文件名,这是使用基本命令的简单方法:

列出该文件的所有提交。

git log -- path/to/file

最后一个提交(最顶部)是删除文件的提交。因此,您需要还原倒数第二个提交。

git checkout {second to last commit} -- path/to/file

只是使用了此解决方案,所以没有提交删除操作。但是,我能够使用最新的提交ID还原文件。
亚当

倒数第二个提交(删除的先前提交)是否不包含已删除文件的最新版本?倒数第二(上一次提交删除之前的提交)可能已经过时了。
Suncat2000

1
这是我所见过的第一个解决方案,它非常简单,因此我下次不必再回到这里找到它。也许。
Eloff '18 -4-3

@ Suncat2000“倒数第二个”表示“先前提交的删除”,与“倒数第二个”相同。en.wiktionary.org/wiki/penultimate#Synonyms
wisbucky

感谢无数次的回答!
Rakesh Bk

29

要恢复已删除并提交的文件:

git reset HEAD some/path
git checkout -- some/path

它已在Git 1.7.5.4版上进行了测试。


1
那对我没用。结帐后,我error: pathspec 'foo' did not match any file(s) known to git.确定文件名正确。Git版本2.7.0
wisbucky

-1; 这是错误的。这些命令将撤消尚未提交的删除操作(第一个取消取消删除(如果已暂存),第二个命令放弃未暂存的对文件的更改),但是您在这里声称它们将还原已提交的内容。删除文件,这根本不是真的,并且会失败,并出现类似@wisbucky上面的注释中的错误。
马克·阿默里

@MarkAmery的确,我认为该命令对那些开发人员没有很好的作用,他们并没有为使用提交已删除的文件进行明确的登台git add -A,但是恢复的文件仍处于未提交阶段。
Fedir RYKHTIK

25

如果您仅进行更改并删除了文件但不提交,那么现在您分手了更改

git checkout -- .

但是删除的文件没有返回,您只需执行以下命令:

git checkout <file_path>

而且,您的文件又回来了。


24

我有这个解决方案

  1. 使用以下方法之一获取删除文件的提交ID。

    • git log --grep=*word*
    • git log -Sword
    • git log | grep --context=5 *word*
    • git log --stat | grep --context=5 *word* #建议,如果您几乎什么都不记得了
  2. 您应该得到类似以下内容:

提交bfe68bd117e1091c96d2976c99b3bcc8310bebe7作者:Alexander Orlov日期:2011年5月12日星期四23:44:27 +0200

replaced deprecated GWT class
- gwtI18nKeySync.sh, an outdated (?, replaced by a Maven goal) I18n generation script

提交3ea4e3af253ac6fd1691ff6bb89c964f54802302作者:Alexander Orlov日期:2011年5月12日星期四22:10:22 +0200

3。现在使用提交ID bfe68bd117e1091c96d2976c99b3bcc8310bebe7做:

git checkout bfe68bd117e1091c96d2976c99b3bcc8310bebe7^1 yourDeletedFile.java

由于提交ID引用了已删除文件的提交,因此您需要在bfe68b之前引用该提交,您可以通过附加来进行引用^1。这意味着:在bfe68b之前给我提交。


这与接受的答案是相同的方法,但是还有更多查找删除提交的方法。我仍然喜欢已接受答案中的方法,但是这些是不错的选择。谢谢!
avdgaag 2012年

我假设首先签出已删除的文件,然后(不进行更改)提交该文件不会创建该文件的副本。对?(我需要对图像进行此操作,而副本将使存储库更大)
Stonecrusher


12

git undelete path/to/file.ext

  1. 将其放入您的.bash_profile(或打开命令shell时加载的其他相关文件)中:

    git config --global alias.undelete '!sh -c "git checkout $(git rev-list -n 1 HEAD -- $1)^ -- $1" -'
    
  2. 然后使用:

    git undelete path/to/file.ext
    

该别名首先检查以找到该文件存在的最后提交,然后从该文件存在的最后提交进行Git签出该文件路径。来源


11

在许多情况下,将coreutils(grep,sed等)与Git结合使用可能会很有用。我已经很好地了解了这些工具,但是Git不太了解。如果要搜索已删除的文件,请执行以下操作:

git log --raw | grep -B 30 $'D\t.*deleted_file.c'

当我找到修订/提交时:

git checkout <rev>^ -- path/to/refound/deleted_file.c

就像其他人在我面前说过的一样。

现在,文件将恢复到删除前的状态。如果要保留它,请记住将其重新提交到工作树中。


7

我必须从特定的提交中还原一堆已删除的文件,并使用两个命令对其进行管理:

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 

(请注意每个命令末尾的空格。)

这些文件已添加到.gitignore文件,然后使用清除git rm。我需要还原文件,但是要取消登台。我有数百个要还原的文件,并且像在其他示例中那样手动为每个文件键入内容太慢了。


7

实际上,这个问题直接与Git有关,但是像我这样的人正在使用WebStorm VCS等GUI工具除了了解Git CLI命令外。

我右键单击包含已删除文件的路径,然后转到Git,然后单击“ 显示历史记录”

在此处输入图片说明

VCS工具显示了所有修订版本,我可以看到每个修订的所有提交和更改。

在此处输入图片说明

然后,选择我的朋友删除该PostAd.js文件的提交。现在看下面:

在此处输入图片说明

现在,我可以看到我想要删除的文件。我只需双击文件名即可恢复。

在此处输入图片说明

我知道我的答案不是Git命令,但是对于初学者和专业开发人员来说,它是快速,可靠且容易的。WebStorm VCS工具非常棒,非常适合使用Git,并且不需要任何其他插件或工具。


1
这太棒了!谢谢。对于使用JetBrains的任何IDE的人来说,绝对是一个更简单的解决方案。
法比亚诺·阿鲁达

如果文件是图像,我们如何还原?
Nodirabegimxonoyim

亲爱的@ FabianoArruda,JetBrains IDE是强大的开发工具。感谢您的可爱评论。
AmerllicA

感谢您,亲爱的@PeterMortensen版。
AmerllicA

6

我有同样的问题。不知不觉中,我创建了一个悬空的提交

列出悬空提交

git fsck --lost-found

检查每个悬空的提交

git reset --hard <commit id>

当我移至悬空提交时,我的文件重新出现。

git status 由于这个原因:

“HEAD detached from <commit id where it detached>”


2
非常感谢你。您帮助我恢复了数千行代码。
Reuben

5
user@bsd:~/work/git$ rm slides.tex
user@bsd:~/work/git$ git pull 
Already up-to-date.
user@bsd:~/work/git$ ls slides.tex
ls: slides.tex: No such file or directory

恢复已删除的文件:

user@bsd:~/work/git$ git checkout
D       .slides.tex.swp
D       slides.tex
user@bsd:~/work/git$ git checkout slides.tex 
user@bsd:~/work/git$ ls slides.tex
slides.tex

2
问题是关于在删除文件并提交更改后还原文件。该答案是关于还原仅在工作目录中删除的文件的。
akaihola

没错,这就是我想要的。
Hola Soy Edu Feliz Navidad 2014年

4

如果您知道删除文件的提交,请运行以下命令,其中<SHA1_deletion>删除文件的提交在哪里:

git diff --diff-filter=D --name-only <SHA1_deletion>~1 <SHA1_deletion> | xargs git checkout <SHA1_deletion>~1 --

管道之前的部分列出了在提交中删除的所有文件;它们都是从上一次提交中检出以还原它们。


4

查找删除您的文件的提交:

git log --diff-filter=D --oneline -- path/to/file | cut -f -d ' '

样本输出:

4711174

从Git 2.23开始,实际上有一个restore命令。它仍处于试验阶段,但是为了恢复在提交中删除的内容(在这种情况下为4711174),可以键入:

git restore --source=4711174^ path/to/file

请注意提交ID后的^,因为我们想从提交之前还原某些内容删除文件的。

--source参数告诉restore命令在哪里寻找要还原的文件,它可以是任何提交,甚至是索引。

请参阅:git-restore doc for git 2.23.0


4

在我们的案例中,我们不小心删除了提交中的文件,而在某些提交之后,我们意识到了自己的错误,并希望找回所有已删除的文件,而不是找回那些已修改的文件。

基于Charles Bailey的出色回答,这是我的一句话:

git co $(git rev-list -n 1 HEAD -- <file_path>)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- <file_path>)~1 head | grep '^D' | cut -f 2)

2

简单而精确-

首先,通过-获得最新的稳定提交,其中包含该文件-

git log 

假设您找到$ commitid 1234567 ...,然后

git checkout <$commitid> $fileName

这将还原该提交中的文件版本。


1

为做到这一点的最佳方法,请尝试一下。


首先,找到删除文件的提交的提交ID。它将为您提供有关已删除文件的提交的摘要。

git log --diff-filter = D-摘要

git checkout 84sdhfddbdddf〜1

注意:84sdhfddbddd是你的commit id

通过此操作,您可以轻松恢复所有已删除的文件。


1

您可以随时git revert删除文件。(这假定删除是提交中的唯一更改。

> git log
commit 2994bda49cd97ce49099953fc3f76f7d3c35d1d3
Author: Dave <dave@domain.com>
Date:   Thu May 9 11:11:06 2019 -0700

    deleted readme.md

而且,如果您继续工作,后来又意识到您不想提交该删除提交,则可以使用以下命令还原它:

> git revert 2994bd

现在git log显示:

> git log
Author: Dave <dave@domain.com>
Date:   Thu May 9 11:17:41 2019 -0700

    Revert "deleted readme"

    This reverts commit 2994bda49cd97ce49099953fc3f76f7d3c35d1d3.

readme.md已还原到存储库中。


由于该问题假定在删除文件后进行了多次提交,并且由于没有迹象表明随后的提交是不需要的,因此在上述情况下这似乎不太可能对OP有所帮助。
乔纳森·勒夫勒

1
是的 您可以进行后续提交,但仍还原删除提交。因此,如果提交111删除了文件,并且提交
222、333、444进行

0

使用以下代码将以前的文件检索到本地目录时,我也遇到此问题:

git checkout <file path with name>

以下示例为我工作:

git checkout resources/views/usaSchools.blade.php


请提及问题所在
Akbor

删除已提交。在这种情况下,您需要指定要还原的提交。
sba


-1

如果尚未提交删除,则以下命令将在工作树中恢复已删除的文件。

$ git checkout -- <file>

您可以使用以下命令获取工作树中所有已删除文件的列表。

$ git ls-files --deleted

如果删除已提交,请在发生删除的地方找到提交,然后从该提交中恢复文件。

$ git rev-list -n 1 HEAD -- <file>
$ git checkout <commit>^ -- <file>

如果您正在寻找要恢复的文件的路径,以下命令将显示所有已删除文件的摘要。

$ git log --diff-filter=D --summary

-1

为了使用Git恢复所有已删除的文件,您还可以执行以下操作:

git checkout $(git ls-files --deleted)

其中git ls-files --deleted列出所有已删除的文件,并git checkout $(git command)在参数中恢复文件列表。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.