使用暂存区中未提交的文件撤消 git reset --hard
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7374069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Undo git reset --hard with uncommitted files in the staging area
提问by eistrati
I am trying to recover my work. I stupidly did git reset --hard
, but before that I've done only get add .
and didn't do git commit
. Please help! Here is my log:
我正在努力恢复我的工作。我愚蠢地做了git reset --hard
,但在此之前我只做get add .
了没有做git commit
。请帮忙!这是我的日志:
MacBookPro:api user$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# modified: .gitignore
...
MacBookPro:api user$ git reset --hard
HEAD is now at ff546fa added new strucuture for api
Is it possible to undo git reset --hard
in this situation?
git reset --hard
在这种情况下可以撤消吗?
回答by Mark Longair
You should be able to recover any files back that you added to the index (e.g, as in your situation, with git add .
) although it might be a bit of work. In order to add a file to the index, git adds it to the object database, which means it can be recovered so long as garbage collection hasn't happened yet. There's an example of how to do this given in Jakub Nar?bski's answerhere:
您应该能够恢复添加到索引中的任何文件(例如,在您的情况下,使用git add .
),尽管这可能需要一些工作。为了将文件添加到索引中,git 将其添加到对象数据库中,这意味着只要垃圾收集尚未发生,它就可以恢复。在Jakub Nar?bski 的回答中给出了一个如何做到这一点的例子:
However, I tried that out on a test repository, and there were a couple of problems - --cached
should be --cache
, and I found that it didn't actually create the .git/lost-found
directory. However, the following steps worked for me:
但是,我在测试存储库中尝试了该方法,但存在一些问题 ---cached
应该是--cache
,并且我发现它实际上并未创建.git/lost-found
目录。但是,以下步骤对我有用:
git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")
That should output all objects in the object database that aren't reachable by any ref, in the index, or via the reflog. The output will look something like this:
这应该输出对象数据库中任何引用、索引或通过引用日志都无法访问的所有对象。输出将如下所示:
unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03
... and for each of those blobs, you can do:
...对于每个斑点,您可以执行以下操作:
git show 907b308
To output the contents of the file.
输出文件的内容。
Too much output?
输出太多?
Update in response to sehe's comment below:
更新以回应sehe在下面的评论:
If you find that you have many commits and trees listed in the output from that command, you may want to remove from the output any objects which are referenced from unreferenced commits. (Typically you can get back to these commits via the reflog anyway - we're just interested in objects that have been added to the index but can never be found via a commit.)
如果您发现该命令的输出中列出了许多提交和树,您可能希望从输出中删除任何未引用提交引用的对象。(通常,您无论如何都可以通过 reflog 返回这些提交 - 我们只对已添加到索引但永远无法通过提交找到的对象感兴趣。)
First, save the output of the command, with:
首先,保存命令的输出,使用:
git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all
Now the object names of those unreachable commits can be found with:
现在可以通过以下方式找到那些无法访问的提交的对象名称:
egrep commit all | cut -d ' ' -f 3
So you can find just the trees and objects that have been added to the index, but not committed at any point, with:
因此,您可以仅找到已添加到索引但未在任何时候提交的树和对象,使用:
git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \
$(egrep commit all | cut -d ' ' -f 3)
That enormously cuts down the number of objects you'll have to consider.
这极大地减少了您必须考虑的对象数量。
Update:Philip Oakleybelow suggests another way of cutting down the number of objects to consider, which is to just consider the most recently modified files under .git/objects
. You can find these with:
更新:下面的Philip Oakley提出了另一种减少要考虑的对象数量的方法,即只考虑.git/objects
. 您可以通过以下方式找到这些:
find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort
(I found that find
invocation here.) The end of that list might look like:
(我在这里找到了该find
调用。)该列表的末尾可能如下所示:
2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a
In which case you can see those objects with:
在这种情况下,您可以通过以下方式查看这些对象:
git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a
(Note that you have to remove the /
at the end of the path to get the object name.)
(请注意,您必须删除/
路径末尾的 以获取对象名称。)
回答by Richard Saunders
I just did a git reset --hard
and lost one commit. But I knew the commit hash, so I was able to do git cherry-pick COMMIT_HASH
to restore it.
我只是做了一个git reset --hard
并丢失了一个提交。但是我知道提交哈希,所以我能够git cherry-pick COMMIT_HASH
恢复它。
I did this within a few minutes of losing the commit, so it may work for some of you.
我在失去提交的几分钟内完成了这项工作,所以它可能对你们中的一些人有用。
回答by Boy
Thanks to Mark Longair I got my stuff back!
感谢 Mark Longair 我找回了我的东西!
First I saved all the hashes into a file:
首先,我将所有哈希值保存到一个文件中:
git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes
next I put them all (removing the 'unreachable blob' thing) in a list and put the data all in new files...you have to pick your files and rename them again which you need...but I only needed a few files..hope this helps someone...
接下来,我将它们全部(删除“无法访问的 blob”)放在一个列表中,并将数据全部放入新文件中……您必须选择您的文件并重新命名您需要的文件……但我只需要一些文件..希望这对某人有帮助...
commits = ["c2520e04839c05505ef17f985a49ffd42809f",
"41901be74651829d97f29934f190055ae4e93",
"50f078c937f07b508a1a73d3566a822927a57",
"51077d43a3ed6333c8a3616412c9b3b0fb6d4",
"56e290dc0aaa20e64702357b340d397213cb",
"5b731d988cfb24500842ec5df84d3e1950c87",
"9c438e09cf759bf84e109a2f0c18520",
...
]
from subprocess import call
filename = "file"
i = 1
for c in commits:
f = open(filename + str(i),"wb")
call(["git", "show", c],stdout=f)
i+=1
回答by Duncan McGregor
@Ajedi32's solution in the comments worked for me in exactly this situation.
@Ajedi32 在评论中的解决方案正是在这种情况下对我有用。
git reset --hard @{1}
Note that all these solutions rely on there being no git gc, and some of them might cause one, so I'd zip up the contents of your .git directory before trying anything so that you have a snapshot to go back to if one doesn't work for you.
请注意,所有这些解决方案都依赖于没有 git gc,其中一些可能会导致一个问题,因此我会在尝试任何操作之前压缩 .git 目录的内容,以便在没有时可以返回快照不适合你。
回答by olange
Ran into the same issue, but had not added the changes to the index. So all commands above didn't bring me back the desired changes.
遇到了同样的问题,但没有将更改添加到索引中。所以上面的所有命令都没有让我恢复所需的更改。
After all the above elaborate answers, this is a naive hint, but may be it'll save someone who didn't thought about it first, as I did.
在上述所有详尽的答案之后,这是一个幼稚的提示,但可能会像我一样拯救那些没有先想到它的人。
In despair, I tried to press CTRL-Z in my editor (LightTable), once in every open tab — this luckily recovered the file in that tab, to its latest state before the git reset --hard
. HTH.
绝望中,我尝试在我的编辑器 (LightTable) 中按 CTRL-Z,在每个打开的选项卡中按一次 - 幸运的是,这将那个选项卡中的文件恢复到git reset --hard
. 哈。
回答by ddoty
This is probably obvious to the git professionals out there, but I wanted to put it up since in my frantic searching I didn't see this brought up.
这对于那里的 git 专业人士来说可能是显而易见的,但我想把它放出来,因为在我疯狂的搜索中我没有看到这个问题。
I staged some files, and did a git reset --hard, freaked out a little, and then noticed that my status showed all my files still staged as well as all their deletions unstaged.
我暂存了一些文件,然后执行了 git reset --hard,吓了一跳,然后注意到我的状态显示我的所有文件仍然暂存,所有删除的文件都未暂存。
At this point you can commit those staged changes, as long as you don't stage their deletions. After this, you only have to work up the courage to do "git reset --hard" one more time, which will bring you back to those changes you had staged and now just committed.
此时,您可以提交那些暂存更改,只要您不暂存它们的删除。在此之后,您只需鼓起勇气再执行一次“git reset --hard”,这将带您回到您已经上演和现在刚刚提交的那些更改。
Again, this is probably nothing new to most, but I'm hoping that since it helped me and I didn't find anything suggesting this, it might help someone else.
同样,这对大多数人来说可能不是什么新鲜事,但我希望因为它对我有帮助,而且我没有发现任何暗示这一点的东西,它可能会帮助其他人。
回答by Lolo
Goodness, I pulled my hair until I ran into this question and its answers. I believe the correct and succinct answer to the question asked is only available if you pull two of the comments above together so here it is all in one place:
天哪,我一直拉着头发,直到遇到这个问题及其答案。我相信只有将上面的两条评论放在一起,才能对所提出的问题做出正确而简洁的回答,所以这里所有内容都集中在一个地方:
As mentioned by chilicuil, run 'git reflog' to identify in there the commit hash that you want to get back to
As mentioned by akimsko, you will likely NOT want to cherry pick unless you only lost one commit, so you should then run 'git reset --hard
正如chilicuil 所提到的,运行'git reflog' 以在其中标识您想要返回的提交哈希
正如 akimsko 所提到的,除非你只丢失了一次提交,否则你可能不想挑选,所以你应该运行 'git reset --hard
Note for egit Eclipse users: I couldn't find a way to do these steps within Eclipse with egit. Closing Eclipse, running the commands above from a terminal window, and then re-opening Eclipse worked just fine for me.
egit Eclipse 用户注意事项:我找不到在 Eclipse 中使用 egit 执行这些步骤的方法。关闭 Eclipse,从终端窗口运行上面的命令,然后重新打开 Eclipse 对我来说效果很好。
回答by Forrest
I'm using IntelliJ and was able to simply go through each file and do:
我正在使用 IntelliJ 并且能够简单地浏览每个文件并执行以下操作:
Edit -> reload from disk
Edit -> reload from disk
Luckily, I had just done a git status
right before I wiped out my working changes, so I knew exactly what I had to reload.
幸运的是,git status
在我清除工作更改之前我刚刚做了一个正确的操作,所以我确切地知道我必须重新加载什么。
回答by ainthu
Remembering your file hierarchy and using the technique of Mark Longair with Phil Oakley modification yields dramatic results.
记住您的文件层次结构并使用 Mark Longair 的技术和 Phil Oakley 修改会产生显着的结果。
Essentially if you at least added the files to the repo but not committed it, you can restore by interactively using 'git show', inspect the log and use shell redirection to create each file (remembering your path of interest).
基本上,如果您至少将文件添加到存储库但未提交,则可以通过交互式使用“git show”进行恢复,检查日志并使用 shell 重定向来创建每个文件(记住您感兴趣的路径)。
HTH!
哼!
回答by alpha_989
The above solutions may work, however, there are simpler ways to recover from
this instead of going through git
-s complex undo. I would guess that most
git-resets happen on a small number of files, and if you already use VIM, this
might be the most time-efficient solution. The caveat is that you already must
be using ViM's
persistent-undo, which you should be using either way, because
it provides you the ability to undo unlimited number of changes.
上述解决方案可能有效,但是,有更简单的方法可以从中恢复,而不是通过git
-s 复杂的撤消。我猜大多数 git-reset 发生在少数文件上,如果您已经使用 VIM,这可能是最省时的解决方案。需要注意的是,您必须已经在使用ViM's
persistent-undo,无论哪种方式,您都应该使用它,因为它使您能够撤消无限数量的更改。
Here are the steps:
以下是步骤:
In vim press
:
and type the commandset undodir
. If you havepersistent undo
turned on in your.vimrc
, it will show a result similar toundodir=~/.vim_runtime/temp_dirs/undodir
.In your repo use
git log
to find out the last date/time you made the last commitIn your shell navigate to your
undodir
usingcd ~/.vim_runtime/temp_dirs/undodir
.In this directory use this command to find all the files that you have changed since the last commit
find . -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"
Here "2018-03-20 11:24:44" is the date and time of the last commit. If the date on which you did the
git reset --hard
is "2018-03-22", then use "2018-03-22", then use "2018-03-23". This is because of a quirk of find, where the lower boundary is inclusive, and the upper bound is exclusive. https://unix.stackexchange.com/a/70404/242983Next go to each of the files open them up in vim, and do a "earlier 20m". You can find more details about "earlier" by using "h earlier". Here
earlier 20m
mean go back to the state of the file 20 minutes back, assuming that you did thegit hard --reset
, 20 mins back. Repeat this over all the files that was spitted out from thefind
command. I am sure somebody can write a script that will combine these things.
在 vim 中按下
:
并输入命令set undodir
。如果您已persistent undo
在您的 中打开.vimrc
,它将显示类似于 的结果undodir=~/.vim_runtime/temp_dirs/undodir
。在您的 repo 中用于
git log
找出您上次提交的最后日期/时间在您的 shell 中导航到您的
undodir
usingcd ~/.vim_runtime/temp_dirs/undodir
.在此目录中,使用此命令查找自上次提交以来更改的所有文件
find . -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"
这里“2018-03-20 11:24:44”是最后一次提交的日期和时间。如果您执行的日期
git reset --hard
是“2018-03-22”,则使用“2018-03-22”,然后使用“2018-03-23”。这是因为 find 的一个怪癖,下限是包含的,而上限是不包括的。 https://unix.stackexchange.com/a/70404/242983接下来转到每个文件,在 vim 中打开它们,然后执行“更早的 20m”。您可以使用“h early”找到有关“earlier”的更多详细信息。这里的
earlier 20m
意思是回到 20 分钟前的文件状态,假设你做了git hard --reset
20 分钟后。对从find
命令中输出的所有文件重复此操作。我相信有人可以编写一个脚本来结合这些东西。