意外检出后如何恢复更改?

82

以下是我的代码库的状态。

[~/rails_apps/jekyll_apps/nepalonrails (design)⚡] ➔ gst
# On branch design
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   _layouts/default.html
#   deleted:    _site/blog/2010/04/07/welcome-to-niraj-blog/index.html
#   deleted:    _site/blog/2010/04/08/the-code-syntax-highlight/index.html
#   deleted:    _site/blog/2010/05/01/showing-demo-to-kalyan/index.html
#   deleted:    _site/config.ru
#   deleted:    _site/index.html
#   deleted:    _site/static/css/style.css
#   deleted:    _site/static/css/syntax.css
#   modified:   static/css/style.css
#
no changes added to commit (use "git add" and/or "git commit -a")

我不小心执行了git checkout -f命令,导致我原本的改动消失了,这并不是我想要的结果。

[~/rails_apps/jekyll_apps/nepalonrails (design)⚡] ➔ git co -f
[~/rails_apps/jekyll_apps/nepalonrails (design)] ➔ gst
# On branch design
nothing to commit (working directory clean)
[~/rails_apps/jekyll_apps/nepalonrails (design)] ➔ 

我能找回之前的更改吗?

15个回答

92

你可以通过IDE查看一下。我无意中检出了2个文件,但是通过我的IDE(Netbeans)的“本地历史记录”功能,我能够恢复更改。真是太好了!

如果你在使用Eclipse,请右键单击文件,选择Team->Show Local History。


4
您可以在Eclipse中右键单击文件,然后转到 "Team->Show Local History" 来执行此操作。 - donturner
18
你刚刚救了我的命!在JetBrains中进行此操作,转到VCS菜单>本地历史记录。 - Michael Bates
我也遇到过这种情况,Eclipse自动刷新了文本内容;但是按几次ctrl+Z就可以恢复我的修改,谢天谢地! - Arnaud A
4
使用Sublime Text 3,我在丢失文件时按下ctrl+z就足以恢复它们。</ 恐慌> - Madbreaks
2
只需按下Cmd+Z并选择“从磁盘重新加载撤消”就可以在IntelliJ Idea中保存我的工作了。 - Sergey Shcherbakov
显示剩余7条评论

63
我不认为你可以恢复那些私人数据(“私人”指的是“未添加到索引中,也未提交”,因此Git无法识别),除非你在当前工作目录中有其他备份过程。即使这在Git别名页面中没有提出,我认为应该为checkout(就像使用alias rm / bin / rm-i 一样)创建某种别名。
[alias]
co = !sh -c 'git stash; git stash apply; git checkout "$@"'

这段内容与编程有关,讲述了“检查点技术”的应用,其中 'git stash; git stash apply' 是Brian Campbellhis answer中使用的方法。请注意保留""和""以及html标签。

stason在评论中提出:

co = "!git stash push -m \"co backup\"; git stash apply; git checkout \"$@\"" 

注意,我添加了一条消息来区分备份储藏和其他储藏。-
这个问题让我想起了ycombinator上关于这种行为的辩论(摘录):
我在使用git时丢失了很多数据。其中大部分与听起来无害的命令有关,这些命令在删除数据时不会要求确认。例如,git checkout filename相当于svn revert filename。当然,git checkout branchname则完全不同。如果一个分支和一个文件共享相同的名称,则git将默认切换分支,但这并不能阻止bash自动完成操作。这是一个疯狂的想法:如果您有一个无害的操作和一个危险的操作,请不要使用相同的命令标记它们。

可能有些烦人,但这是用户错误而不是设计错误。使用git时,如果我想无损地丢弃我的工作副本,我只需执行"git stash"即可。
按照您的逻辑,"rm"是有缺陷的,因为当您传递-f而不是-i时,它不会要求确认。是的,抱歉。


您的比喻更准确,如果rm somename相当于apt-get update,而rm othernamerm -fr othername。但是,“get checkout foo”不能对是否存在名为foo的文件在当前目录中进行完全不同的操作。
这里有另一个疯狂的想法:不要在脏工作目录上运行“git checkout ...”。问题解决了。 还有一个:不要将文件名重复用作分支名称。 说实话:我也有粗心调用“rm”而毁掉一天的问题,但当我嘟囔诅咒时,是因为我的懒惰/愚蠢,而不是bash补全或“rm”的行为。

在我的 git 1.7.9.5 上,上述别名会出现“意外的 EOF”错误。尝试将“;”替换为“&&”。尝试使用“$@”代替“$*”,但 strace 表明参数未传递给 execve。尝试使用“f() {...}; f”,但没有成功。这对其他人有效吗? - alexei
@alexei 我已经很久没有使用过那个了。我需要根据http://blogs.atlassian.com/2014/10/advanced-git-aliases/的内容进行更新。 - VonC
1
这个别名似乎可以使用:co = "!git stash push -m \"co backup\"; git stash apply; git checkout \"$*\""。请注意,我添加了一条消息以区分备份存储和其他存储。 - stason
1
@stason 谢谢你。我已将你的评论包含在答案中以供更多人注意。 - VonC
1
@VonC,我有一个更正:请在您的原始解决方案和我的更新中将$*替换为$@。如果您使用git co entry1 entry2,则$*将无法工作-它会抱怨“错误:pathspec 'entry1 entry2' did not match any file(s) known to git”。应该改为:co = "!git stash push -m \"co backup\"; git stash apply; git checkout \"$@\""谢谢。 - stason

29

除非你之前曾使用git addgit stash这些文件,否则很抱歉没有办法找回。如果你已经添加或隐藏它们,则可以通过git reflog找到它们的哈希。

我从未对git checkout的这种破坏性行为感到舒适。也许一个有用的增强功能是在覆盖你的工作之前自动创建一个存储(以便通过reflog捕获文件)。


5
我希望 Git 能够做到这一点。每当我切换分支时都需要将我的工作储藏起来,这让我感到很烦恼。我希望能够输入 "git checkout foo; git checkout bar",并且假设我一开始在分支 bar 上,无论我修改了什么、已经将什么添加到索引中等,命令执行后我的索引和工作目录都能恢复到原来的状态。 - divegeek
所以你想让Git自动对文件和更改进行版本控制,而无需您告诉它吗? - Dennis Estenson
截至最新的Git版本,所有的checkout都记录在reflog中。 - Raj
即使分支被切换,将状态(已提交或未提交)保存在本地环境中是有意义的。@DennisEstenson - M.K

17
如果您使用 IntelliJ Idea , 您可以在所选的项目文件夹上单击鼠标右键,然后选择本地历史记录,您将会看到所有文件。

这个问题没有提到IntelliJ Idea,所以这不太可能是一个有用的答案。 - McFadden
1
对我很有用 :) - Ignacio Tomas Crespo
1
你救了我,非常感谢。那是个好主意。我丢失了文件,也记不起它们的路径以便通过本地历史还原它们,但这个建议帮助我想起了文件的结构和名称。 - Adi Dasler

10

使用VS Code,通过按下CTRL+Z从本地磁盘获取最新更改的过程非常顺利。因此,请尝试使用该IDE。


1
使用无限宝石恢复我的代码后,感觉像托尼·斯塔克一样,几乎失去了一整天的工作,干杯! - collo54

5
如果您在Linux上使用vim,可能会遇到以下情况。
  • If files are open in an active buffer then you've got the file content as long as you don't reload the file in vim, and can restore by saving it. .

  • If files are not open in an active buffer, but are dirty, then there should be an .swp file in the source directory which also has a copy of the content that is recoverable via vim -r file.swp.

  • If the files are neither open in antive buffer nor dirty, and if your working copy is on an ext3 or ext4 partition, then extundelete might be able to find the recently deleted .swp files and/or an older version of the source files. Remount the partition as read-only, e.g. mount -o remount,ro /mnt/point, and run

    extundelete --recover-directory /path/to/working/copy /dev/sdaX
    

    If the partition that contains the working copy is the root partition, it may refuse to remount, then try killing all services, and if still no go, then shutdown and boot using a Live CD/USB/PXE, like GRML, and run the above. I was successful in recovering one out of three lost files this way.


5
如果您使用Eclipse作为IDE和EGit,您将在文件上拥有Team菜单:
  1. 从内部右键单击文件
  2. 列表项 "Team" -> "Show Local History"
您将看到所有本地保存的版本,没有任何保存名称,在我的情况下,您可以轻松检查所有未跟踪的更改并恢复丢失的代码。

3
如果使用的是Android Studio作为IDE,那么打开被更改过的文件,然后进入VCS -> Local History -> Show History。你将能够在这里看到已打开的文件的历史记录。

3
您可以使用 VSCode 文件时间轴,只需右键单击文件即可。 enter image description here

2

我正在使用Intellij。对于我而言,CTRL+z是可行的,它会提示你“从磁盘重新加载更改”,然后点击“是”即可。


1
基本上撤销你的操作将会让你回到IDE中。只需要希望这是一个小的提交。 - Winnemucca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接