这个问题的标题相同,但不是同一个问题。这个问题实际上是在问"丢弃 git stash pop 的结果"。这个问题其实是
撤消 git stash pop
换句话说
1 2 3 4 5 6 7
| // in branch foo
git stash
git checkout bar
git stash pop # ERROR. I didn't want to pop on top of bar, lots of conflicts
git stash undo-pop # NEED COMMAND TO PUT STASH AND LOCAL FILES BACK AS THEY WERE
git checkout foo
git stash pop |
有没有办法让一切恢复到我输入 git stash pop 之前的状态?换句话说,实际上撤消 pop 并将隐藏的东西放回 stash 并将本地文件恢复到我输入 git stash pop 之前的状态。
这也不是如何在 Git 中恢复丢弃的存储?虽然这在某些情况下可能会有所帮助
- 通常,您可以为此再次使用 git stash 。
-
我无法使用 git stash,文件在 bar 之上处于冲突状态。
-
然后将这些信息放在问题中,因为它有很大的不同。
-
它在问题中。这也是UNDO这个词的全部意义。
在您的示例中,要恢复到 git stash pop 之前的状态,请使用:
这种形式的git reset命令将索引和工作目录的状态恢复到bar分支的头部。
因为你在第一个 git stash pop 上发生了冲突,所以存储仍然在存储堆栈的顶部。
从那里,你可以再次git checkout foo和git stash pop。
Greg Hewgill 的答案是正确的(并且被赞成,并且 OP 应该接受它)但是这里还有几个额外的警告,以防有人想以更一般的方式使用答案。我们先来看看具体使用的命令顺序:
1 2 3
| git stash
git checkout bar
git stash pop # ERROR ... lots of conflicts |
现在,让我们列出注意事项:
-
git stash pop 失败很重要。 (格雷格已经注意到了这一点。)
-
创建存储时您没有使用 git stash --keep-index。
-
运行 git stash 后,您没有对工作树进行任何更改。
-
git checkout 命令成功了,所以它可能已经对您的工作树进行了更改——事实上,它必须这样做才能使 pop 失败——但是您的工作树仍然是"干净的",因为 git status会说。
这是最后一点,git status 会(在尝试 git stash pop 之前)告诉您您的工作树是 clean,这是关键。如果您在 git checkout bar 之前或之后对工作树进行了更改,您将遇到更多麻烦。
因为你没有做那些事情,git reset --hard就是答案。
为什么会这样
git stash 所做的通常是进行两次提交。一个保存当前索引,另一个保存当前工作树。1 这些提交在某些方面有些特殊;最重要的是它们根本不在分支上。2 提交后,git stash 然后正常运行 git reset --hard.3
git reset --hard 步骤的作用是使索引和工作树与当前提交匹配。也就是说,我们将(整个)索引和(整个跟踪的部分)工作树保存在存储库中;因此,无论当前 HEAD 提交和索引之间有什么不同,都可以重新设置为相同; HEAD 提交和工作树之间的任何不同之处都可以重新设置为相同。
在 git reset 之后,索引和工作树都是"干净的",正如 git status 所说:它们都匹配 HEAD 提交。然后您可以 git checkout 其他分支,因为您没有未保存的工作。然后,您可以尝试 git stash apply,甚至 git stash pop,将您的更改"移动"到另一个分支。
如果失败(如本例所示),则存储将保留在已保存的存储中。当前索引和工作树现在充满了合并冲突。如果你运行 git reset --hard,Git 将像往常一样重新设置索引和工作树以匹配 HEAD 提交,这样你将回到 git checkout 步骤之后的相同情况。由于您没有未保存的工作(您保存的工作仍在 stash 提交中),所以您在这里没问题。
(如果您确实有未保存的工作,则 git stash apply 步骤将通过尝试合并隐藏的工作树更改来破坏未保存的工作。这通常很难撤消。)
1虽然 git stash 通常会进行两次提交,但如果您使用 --all 或 --include-untracked 运行它,它将进行三次提交。我喜欢将这些称为 i(索引)、w(工作树)和 u(取消跟踪文件)提交。
当使用 --all 或 --include-untracked 时,save 或 push 步骤将不仅仅是 git reset --hard:它还将运行 git clean 以删除进入第三次提交的任何内容(仅限未跟踪文件,或未跟踪的包括忽略的文件)。在应用这样的存储之前,您可能必须重复此 git clean 工作,这既棘手又烦人。
稍后,当您运行 git stash apply 时,Git 将(尝试)应用 u 提交(如果存在)。它将始终(尝试)应用 w 提交。仅当您给它 --index 标志时,它才会(尝试)应用 i 提交。许多版本的 git stash 围绕整个"单独的索引恢复"内容存在一些小错误。它们往往会影响想要在例如预提交钩子中使用 --keep-index 和 --index 标志的人。
请注意,git stash pop 只是 git stash apply && git stash drop:也就是说,尝试应用存储,然后,如果 Git 认为 apply 运行良好,那么 drop 也会应用存储。我发现最好先使用 git stash apply ,即使 Git 认为它进展顺利,也可以避免丢弃存储,因为 Git 和我有时不同意"进展顺利"的含义。 :-)
2Git 使用名称 refs/stash 来记住当前的存储,并且(ab)使用 refs/stash 的 reflog 来维护"存储堆栈"的其余部分。内部分支名称都具有 refs/heads/name 形式,因此 refs/stash 不是分支名称。
3如果使用git stash --keep-index,它运行的不仅仅是git reset --hard:它会将保存的索引状态提取到工作树中。这里的目标是让工作树按照索引的设置方式设置,以便您可以测试您将要提交的内容。如脚注 1 中所述,这里有一个小但相当讨厌的错误,这里有许多版本的 git stash,如果正确的工作树版本与HEAD 版本。
您可以对存储进行反向修补(如前所述,它应该仍然存在,因为如果它不干净地应用,git 不会删除存储)
1
| git stash show -p stash@{0} | git apply -R |
所以,我不能在所有情况下都 100% 确定答案。在我的情况下,当我输入 git stash pop 并且我在分支 bar 上时存在冲突。因此,当它应用存储时,它并没有丢弃存储。所以要撤消并正确地将存储应用到分支 foo 它只是
1 2 3
| git reset --hard # resets bar to before the stash pop
git checkout -b foo
git stash pop |
如果与分支 bar 没有冲突,那么它只是
1 2 3
| git stash # restash
git checkout -b foo
git stash pop |
- 如果你弹出一个存储并且没有冲突,那么要撤消 git stash pop 你只需再次 git stash 。
-
你确定吗?与 bar 合并时是否有可能某些合并会匹配,因此重新存储的差异与用于不同分支的原始存储不匹配?我想它只是存储树的状态而不是差异,所以是的,git stash 应该可以工作