在Git存储库中查找并还原已删除的文件

Find and restore a deleted file in a Git repository

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

我知道我可以使用git checkout HEAD^ foo.bar签出一个文件,但我不知道该文件何时被删除。

  • 找到删除给定文件名的提交的最快方法是什么?
  • 把那个文件放回我的工作副本最简单的方法是什么?
  • 我希望我不必手动浏览我的日志,签出给定sha的整个项目,然后手动将该文件复制到我的原始项目签出中。


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

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

    然后在提交之前签出版本,使用插入符号(^符号:

    1
    git checkout <deleting_commit>^ -- <file_path>

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

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

    如果您使用的是zsh并启用了扩展的_glob选项,插入符号将无法工作。你可以用~1代替。

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


  • 使用git log --diff-filter=D --summary获取所有删除文件的承诺和删除文件的承诺;
  • 使用git checkout $commit~1 path/to/file.ext恢复删除的文件。
  • 其中,$commit是您在步骤1中发现的承诺值,例如e4cf499627


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

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


    我来这个问题是想恢复一个刚删除的文件,但我还没有提交更改。如果你发现自己处于这种情况,你需要做的就是:

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


    如果你疯了,用git-bisect。以下是要做的:

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

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

    1
    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 .


    我最喜欢的新别名,基于Bonyiii的回答(上票),以及我自己关于"将参数传递给git alias命令"的回答:

    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

    避免危机。

    罗伯特·戴利在评论中提出了以下别名:

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

    杰根在评论中补充道:

    For setting the alias from the command line, I used this command:

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


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

    列出该文件的所有提交。

    1
    git log -- path/to/file

    最后一次提交(最顶部)是删除文件的提交。所以您需要恢复第二次提交到最后一次提交。

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


    要还原已删除并提交的文件,请执行以下操作:

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

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


    如果您只做了更改并删除了一个文件,但没有提交,现在您就放弃了更改。

    1
    git checkout -- .

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

    1
    git checkout <file_path>

    普雷斯托,你的文件回来了。


    我有这个解决方案。

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

    • git log --grep=*word*
    • git log -Sword
    • git log | grep --context=5 *word*
    • git log --stat | grep --context=5 *word*建议如果你很难记住任何事
  • 你应该得到如下信息:

  • commit bfe68bd117e1091c96d2976c99b3bcc8310bebe7 Author: Alexander
    Orlov Date: Thu May 12 23:44:27 2011
    +0200

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

    commit 3ea4e3af253ac6fd1691ff6bb89c964f54802302 Author: Alexander
    Orlov Date: Thu May 12 22:10:22 2011
    +0200

    三。现在,使用提交ID bfe68bd17e1091c96d296c99b3bcc8310be7执行以下操作:

    1
    git checkout bfe68bd117e1091c96d2976c99b3bcc8310bebe7^1 yourDeletedFile.java

    由于commit id引用的是已删除文件的commit,因此您需要在bfe68b之前引用commit,您可以通过追加^1来完成。这意味着:在bfe68b之前给我承诺。


    1
    git checkout /path/to/deleted.file


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

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

    当我找到修订/提交时:

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

    就像别人在我面前说的那样。

    文件现在将恢复到删除前的状态。如果你想让它一直存在,记得把它重新提交到工作树上。


    git undelete path/to/file.ext

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

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

    1
    git undelete path/to/file.ext
  • 此别名首先检查以查找该文件存在的最后一次提交,然后从该文件存在的最后一次提交中对该文件路径执行git签出。来源


    所以我必须从一个特定的提交中恢复一堆已删除的文件,并用两个命令管理它:

    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

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

    这些文件已经添加到.gitignore文件中,然后用git rm清除,我需要还原这些文件,但随后将其取消存储。我有数百个文件要恢复,手动为每个文件键入内容,在其他示例中,速度太慢了。


    实际上,这个问题直接与Git有关,但像我这样的人使用的是诸如WebStormVCS之类的GUI工具,而不是了解git cli命令。

    我右键单击包含已删除文件的路径,然后转到Git,然后单击Show History

    enter image description here

    VCS工具显示所有的修订,我可以看到它们的所有提交和更改。

    enter image description here

    然后我选择我的朋友删除PostAd.js文件的承诺。现在见下面:

    enter image description here

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

    enter image description here

    我知道我的答案不是Git命令,但对于初学者和专业开发人员来说,它是快速、可靠和容易的。webstorm vcs工具非常棒,非常适合与Git一起工作,不需要任何其他插件或工具。


    1
    2
    3
    4
    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

    还原已删除的文件:

    1
    2
    3
    4
    5
    6
    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


    我也有同样的问题。在不知道的情况下,我创造了一个悬而未决的承诺。

    列出悬而未决的承诺

    git fsck --lost-found

    检查每个悬空任务

    git reset --hard

    当我转到悬而未决的任务时,我的文件又出现了。

    git status原因:

    "HEAD detached from "


    如果知道删除文件的提交,请运行此命令,其中是删除文件的提交:

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

    管道前面的部分列出了在提交中删除的所有文件;它们都是从上一次提交中签出以恢复它们。


    在我们的例子中,我们不小心在提交时删除了文件,后来又有一些提交,我们意识到了我们的错误,并希望返回所有被删除的文件,但不返回那些被修改的文件。

    根据查尔斯·贝利的绝妙回答,这里是我的一句话:

    1
    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)


    简单而精确-

    首先,获取一个最新的稳定提交,在该提交中-

    1
    git log

    假设你找到$commitid 1234567…,那么

    1
    git checkout <$commitid> $fileName

    这将恢复提交中的文件版本。


    1
    $ git log --diff-filter=D --summary  | grep"delete" | sort