【问题标题】:How to recover from "git rm -rf ." and still retain uncomitted changes?如何从“git rm -rf”中恢复。并且仍然保留未提交的更改?
【发布时间】:2019-06-14 11:59:31
【问题描述】:

git add * 向暂存索引添加了一堆更改,但尚未提交,我想删除它们,撤消添加,所以我git rm -rf . 令我惊讶的是,它把它们从我的硬盘中删除了,我想要一种方法把它们找回来;但是,我已经做出了巨大的改变,我想恢​​复这些改变。

TLDR:我通过git rm -rf . 删除了我的整个项目,我需要一些方法来重置删除,以便我保留未提交的更改并取回我的文件。拜托我太害怕我可能会失去我的整个项目。

回答:我的存储库基本上是一个包含大量内容的网站,根据下面的答案,我制作了 2 个存储库副本,我们称它们为副本 A 和副本 B,对于 A 我做了git reset --hard 回到最新的提交,我找回了我的文件,但丢失了我对它们所做的更改。所以对于副本 B,我做了git fsck --lost-found 并进入了 .git/lost-found/other/ 目录,其中包含我的文件的多个以哈希命名的版本,我一直打开它们,顺便说一句,它们有 60 多个文件,我认识的每个文件我都将其重命名为它的实际名称,然后将它而不是旧版本放在副本 A 中,最后我删除了我的原始存储库,我现在使用副本 A 作为我的网站。就像现在什么都没有发生一样。一个小小的愚蠢错误 => 5 小时的痛苦。不要重复我所做的,永远不要。

现在git status 将我所有的文件都显示为“已删除:”并且它是绿色的。

【问题讨论】:

  • 我觉得你运气不好。如果您输入了rm -rf .,那么您的更改仍然会在Git 的索引中,但是通过使用git rm,磁盘上的索引和工作副本都会更新。但以防万一我错了,在您进行任何实验之前,请复制整个项目目录,包括 .git 目录。
  • 是的,我学得很辛苦,如果你弄乱了 git,git 就会弄乱你。在我参加的任何 git 课程中必须教授的第 1 条规则是,如果您不确定自己在做什么,请复制一份。
  • 进一步思考,可能是以前版本的索引,或者至少其中包含的文件,仍然作为 blob 存在于您的存储库中。希望对此有更多了解的人会加入。
  • Commits 被永久保存(或者至少,只要您仍然可以找到哈希 ID,请参阅 Think Like (a) Git 了解详细信息)。您在索引和工作树中积极处理的内容不会永远保存。

标签: git git-rm


【解决方案1】:

使用

find .git/objects/ -type f -printf "%T+\t%p\n" \
  | sort \
  | sed 's:.*git/objects/\(.*\)/\(.*\):\1\2:' \
  | while read object; do
       echo -n "$object "; 
       git cat-file -t "$object";
    done

您应该获得按时间排序的对象和类型列表。

例如,在测试仓库中:

908553f63e9126f933b690970d41adc3377e3360 blob
31e0d0e213c9976308fbb91c542ced9218fa8f6a tree
5b181f91c49d287b4670fcf3545656dc0c0ef5f4 commit
de683137e0b2d0a40f766307e81999986e4b31c2 blob
086cb344a4fd8a9d671006b8e5844f2437faa3ab tree
930ba9809b5d50410b72c3fbff111d948f1027fa commit
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 blob
40cda8e010466dc7a4a0eb107e7e45804290685e blob

最后两个 blob 是在最后一次提交之后创建的,如果您使用例如打印它们。 git cat-file -p 40cda8e010466dc7a4a0eb107e7e45804290685e,应该可以恢复文件内容了。

您也可以通过这种方式获得一些树(使用git ls-tree <tree-id> 打印它们),但不是顶级树,因为它直接存储在索引中。

【讨论】:

  • 这是目前为止最有用的答案,我会稍微研究一下,让你知道
【解决方案2】:

可能会有希望:您之前添加到索引中的对象可能仍然存在,尽管它们不再被引用。我做了以下测试:

$ git init test
$ cd test
$ echo hello > README.md
$ git add README.md
$ git commit -m"Add README.md"
$ echo world >> README.md
$ cat README.md
hello
world
$ git add README.md
$ git rm -f README.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    README.md

$ git fsck
Checking object directories: 100% (256/256), done.
unreachable blob 94954abda49de8615a048f8d2e64b5de848e27a1
$ git show 94954abda49de8615a048f8d2e64b5de848e27a1
hello
world

所以即使在git rm -f 之后,添加到索引中的文件内容仍然存在。您可以通过运行git fsck --lost-found 将它们全部转储到.git/lost-found/other

索引本身并没有存储为 Git 对象,而是直接驻留在.git/index 中,所以我认为这已被不可逆转地覆盖。这意味着文件的路径以及权限等任何元数据都已丢失。

【讨论】:

  • 我使用了git fsck --lost-found,但是文件的杂乱无章,混合了我以前的提交和未提交的更改,我相信有办法撤消你的任何 git 命令做,它不是白叫版本控制
  • 你重现手头问题的方法很巧妙,向你致敬!
【解决方案3】:

对于已经提交的文件,git reset --hard 会全部恢复。

对于那些添加但未提交的,请尝试git fsck --lost-found。它将打印悬空的 blob 并在 .git/lost-found/other 中制作它们的副本。您可以运行git cat-file -p $blobcat .git/lost-found/other/$blob 来查看内容。 blob 不记录文件路径,所以需要通过内存映射内容和文件路径,或者通过不是git grep $keyword 新修改的关键字。找到 blob 的路径后,运行 cp .git/lost-found/other/$blob $path 来恢复它。

【讨论】:

    【解决方案4】:

    git status 为您提供了一些关于您可以使用哪些命令来恢复文件的提示:

    $ git rm  -rf .
    $ git status
    
    On branch master
    Your branch is up to date with 'origin/master'.
    
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
      deleted: file1
      deleted: file2
    

    取消暂存已删除文件:

    $ git reset HEAD file1 file2
    $ git status
    
    On branch master
    Your branch is up to date with 'origin/master'.
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
        deleted:    file1
        deleted:    file2
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    检查已删除的文件:

    $ git checkout -- file1 file2
    $ git status
    On branch master
    Your branch is up to date with 'origin/master'.
    
    nothing to commit, working tree clean
    

    【讨论】:

    • 你救了我的命
    【解决方案5】:

    正如评论者所说,您应该做的第一件事是备份您的项目目录。

    您可以使用git reset --hard HEAD 取回您提交的文件。由于您清除了暂存树,因此您未提交的更改不再存在于 git 中(正如其他几个答案所指出的,这可能不是真的)因此您恢复它们的唯一机会是您或您的操作系统可能已进行的任何备份。

    很抱歉,这对当前情况没有帮助,但为了将来参考,您可以使用 git reset HEAD 取消您的更改。

    【讨论】:

    • AFAIK,git add * 将更改从工作目录移动到暂存索引,git rm --cached 则相反,而 git commit 将更改从暂存索引移动到 .git 存储库,git reset 做什么?我错过了什么?
    • git reset --hard HEAD 会将暂存树的尖端设置为当前分支的尖端,并从当前分支中检出所有文件。它会将所有内容重置为您的最后一次提交。
    • git rm --cached 不会像您认为的那样做。使用git reset &lt;file&gt; 从索引中删除文件,而不是从您的工作目录中删除。
    • 感谢您清除了一些信息,或者更恰当地说:“揭秘”。
    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 2016-07-09
    • 2018-07-01
    • 2012-08-15
    • 2017-04-16
    • 2022-12-04
    相关资源
    最近更新 更多