对暂存区中未提交的文件撤消 git reset --hard

发布于 2024-12-03 19:53:45 字数 417 浏览 0 评论 0原文

我正在努力恢复我的工作。我愚蠢地执行了 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

在这种情况下是否可以撤消 git reset --hard ?

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:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

十雾 2024-12-10 19:53:46

您应该能够恢复添加到索引中的任何文件(例如,在您的情况下,使用 git add . ),尽管这可能需要一些工作。为了将文件添加到索引,git 将其添加到对象数据库,这意味着只要垃圾收集尚未发生,就可以恢复该文件。 中给出了如何执行此操作的示例Jakub Narębski 的回答在这里:

但是,我在测试存储库上尝试了这一点,并且存在一些问题 - --cached 应该是 --cache,但我发现它没有实际上创建了.git/lost-found 目录。但是,以下步骤对我有用:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")

这应该输出对象数据库中任何引用、索引或通过引用日志都无法访问的所有对象。输出将如下所示:

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03

... 对于每个 blob,您可以执行以下操作:

git show 907b308

输出文件的内容。


输出太多?

更新以响应 sehe 下面的评论:

如果您发现自己有很多提交并且如果该命令的输出中列出了树,您可能希望从输出中删除未引用提交引用的任何对象。 (通常,您无论如何都可以通过引用日志返回这些提交 - 我们只对已添加到索引但永远无法通过提交找到的对象感兴趣。)

首先,保存命令的输出,使用

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all

:可以通过以下方式找到这些无法访问的提交的对象名称:

egrep commit all | cut -d ' ' -f 3

因此,您可以仅找到已添加到索引中但在任何时候都未提交的树和对象,通过:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \
  $(egrep commit all | cut -d ' ' -f 3)

这极大地减少了您将拥有的对象数量考虑。


更新:下面的Philip Oakley提出了另一种减少要考虑的对象数量的方法,即只考虑 .git/objects 下最近修改的文件。您可以通过以下方式找到这些内容:(

find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort

我发现 find 调用此处.) 该列表的末尾可能如下所示:

2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a

在这种情况下,您可以通过以下方式查看这些对象:

git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a

(请注意,您必须删除路径末尾的 / 才能获取对象名称。 )

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 answer here:

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:

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:

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

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 Oakley below 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:

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:

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

人│生佛魔见 2024-12-10 19:53:46

我刚刚执行了 git reset --hard 并丢失了一次提交。但我知道提交哈希,因此我能够执行 gitcherry-pick COMMIT_HASH 来恢复它。

我在失去提交后几分钟内就完成了此操作,因此它可能对你们中的一些人有用。

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.

I did this within a few minutes of losing the commit, so it may work for some of you.

留蓝 2024-12-10 19:53:46

感谢 Mark Longair 我拿回了我的东西!

首先,我将所有哈希值保存到一个文件中:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes

接下来,我将它们全部(删除“无法访问的斑点”的东西)放入列表中,并将数据全部放入新文件中...您必须选择文件并再次重命名它们需要...但我只需要一些文件..希望这对某人有帮助...

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

Thanks to Mark Longair I got my stuff back!

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

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
吻安 2024-12-10 19:53:46

@Ajedi32 评论中的解决方案在这种情况下对我有用。

git reset --hard @{1}

请注意,所有这些解决方案都依赖于没有 git gc,其中一些可能会导致出现这种情况,因此我会在尝试任何操作之前压缩 .git 目录的内容,以便在没有 git gc 的情况下可以返回到快照不适合你。

@Ajedi32's solution in the comments worked for me in exactly this situation.

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.

烟雨凡馨 2024-12-10 19:53:46

遇到了同样的问题,但没有将更改添加到索引中。所以上面的所有命令都没有给我带来所需的更改。

在上面所有详尽的答案之后,这是一个天真的提示,但它可能会拯救那些像我一样首先没有考虑到这一点的人。

绝望中,我尝试在编辑器 (LightTable) 中按 CTRL-Z,在每个打开的选项卡中按一次 - 幸运的是,该选项卡中的文件恢复到了 git reset --hard 之前的最新状态。

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.

权谋诡计 2024-12-10 19:53:46

天哪,我揪着头发直到遇到这个问题及其答案。我相信只有当您将上面的两条评论放在一起时,才能得到所问问题的正确而简洁的答案,因此这里所有内容都集中在一个地方:

  1. 正如 chilicuil 所提到的,运行 git reflog 来识别其中的
    提交您想要返回的哈希

  2. 正如 akimsko 所提到的,您可能不想选择樱桃
    除非您只丢失了一次提交,所以您应该运行 git reset --hard

egit Eclipse 用户注意:我找不到一种方法来执行这些操作Eclipse 中使用 egit 的步骤。关闭 Eclipse,从终端窗口运行上述命令,然后重新打开 Eclipse 对我来说效果很好。

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:

  1. As mentioned by chilicuil, run git reflog to identify in there the
    commit hash that you want to get back to

  2. 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 <hash-commit-you-want>

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 reopening Eclipse worked just fine for me.

(り薆情海 2024-12-10 19:53:46

如果您使用 IDE 编辑文件,它也可能会独立于 Git 保留自己的历史记录。在某些情况下,完全绕过 Git 并使用 IDE 会简单得多。例如,IntelliJ IDEA 和 Eclipse 都具有这种自动化的本地版本控制,他们将其称为“本地历史记录”。在 IntelliJ 中,检索多个文件中丢失的整批更改非常简单:在“项目”窗格中,您可以右键单击整个项目或目录树,然后在“本地历史记录”子菜单中选择“显示历史记录”。 git reset --hard 应作为“外部更改”(即从 IDE 外部触发)出现在列表中,并且您可以使用恢复按钮或上下文菜单项将所有内容恢复到状态就在外部变化发生之前。

If you are editing your files with an IDE, it may also be keeping its own history independent of Git. In some circumstances it is much simpler to bypass Git entirely and use the IDE. For example, IntelliJ IDEA and Eclipse both have this kind of automated local version control, which they refer to as "local history". In IntelliJ it's straightforward to retrieve a whole batch of lost changes across many files: in the Project pane, you can right-click an entire project or directory tree and select Show History in the Local History submenu. The git reset --hard should appear in the list as an "external change" (i.e. triggered from outside the IDE), and you can use the revert button or context menu item to revert everything to the state right before that external change happened.

婴鹅 2024-12-10 19:53:46

这对于 git 专业人士来说可能是显而易见的,但我想把它提出来,因为在我疯狂的搜索中我没有看到这个问题。

我暂存了一些文件,并执行了 git reset --hard,有点害怕,然后注意到我的状态显示我的所有文件仍然暂存,并且所有删除​​的文件都未暂存。

此时,您可以提交这些暂存的更改,只要您不暂存它们的删除即可。
之后,您只需要鼓起勇气再执行一次 git reset --hard ,这将使您回到您已经上演并现在刚刚提交的更改。

再说一次,这对大多数人来说可能不是什么新鲜事,但我希望既然它对我有帮助,而且我没有发现任何暗示这一点的东西,它可能会对其他人有所帮助。

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.

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.

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.

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.

时间海 2024-12-10 19:53:46

如果您最近查看了 git diff,那么还有另一种方法可以从此类事件中恢复,即使您尚未暂存更改:如果 git diff 的输出> 仍在控制台缓冲区中,您只需向上滚动,将差异复制粘贴到文件中,然后使用 patch 工具将差异应用到您的树: patch -p0 patch -p0 patch -p0 patch -p0 patch -p0 文件。这种方法救了我几次。

If you've recently reviewed a git diff then there's another way to recover from incidents like this, even when you haven't staged the changes yet: if the output of git diff is still in your console buffer, you can just scroll up, copy-paste the diff into a file and use the patch tool to apply the diff to your tree: patch -p0 < file. This approach saved me a few times.

与酒说心事 2024-12-10 19:53:46

上述解决方案可能有效,但是,还有更简单的方法可以恢复
这而不是通过 git -s 复杂的撤消。我猜大多数
git-resets 发生在少量文件上,如果你已经使用 VIM,这
可能是最省时的解决方案。需要注意的是,你已经必须
使用 ViM 的持久撤消,您应该使用任何一种方式,因为
它使您能够撤消无限数量的更改。

步骤如下:

  1. 在 vim 中按 : 并输入命令 set undodir。如果你有执着
    undo
    在你的 .vimrc 中打开,它会显示类似的结果
    undodir=~/.vim_runtime/temp_dirs/undodir

  2. 在您的存储库中使用git log来查找您上次创建的最后日期/时间
    commit

  3. 在你的 shell 中使用以下命令导航到你的 undodir
    cd ~/.vim_runtime/temp_dirs/undodir

  4. 在此目录中使用此命令查找您拥有的所有文件
    自上次提交以来已更改

    <代码>
    寻找 。 -newermt“2018-03-20 11:24:44”\! -newermt "2018-03-23" \( -type f
    -regextype posix-extend -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

  5. 接下来转到每个文件在 vim 中打开它们,并执行“earlier 20m”。
    您可以使用“h previous”找到有关“earlier”的更多详细信息。这里
    earlier 20m 表示回到文件20分钟前的状态,
    假设您在 20 分钟前执行了 git Hard --reset。重复此操作
    find 命令中吐出的所有文件。我相信
    有人可以编写一个脚本来组合这些东西。

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.

Here are the steps:

  1. In vim press : and type the command set undodir. If you have persistent
    undo
    turned on in your .vimrc, it will show a result similar to
    undodir=~/.vim_runtime/temp_dirs/undodir.

  2. In your repo use git log to find out the last date/time you made the last
    commit

  3. In your shell navigate to your undodir using
    cd ~/.vim_runtime/temp_dirs/undodir.

  4. 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/242983

  5. Next 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 the git hard --reset, 20 mins back. Repeat this over
    all the files that was spitted out from the find command. I am sure
    somebody can write a script that will combine these things.

回忆追雨的时光 2024-12-10 19:53:46

我正在使用 IntelliJ,并且能够简单地浏览每个文件并执行以下操作:

Edit ->从磁盘重新加载

幸运的是,我刚刚在清除工作更改之前完成了git status,所以我确切地知道我必须重新加载什么。

I'm using IntelliJ and was able to simply go through each file and do:

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.

痴意少年 2024-12-10 19:53:46

我无法使用 git 命令恢复该文件。就我而言,它是一个 CPP 文件。我知道其中有一个独特的字符串,有帮助。命令是:

sudo grep -a -B[number of rows before the text being searched] -A[number of rows after the text being searched] '[some unique text in the lost file]' /dev/sda3 > test.cpp

搜索整个磁盘,但最终找到了丢失文件的内容。

I was not able to recover the file using git commands. In my case, it was a CPP file. I knew a unique string in it and this helped. The command is:

sudo grep -a -B[number of rows before the text being searched] -A[number of rows after the text being searched] '[some unique text in the lost file]' /dev/sda3 > test.cpp

Searches the whole disk but in the end, it found the content of the lost file.

不语却知心 2024-12-10 19:53:46

记住你的文件层次结构并使用 Mark Longair 的技术和 Phil Oakley 的修改会产生显着的结果。

本质上,如果您至少将文件添加到存储库但未提交,则可以使用 git show 交互地进行恢复,检查日志并使用 shell 重定向来创建每个文件(记住您感兴趣的路径) 。

Remembering your file hierarchy and using the technique of Mark Longair with Phil Oakley modification yields dramatic results.

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

甜中书 2024-12-10 19:53:46

使用 IntelliJ IDEA 的本地历史记录功能恢复未提交的更改

我也遇到过类似的情况,但未提交的更改也没有添加到索引(git add .),我成功恢复了它。

如果您使用的是 IntelliJ IDEA,请按照以下步骤操作:

  • 在 IntelliJ IDEA 中,转到项目视图。 (左上角栏上的文件夹图标
  • 右键单击丢失更改的文件或目录。
  • 从上下文菜单中选择“本地历史记录”。
  • 从子菜单中选择“显示历史记录”。
  • 这将显示对文件或目录所做的本地更改的列表,包括丢失的更改。然后,您可以选择要恢复的版本并恢复到它。
  • 右键单击所选版本,然后单击“恢复”,

这将恢复您未提交的更改。

Recover your uncommitted changes using IntelliJ IDEA's local history feature

I was also in the similar situation but with uncommitted changes and also wasn't added to index (git add .), I successfully recovered it.

If you're using IntelliJ IDEA, please follow the below steps:

  • In IntelliJ IDEA, go to the project view. (Folder icon on the top left bar)
  • Right-click on the file or directory where you lost the changes.
  • Choose "Local History" from the context menu.
  • From the submenu, select "Show History".
  • This will display a list of local changes made to the file or directory, including the lost changes. You can then select the version you want to restore and revert to it.
  • Right-click on the selected version then click "Revert"

This will revert back your uncommitted changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文