如何放弃远程更改并将文件标记为“已解决”?

215

我有一些本地文件,从远程分支拉取后出现了冲突。我想保留本地修改并忽略导致冲突的远程修改。是否有一条命令可以实现“标记所有冲突已解决,使用本地文件”的效果?


2
下面的答案对我非常有启发。其中有几个微妙的点子真正帮助我澄清了事情,我建议任何非专家GIT用户都要阅读下面帖子下面的所有评论,感谢Brian! - Tom DeMille
2个回答

365

git checkout--ours选项,可检出您本地拥有的文件版本(与--theirs相对,后者是您拉取的版本)。您可以将.传递给git checkout,以告诉它检出树中的所有内容。然后您需要标记冲突已解决,这可以使用git add完成,并在完成后提交您的工作:

git checkout --ours .  # checkout our local version of all files
git add -u             # mark all conflicted files as merged
git commit             # commit the merge

请注意git checkout命令中的.。这很重要,也容易被忽略。 git checkout有两种模式:一种是切换分支,另一种是将文件从索引中检出到工作副本中(有时会先从另一个版本中将其拉入索引)。它区分的方式是是否传递了文件名;如果没有传递文件名,则尝试切换分支(尽管如果您也没有传递分支,它将尝试再次检查当前分支),但如果有已修改的文件,它将拒绝执行。因此,如果您想要覆盖现有文件的行为,则需要传递.或文件名,以便从git checkout获得第二种行为。
在传递文件名时,使用--来偏移它也是一个好习惯,例如git checkout --ours -- <filename>。如果不这样做,并且文件名恰好与分支或标记的名称匹配,Git将认为您要检查该修订版本,而不是检查该文件名,因此使用checkout命令的第一种形式。
我稍微详细介绍一下Git中冲突和merging的工作原理。当您合并其他人的代码时(这也发生在拉取期间;拉取本质上是一个获取操作,后跟合并操作),有几种可能的情况。

最简单的情况是你们在同一个版本,这时候你已经"更新到最新"了,什么也不会发生。

另一种可能是他们的版本只是你的后代,在这种情况下,你将默认进行"快进合并",即你的HEAD只是更新到他们的提交,没有进行合并(如果你真的想记录合并,则可以使用--no-ff来禁用)。

然后你会遇到需要合并两个版本的情况。在这种情况下,有两种可能的结果。一种是干净地合并,所有更改都在不同的文件中,或者在相同的文件中但足够远,以便两组更改都可以无问题地应用。默认情况下,当进行干净的合并时,它会自动提交,但如果需要事先编辑它(例如,如果您将函数foo重命名为bar,而其他人添加了调用foo的新代码,则会干净地合并,但产生一个损坏的树,因此您可能需要在合并提交的过程中清理它,以避免出现任何损坏的提交)。

最后一种可能是真正的合并,出现了冲突。在这种情况下,Git会尽可能地进行合并,并在您的工作副本中生成带有冲突标记(<<<<<<<=======>>>>>>>)的文件。在索引中(也称为“暂存区”;在提交之前使用git add存储文件的地方),您将拥有每个有冲突的文件的3个版本;存在于两个合并分支祖先的原始文件版本,来自HEAD(合并的一方)的版本以及来自远程分支的版本。
为了解决冲突,您可以编辑位于工作副本中的文件,删除冲突标记并修复代码使其正常工作。或者,您可以使用git checkout --oursgit checkout --theirs检出一个合并双方的版本。一旦您将文件放入所需状态,您可以使用git add指示已完成文件合并并准备好提交,然后可以使用git commit提交合并。

8
请注意,git add --all 将所有文件添加到仓库中,因此除非您的 .gitignore 模式完美无误,否则可能会添加更多文件。在解决合并时,git add -u 可能更适合此情况,因为您不太可能对不想添加的已跟踪的文件进行编辑。 - CB Bailey
1
感谢您详细的回答。我实际上尝试过git checkout --ours并收到了一个错误消息(我现在不记得了)。问题文件是dll(我们有一些需要stash的第三方引用),我想说“好的,我的拷贝是我想要的”,但是错误信息大致是”无法合并时检出“......我会把这篇文章留作参考,下次再尝试一遍看看它是否能正常工作或者我能否发布这个消息。再次感谢! - Tom DeMille
2
你需要执行 git checkout --ours .。注意,. 是很重要的;如果传入一个文件名(在这种情况下是整个目录),则会选择 checkout 的两种不同操作模式之一,一种是切换分支,另一种是将文件从索引移动到工作副本。我同意,这非常令人困惑。你也可以执行 git checkout --ours -- <filename> 逐个检出单个文件。 - Brian Campbell
很好的回答。然而,提问者说:“我有一些本地文件,我从远程分支拉取并且发生了冲突。” 这意味着使用rebase,对吧? 这意味着最后只需要添加已解决的文件,然后使用 --continue 命令即可。我们不在这里提交(commit)。 - Martin Klosi
请注意,在变基(rebase)中,ourstheirs相反的,与您可能想的不同。 - ErikE
显示剩余11条评论

26

请确认冲突的起源:如果这是由于 git merge 引起的,请参见Brian Campbell答案

但如果这是由于 git rebase 引起的,为了放弃远程(他们的)更改并使用本地更改,您需要执行以下操作:

git checkout --theirs -- .

查看"为什么“ours”和“theirs”的含义会被颠倒"",以了解在重新定义基础时如何交换ourstheirs(因为检出了上游分支)。


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