奇怪的Git情况 - git stash后跟git stash apply导致未提交的数据丢失?

6
我有一个文件,假设叫file.txt。我用git mv命令把它改名为file1.txt,然后创建了一个叫file.txt的新文件并对其进行操作。不幸的是,我还没有将这个新文件添加到git中。问题在于,我使用了git stash命令,然后又用git stash apply命令,但新的file.txt文件却消失了...有没有办法找回它?

学习Git时,最好在执行功能不完全理解的命令之前备份整个项目目录(包括.git子目录)。我在开始使用Git时经常这样做,从而避免了很多痛苦。尝试从错误中恢复是一个好的实践,但有时您确实会意外永久删除某些内容。硬重置、强制推送、变基等本质上都存在数据丢失的风险,这一点在我阅读的大多数教程中都明确说明了。 - Dan Bechard
4个回答

10
问题在于大多数人误解了git stash save的作用。它只保存已跟踪文件的更改,未跟踪文件不会被git stash保存。当您将file.txt移动到file1.txt时,新的file.txt是一个未跟踪的文件,不会git stash保存。这不是一个bug,而是git stash的行为方式。也许应该更清楚地说明git stash的文档。
正如git stash save的文档所述,它将在保存更改后执行git reset --hard。正是git reset --hard覆盖了新的file.txt。有人可能会认为如果要覆盖未跟踪的文件,git reset --hard应该生成警告,但我仍然不会称之为bug。它正在执行它应该执行的操作。
在这里需要理解的重要事情 - 并且可以节省您很多麻烦的是,git stash save 不会保存未跟踪的文件(也许不应该)。

1
@Dan Moulding,我同意这个观点,但是如果git stash正在回滚并覆盖未提交的数据,就需要一些通知。 - maček
4
我认为这不是误解,而是一个铁一般的错误。Git不应该在没有警告的情况下丢弃未跟踪文件的更改。尽管该文件在索引中没有被跟踪,但它确实在用户试图隐藏的HEAD版本中被跟踪。出于这个原因,我认为在隐藏操作中,Git肯定应该保存工作树版本。 - CB Bailey
@Charles:新文件和重命名后的文件,尽管它们可能有相同的名称,但它们是两个完全不同的文件。Git只跟踪其中一个。说新文件被跟踪是因为Git知道其他树中具有相同名称的某些其他文件就是错的。看看git status在原始文件移动并创建新文件后对工作树状态的描述——这几乎说明了一切。 - Dan Moulding
4
@Dan: 没有 git stash 操作应该会使文件内容丢失,所以这是 git stash 的一个 bug。它使用 reset --hard 将修改后的文件覆盖为 HEAD 版本。由于 stash 正在重置到文件的已跟踪版本,它应该确保已保存要覆盖的任何版本。git stash 应该是一个安全的操作,它不像 reset --hard 要求 git 丢弃东西。我认为观察到的 stash 行为是不可接受的。 - CB Bailey
git stash可以撤销索引和工作树的更改。如果文件在HEAD提交中,从索引中删除并重新添加到工作树中,那么是本地修改。如果您同意“在任何情况下都不应该擦除修改”,那么您是否认为广告行为应该更改?您认为如果重置会更改未跟踪的文件,git stash是否应该失败? - CB Bailey
显示剩余14条评论

4

这看起来是一个严重的问题(即数据丢失)在stash中。请报告此问题。不幸的是,我认为没有任何方法可以恢复新的file.txt

这个bug已经在git >=1.7.1.1版本中被修复。


@khelll:Git 邮件列表:git@vger.kernel.org - CB Bailey
下投票者:我相信我的答案是正确的;如果我错了,请展示一下文件内容可能如何被恢复。 - CB Bailey

2

为了处理未提交的文件,建议使用git stash -u命令(http://www.kernel.org/pub/software/scm/git/docs/git-stash.html),此功能从Git版本1.7开始提供。


1

这篇文章旨在简单说明重建过程,而不会让您陷入评论区。 注意:使用 Git 版本 1.7.0.2

重新创建:

~/test $ git init
~/test $ echo "hello" > file.txt
~/test $ git add .
~/test $ git commit -m "init commit"

~/test $ git mv file.txt file1.txt
~/test $ echo "new data" > file.txt
~/test $ git stash
~/test $ git stash apply

~/test $ cat file.txt
cat: file.txt: No such file or directory

~/test $ cat file1.txt
hello

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