恢复已添加到索引但通过git重置删除的文件 [英] Recover files that were added to the index but then removed by a git reset

查看:723
本文介绍了恢复已添加到索引但通过git重置删除的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


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

  2. 然后我提交了

  3. 当我检查状态时,还有一些文件未包含在添加的提交中,奇怪的

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

  5. 但是我希望一切都在1次单独提交中,所以我查了一下如何停止我刚刚提交的内容

  6. 我使用了 git reset --hard HEAD ^ - 显然不好意思,所有文件都被删除了
  7. >
  8. 然后我用 git reflog 找到我离开的位置

  9. 然后我用 git reflog ______ 返回上次提交。

  10. 然后我使用 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 

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


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



  $ git add。 

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


但是我希望所有事情都在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


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






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



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






这里有一些注释: p>

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



另外,使用 git add几乎不是个好主意。通常,当您创建新的存储库时,您只希望第一次使用它。
更好的替代方案是 git add -u git commit -a 文件。要追踪新文件,最好明确地指定它们。


I added some files to the index but then by mistake I deleted them with git reset --hard. How do I recover them? Here's what happened:

  1. I added all files using git add .
  2. I then committed
  3. When I checked the status, there were still files that weren't included in the commit from the add, which was strange
  4. I added the untracked files again and it worked this time
  5. But I wanted everything to be in 1 single commit so I looked up how to unstage what I just committed
  6. I used git reset --hard HEAD^ — bad idea obviously, all files were deleted
  7. so then I used git reflog to find where I left off
  8. then I used git reflog ______ to go back to my last commit.
  9. then I used git reset HEAD to unstage the commit (what I should have originally done) but the files I added (see above) after the commit were still gone.

How do I get those files back?

解决方案

First, make a full backup of your Git repository!

When you git add a file, git will create a blob out of this file's content and add it to its object database (.git/objects/??/*).

Let's look at your commands, one by one:

I added all files using git add .

$ git add .

This will add all files contained in the current directory and its subdirectories to Git's object database. Untracked files matching patterns from .gitignore files will not be added. Tree files will also be written. Please see the end of my answer.

I then committed

$ git commit -m'added all files'

This will write a new commit object to the object database. This commit will reference a single tree. The tree references blobs (files) and other trees (subdirectories).

When I checked the status, there were still files that weren't included in the commit from the add, which was strange

$ git status

I can think of two scenarios where this happens: something modified your files or new files were added behind your back.

I added the untracked files again and it worked this time

$ git add .

I assume you used the same add command again, as in step 1.

But I wanted everything to be in 1 single commit so I looked up how to unstage what I just committed

I will tell you a better way at the end of this answer, which does not require the user to issue a potentially dangerous reset

I used git reset --hard HEAD^ — bad idea obviously, all files were deleted

$ git reset --hard HEAD^

This command will set your current working tree and index to be exactly at the commit HEAD^ (the second-last commit). In other words, it will discard any local uncommitted changes and move the branch pointer back one commit. It does not touch untracked files.

so then I used git reflog to find where I left off

$ git reflog

This shows the last commits that were recently checked out (identical to git reflog HEAD). If you specify a branch name, it will show you the last commits that this branch pointed to recently.

then I used git reflog __ to go back to my last commit.

Not sure about this one. git reflog is (mostly) a read-only command and cannot be used to "get back" to commits. You can only use it, to find commits a branch (or HEAD) pointed to.

then I used git reset HEAD to unstage the commit (what I should have originally done) but the files I added (see above) after the commit were still gone. $ git reset HEAD

This will not unstage this commit, but it will unstage all staged (but uncommitted) changes from the index. Originally (1st step), you wanted to say git reset HEAD^ (or git reset --mixed HEAD^) – this will leave your working tree untouched, but set the index to match the tree pointed to by the commit named by HEAD^.


Now, to get back your files, you have to use git fsck --full --unreachable --no-reflog. It will scan all objects in Git's object database and perform a reachability analysis. You want to look for blob objects. There should also be a tree object, describing the state after your second git add .

git cat-file -p <object hash> will print the files content, so you can verify that you have the right objects. For blobs, you can use IO redirection to write the content to the correct file name. For trees, you have to use git commands (git read-tree). If it's only a few files, you are better off writing them directly to files.


A few notes here:

If you want to add files to the last commit (or edit its commit message), you can simply use git commit --amend. It's basically a wrapper around git reset --soft HEAD^ && git commit -c HEAD@{1}.

Also, it's almost never a good idea to use git add .. Usually, you only want to use it the first time, when you are creating a new repository. Better alternatives are git add -u, git commit -a, which will stage all changes to tracked files. To track new files, better specify them explicitely.

这篇关于恢复已添加到索引但通过git重置删除的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆