如何撤消 git stash save --keep-index

问题描述

我正在努力从我的 MacO 中删除 Flutter,并使用命令 git stash save --keep-index,它删除了我 Mac 上的所有内容。我的笔记本电脑上有非常重要的文件,真的很需要这些文件。 非常感谢您的帮助。

提前致谢。

解决方法

TL;DR:git reset --hard && git stash pop。不过请先阅读其余部分!

常规 git stash savegit stash push 的工作原理是:

  • 进行两次提交,1no 分支;2
  • 正在运行 git reset --hard

使用 git stash save 运行的 --keep-index 修改了第二步:而不是 git reset --hard,Git 检查在第一步中进行的 index 提交。 >

这种做法背后的想法很简单。我们从这样一个事实开始,即 Git 进行new 提交不是来自您工作树中的内容,而是来自 Git 索引中的内容。然后,在这个事实之上,我们添加了这样一个想法,即有测试程序(编译器、linter、样式检查器等)读取一个充满文件的目录,例如您的工作树文件,以告诉您是否这些文件是 Good™ 还是 Bad.™

为了让这些不同的测试程序完成它们的工作,那么,我们需要接受提议的提交——它通常在 Git 的索引中,而不是在你的工作树中——并把它放在某个地方。然后我们就可以运行测试程序了。如果它认为你提出的提交是好的,你可以做出那个提交。如果它发现您提议的提交有问题,您可以修复它们并重试。

那么:git stash 应该把这个提议的提交放在哪里?也就是说,我们需要一棵树,就像你的工作树一样,里面装满了 Git 索引中的文件。有人想出的答案是:让我们把它放在你的工作树中。 但这意味着 Git 必须销毁你的工作树的内容!但是——等等—— git stash 刚刚保存您的工作树的内容,在它刚刚制作的这两个无分支提交之一中!所以现在摧毁它肯定没问题,因为它被保存了! stash 命令可以删除所有 那些 文件并将它们替换为 index 提交中的文件。

这就是 --keep-index 所做的。这就是 --keep-index 的全部要点:由于 git stash 已经进行了两次(或三个,每个脚注 1)提交,这为清除创造了足够的空间 em> 所有文件,并将在“在无分支上进行一些提交”步骤中所做的索引提交中的文件放入它们的位置。现在您可以测试这些文件,如果它们很好,就提交它们。

这种方法有一个大问题3(还有许多小问题),但它确实有效:你运行,例如,git stash --keep-indexgit stash -a --keep-index,然后运行linter 或任何你想要的程序,然后运行 ​​git reset --hard,然后运行 ​​git stash pop 来应用并删除存储并放置所有东西——你的工作树 Git 的索引——回到你运行 git stash 之前的样子。 linter 的错误(如果有的话)仍然在您的屏幕上,现在您可以修复它们。如果没有错误,现在您可以运行 git commit

然而,这确实让 git stash --keep-index 成为粗心大意的陷阱,因为 git stash pop 会尝试将保存的工作树应用到保存然后放入-你的工作树索引。如果你有一个“干净”的索引——如果 git status,在 git stash 命令之前,会说没有“暂存以进行提交”的更改,但有些更改“不暂存以进行提交”——一切没问题,一个简单的 git stash pop 就足够了。否则,您首先需要 git reset --hard ......并且您必须意识到这会破坏您在git stash save --keep-index之后所做的任何工作。


1这两个提交分别保存 Git 索引和工作树的内容。如果您添加 -u-a 选项(它们的长拼写,--include-untracked / --all,在这里做完全相同的事情),git stash 添加一个 第三次提交包含额外文件,并添加第三步,从您的工作树中删除存储在第三次提交中的每个文件。

2请记住,任何提交都可以在零个、一个、两个、十个甚至数百万个分支上(如果有的话)。通过确保这两个提交完全没有分支,git stash 试图让您更容易“认为”这些提交可以从 all 获得em> 分支。我不认为这是一个特别好的主意,因为所有提交总是在任何时候都可用,但这就是 git stash 的工作原理。

3最大的问题是,如果您的工作树和索引与当前提交匹配,那么 git stash --keep-index 什么都不做。这使得自动化过程变得不可能(或者至少太困难以至于人们不断出错):人们在执行 linting 之前编写使用 git stash --keep-index 的预提交钩子,然后执行 git reset --hard && git stash pop,如果git stash --keep-index 什么也没做,这会弹出其他一些藏匿处,带来可怕的副作用。