Git存储错误:使用git stash pop命令导致合并冲突。

203

我执行了一个 git stash pop 命令,结果出现了合并冲突。我从文件系统中删除了这些文件,并像下面这样执行了一个 git checkout 命令,但是 Git 认为这些文件仍然没有合并。接着我尝试替换这些文件并再次执行 git checkout 命令,但结果相同。我甚至使用了 -f 标志来强制执行。如果有任何帮助,将不胜感激!

chirag-patels-macbook-pro:haloror patelc75$ git status
app/views/layouts/_choose_patient.html.erb: needs merge
app/views/layouts/_links.html.erb: needs merge
# On branch prod-temp
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   db/schema.rb
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       unmerged:   app/views/layouts/_choose_patient.html.erb
#       unmerged:   app/views/layouts/_links.html.erb

chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged

注意:自 Git 2.5(2015 年第二季度)起,恢复 git stash apply/pop 前的状态应该更容易了,因为现在工作树需要保持干净:请参见我的下面的回答 - VonC
5个回答

222

查看man git merge如何解决冲突):

在发现冲突后,您可以做两件事:

  • 决定不合并。您需要执行的唯一清理操作是将索引文件重置为HEAD提交以撤消2.,并清理由2.和3.产生的工作树更改;可以使用git-reset --hard进行此操作。

  • 解决冲突。Git会在工作树中标记冲突。编辑文件并将其添加到索引中。使用git commit完成操作。

真正的合并下(查看2.和3.指的是什么):

当不明显如何协调更改时,会发生以下情况:

  1. HEAD指针保持不变。

  2. MERGE_HEAD ref被设置为指向其他分支头。

  3. 已经干净地合并的路径会同时更新索引文件和您的工作树。

  4. ...

因此:如果您想要从工作树中删除存储更改,请使用git reset --hard,或者如果您只想清理索引并将冲突留在工作树中手动合并,请使用git reset

man git stash (选项, pop) 下,您还可以阅读以下内容:

应用状态可能会因冲突而失败;在这种情况下,它不会从存储列表中删除。您需要手动解决冲突,并随后手动调用 git stash drop 命令。


9
实际上,即使您删除了一个暂存区,仍然有可能(尽管更加困难)再次检索它,因为变更集仍存在于代码库中。请参考http://stackoverflow.com/search?q=git+recover+dropped+stash。 - phils
3
@nalply: 这是好事还是坏事?如果你一开始没明白我的回答,欢迎你进行改进... - tanascius
1
我认为源代码版本控制是一个复杂的问题领域。很容易混淆。尽管如此,我仍然认为你的回答很好,因为它重新确认了我的方法。 - nalply
1
这不仅让我意识到stash并没有像我以为的那样被删除,而且这也解释了为什么即使我确信没有忘记从stash中取出物品,我的stash仍然不断增加。 - Vala
12
“应用状态可能会失败并出现冲突;在这种情况下,它不会从存储列表中移除。” 这是我认为本文中最重要的部分。考虑编辑您的答案,在此处与“别惊慌”这几个词一起用友好的大字体突出显示。 (已有+1赞,感谢) - Patrick M
显示剩余3条评论

45

我遇到了类似的情况。当时我不想立即提交文件,所以使用了git add将它们添加,然后执行了git reset。这基本上只是添加了我的更改,但是取消了暂存,并清除了未合并的路径。


4
这个方法似乎比使用“reset --hard”更好,因为它不会覆盖你的文件(除了存在合并问题的文件)。谢谢! - sinelaw
我还不想暂存这些文件,所以我只是把它们添加了进来。-- add 命令不是将工作树中的内容暂存到索引中吗?从描述中我不太明白你的回答为什么有效。 - Drew Noakes
2
"git add" 会将它们加入暂存区,但是我马上执行的 "git reset" 将它们移出暂存区。实质上,通过这种方式清除未合并的路径,并且模拟 git 的行为将我返回到正常的工作目录。 - Aaron
3
如果您要执行 git reset,则无需进行 git add 操作。git reset 实际上是撤消了 git add 的操作。git reset(默认选项为 --mixed) 不会对工作目录造成任何影响,因此您的工作目录中所有内容,包括合并冲突等都将保持不变。但是,索引(index)和分支头将被重置(如果没有指定引用,则它们将被重置回 HEAD)。这可能意味着分支头没有更改,同时也会撤消对索引的任何 git add 操作,并清除未合并路径的状态。 - bambams
3
"sequence","edit/resolve","git reset"和"github stash drop"组合使用非常有效。它能够像“git stash pop”一样无冲突地完成任务。似乎不需要使用“git add”,但如果有许多文件存在冲突,则可能会有用。解决每个文件的冲突后,可以将其添加并使用“git status”进行跟踪。 - artless noise

14

如果像我一样,您通常希望用暂存文件的内容覆盖工作目录的内容,并且仍然出现冲突,则您需要使用git checkout --theirs -- .来解决冲突。

完成后,您可以使用git reset将所有更改从索引中带入工作目录,因为在发生冲突的情况下,对于未发生冲突的文件的更改会留在索引中。

您可能还想运行git stash drop [<stash name>],以摆脱暂存,因为在冲突的情况下git stash pop不会删除它。


2
请注意,Git 2.5(2015年第二季度)未来的Git可能会尝试使这种情况不可能发生。
请参见commit ed178efJeff Kingpeff)于2015年4月22日提交。(由Junio C Hamano -- gitster -- 合并于commit 05c3967,2015年5月19日) 注意:这已被撤销,请参见下文。

stash:需要清洁的索引才能应用/弹出

问题

如果您在索引中分阶段地存储了内容并运行“stash apply/pop”,我们可能会遇到冲突并将新条目放入索引中。在那一点上,恢复到原始状态是困难的,因为诸如“git reset --keep”之类的工具将清除任何已经分阶段的内容。
换句话说:“git stash pop/apply”忘记确保不仅工作树干净,而且索引也干净。后者很重要,因为存储应用程序可能会发生冲突,索引将用于解决冲突。
解决方案:
我们可以通过拒绝在存在分阶段更改时应用来使这更加安全。这意味着,如果之前由于在修改的文件上应用存储(已添加但未提交)而导致合并,现在就不会有任何合并,因为存储应用/弹出将立即停止。
Cannot apply stash: Your index contains uncommitted changes.

强制你提交更改意味着,在合并的情况下,你可以通过使用 git reset --hard 轻松恢复最初状态(即执行 git stash apply/pop 之前的状态)。
参见提交 1937610(2015年6月15日)和提交 ed178ef(2015年4月22日),作者为Jeff King(peff
(由Junio C Hamano -- gitster --提交 bfb539b中合并,于2015年6月24日) 这个提交是为了提高应用存储的安全性,因为应用过程可能会创建冲突的索引条目,难以恢复原始的索引状态。不幸的是,这会影响一些常见的工作流程,比如“git stash -k”等。
git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

如果在步骤(3)和(4)之间执行“git commit”,那么它就可以正常工作。但是,如果这些步骤是预提交钩子的一部分,您就没有这个机会(无论测试是否通过,都必须恢复原始状态)。

1
git restore --staged  name-of-file-that-has--merge-conflict

这似乎是一个有用的替代方案,但可以添加一个介绍来解释这具体有什么影响吗?有几个选项可能是需要的,而这个选项并不总是正确的。 - joanis

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