恢复已添加到索引但通过git重置删除的文件

我在索引中添加了一些文件,但后来我错误地用git reset --hard删除了它们。 我如何恢复它们? 以下是发生的事情:

  • 我使用git add .添加了所有文件git add .
  • 然后我承诺
  • 当我检查状态时,仍然存在没有包含在添加提交中的文件,这很奇怪
  • 我再次添加了未跟踪的文件,并且这次它工作
  • 但我希望所有事情都能在一次单独提交中进行,因此我查找了如何取消我刚刚承诺的内容
  • 我用git reset --hard HEAD^ - 很明显,所有文件都被删除了
  • 然后我使用git reflog来查找我离开的位置
  • 然后我使用git reflog ______返回到上次提交。
  • 然后我使用git reset HEAD取消提交(原本应该执行的操作),但提交后添加的文件(请参见上文)仍然消失。
  • 我如何获取这些文件?


    首先,对你的Git仓库进行完整备份!

    当你git add一个文件时,git会从这个文件的内容中创建一个blob,并将它添加到它的对象数据库( .git/objects/??/* )。

    让我们一个一个地看看你的命令:

    我使用git add添加了所有文件。

    $ git add .
    

    这会将当前目录及其子目录中包含的所有文件添加到Git的对象数据库中。 未匹配的.gitignore文件匹配模式的文件将不会被添加。 树文件也将被写入。 请参阅我的答案的结尾。

    然后我承诺

    $ git commit -m'added all files'
    

    这会将新的提交对象写入对象数据库。 这个提交会引用一棵树。 树引用blob(文件)和其他树(子目录)。

    当我检查状态时,仍然存在没有包含在添加提交中的文件,这很奇怪

    $ git status
    

    我可以想到发生这种情况的两种情况:修改您的文件或在您背后添加新文件。

    我再次添加了未跟踪的文件,并且这次它工作

    $ git add .
    

    我假设你再次使用了相同的add命令,如第1步所示。

    但我希望所有事情都能在一次单独提交中进行,因此我查找了如何取消我刚刚承诺的内容

    我会告诉你一个更好的方式,在这个答案的结尾,这不需要用户发出潜在的危险reset

    我用git reset --hard HEAD ^ - 很明显,所有文件都被删除了

    $ git reset --hard HEAD^
    

    这个命令会将你当前的工作树和索引设置为提交HEAD^ (倒数第二个提交)。 换句话说,它将丢弃任何本地未提交的更改并将分支指针移回一个提交。 它不会触及未跟踪的文件。

    所以我用git reflog来查找我离开的地方

    $ git reflog
    

    这显示了最近检出的最后一个提交(与git reflog HEAD相同)。 如果您指定了分支名称,它将向您显示此分支最近指向的最后一个提交。

    然后我使用git reflog __返回上次提交。

    不知道这个。 git reflog (大部分)是只读命令,不能用于“提交”提交。 您只能使用它来查找指向分支(或HEAD )的提交。

    然后我使用git reset HEAD取消提交(原本应该执行的操作),但提交后添加的文件(请参见上文)仍然消失。 $ git reset HEAD

    这不会取消这个提交,但它会取消索引中所有已执行的(但未提交的)更改。 最初(第1步),你想说git reset HEAD^ (或者git reset --mixed HEAD^ ) - 这会让你的工作树保持原样,但是将索引设置为匹配由HEAD^指定的提交所指向的树HEAD^


    现在,为了取回你的文件,你必须使用git fsck --full --unreachable --no-reflog 。 它将扫描Git对象数据库中的所有对象并执行可达性分析。 你想寻找blob对象。 还应该有一个tree对象,描述第二个git add .后的状态git add .

    git cat-file -p <object hash>会打印文件内容,所以你可以验证你是否有正确的对象。 对于blob,您可以使用IO重定向将内容写入正确的文件名。 对于树木,你必须使用git命令( git read-tree )。 如果只有几个文件,最好直接写入文件。


    这里有几个注意事项:

    如果你想添加文件到最后一次提交(或编辑它的提交信息),你可以简单地使用git commit --amend 。 它基本上是git reset --soft HEAD^ && git commit -c HEAD@{1}的包装。

    另外,使用git add .几乎不是一个好主意git add . 。 通常,当您创建新的存储库时,您只希望第一次使用它。 更好的选择是git add -ugit commit -a ,它将对所有跟踪文件进行更改。 要跟踪新文件,最好明确地指定它们。


    我有一个类似的问题,但我的回购中有很多晃来晃去的斑点和树,所以我最后用grep过滤了所有悬空斑点的输出并打印出匹配的斑点。 假设${UNIQUE_CODE}是你在索引中的文件所独有的一些代码,那么这应该给你你正在寻找的斑点的哈希:

    for b in $(git fsck --lost-found | grep blob | awk '{print $3}'); do git cat-file -p $b | grep -q ${UNIQUE_CODE} && echo $b; done
    
    链接地址: http://www.djcxy.com/p/23499.html

    上一篇: Recover files that were added to the index but then removed by a git reset

    下一篇: Undo a git pull