撤销导致合并冲突的git stash pop

920
我开始修改代码库,没有意识到我正在使用一个旧的主题分支。为了转移它们,我想把它们存储下来,然后应用到一个新的基于主分支的分支上。我使用 git stash pop 命令把工作中的更改转移到这个新分支,却忘记在创建新分支之前拉取了主分支的新更改,导致一堆合并冲突和我的更改清单丢失(因为我使用了pop命令)。
一旦我正确地重新创建了新分支,我该如何恢复我的隐藏更改以便正确地应用它们?

5
Git 聪明地不会丢弃存储区(stash),如果它不能干净地应用(apply)该存储区。 - Snowmanzzz
1
知道你的存储仍在 git stash list 上,可以放心使用 git reset --hard。即当你在错误的分支上进行了存储弹出并且冲突很明显时。 - Sławomir Lenart
1
这里有一个重复的问题,解决冲突的方法更简单,只涉及到少量文件。https://stackoverflow.com/a/60348183/5440638 - undefined
6个回答

1046

结果证明,Git足够智能,如果它不能应用,就不会丢弃存储。我通过以下步骤达到了期望的状态:

  1. 取消暂存合并冲突:git reset HEAD .(注意末尾的点)
  2. 保存有冲突的合并(以防万一):git stash
  3. 返回主分支:git checkout master
  4. 拉取最新的更改:git fetch upstream; git merge upstream/master
  5. 纠正我的新分支:git checkout new-branch; git rebase master
  6. 应用正确的存储更改(现在在第二个位置):git stash apply stash@{1}

18
非常感谢!#6 真的是我在寻找的答案。你可以在最后一步添加 git stash drop 命令以删除 #2 中不需要的贮藏内容。 - austinmarton
3
如果存在未合并的路径,#2 将无法生效,它会输出此处描述的错误信息:https://dev59.com/2m035IYBdhLWcg3wVud1 - Étienne
8
并非完全正确--如果Git无法干净地应用暂存内容,它将在暂存列表中保留该项。请参阅有关git stash pop的文档:“如果应用状态存在冲突而失败,则不会从暂存列表中删除。您需要手动解决冲突,并随后调用git stash drop进行删除。” (https://git-scm.com/docs/git-stash) - Carolyn Conway
2
这个不能正常工作。 :-( 它撤销了更改,但是在我的文件中留下了一堆噪音,例如:<<<<<<< Updated upstream >>>>>>> Stashed changes - Jez
34
@call-me 这是我认为人们实际上应该更经常做的事情!请注意,“提问”表单有一个复选框,让您在同一表单中回答自己的问题 :)。这有时会发生在我撰写一个难住我的问题时,但在试图调整问题使其适合 StackOverflow 时,我最终会找到解决方案。这是一段时间以前的事情了,所以我不记得是否出现了这种情况,但我猜这就是发生的事情。 - acjay
显示剩余6条评论

511

幸运的是,git stash pop在冲突的情况下不会更改stash!

所以不用担心,只需清理代码并重试即可。

假设你的代码库之前是干净的,你可以通过以下命令回到那个状态:git checkout -f
然后做你忘记的事情,例如:git merge missing-branch
之后再次运行git stash pop,就会得到之前冲突的相同的stash。

请注意:stash是安全的,但是工作目录中的未提交更改当然不是。它们可能会被搞砸。


33
我的理解是,你可以简单地清除并再次弹出,但你无法撤消它。如果弹出操作与其他未提交的更改混合在一起,那么你就必须手动清理。 - haridsv
1
@TrevorHickey 这个答案的重点是,在冲突的情况下,存储区保持不变,你可以多次调用 git stash pop 直到它在没有冲突的情况下结束。因此,在冲突后,是的,工作目录会很混乱,但是你可以清理它并再次调用 git stash pop - flori
17
撤销上一个stash apply命令的指令非常有用:git checkout -f - Lafi
3
git checkout -f 的意思是强制切换到另一个分支并覆盖本地未提交的更改。 - Aparna
1
git checkout -f branchname 的意思是“检出branchname,f = force,意味着我知道当前有未提交的更改,但我不在乎,只需丢弃所有更改。由于如果存在冲突,则git stash pop实际上不会“pop”,因此我能够进行强制检出,然后在正确的分支上再次执行git stash pop。非常简单易行。 - Mike K
显示剩余4条评论

122

最简单的命令,适用于任何地方,包括 git stash pop, git merge 等。

但要小心!您将失去所有未跟踪文件的更改。已跟踪文件保持不变。

git reset --merge

30
小心!您将会丢失所有未追踪文件的更改。 - Ebram Shehata
4
而且似乎你也会失去所有已暂存、已跟踪文件的更改。 - enocom
这正是我所需要的,因为我已经对被跟踪的文件进行了更改,所以我不想进行硬重置,并且它们仍然保持原样。 - tishma
这很危险!在我的文件已经被索引的情况下,我运行了git stash pop之后又运行了这个命令,结果我失去了所有被索引的文件! - Attila Szeremi

45

这里的说明有点复杂,所以我将提供更简单的方法:

  1. git reset HEAD --hard 放弃对当前分支的所有更改

  2. ... 根据需要执行中间工作

  3. git stash pop 在稍后准备好时再次恢复存储


34
git checkout -f

如果你之前的状态是干净的,那么必须工作。

注意:小心,你将丢失所有未跟踪的文件更改。


9
注意,你将会失去所有未被追踪的文件变更。 - sbrk
好的,这删除了我跟踪、暂存但未提交的更改! - Ali80

2
如果您和我一样,有一些未提交的更改需要保存,您可以通过从 stash 中检出每个单独文件的已知稳定版本来避免丢失这些工作。希望这些文件与您正在处理的文件不同。此外,这也是为什么我们在操作时使用小的提交,以避免出现问题。
git checkout main -- <file_with_conflicts>

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