使用Git解决二进制文件冲突

573

我一直在Windows上使用Git(msysgit)来跟踪我正在做的一些设计工作的更改。

今天,我在另一台电脑上工作(使用远程repo brian),现在我正在尝试将今天所做的修改合并回到我的笔记本电脑上的常规本地版本中。

在我的笔记本电脑上,我使用了git pull brian master命令将更改拉入到本地版本中。除了主要的InDesign文档之外,一切都很好 - 这个文件显示为冲突。

PC上的版本 (brian) 是我想要保留的最新版本,但我不知道哪个命令可以让repo使用它。

我尝试将文件直接复制到我的笔记本电脑上,但这似乎破坏了整个合并过程。

有人能指点我正确的方向吗?

12个回答

1043

git checkout 命令可以接受 --ours 或者 --theirs 选项来处理类似这种情况。所以,如果你遇到了合并冲突,并且你知道你只需要使用正在合并的那个分支中的文件,你可以执行以下操作:

$ git checkout --theirs -- path/to/conflicted-file.txt

要使用该文件的版本。同样地,如果您知道您需要的是您自己的版本(而不是正在合并的版本),您可以使用

$ git checkout --ours -- path/to/conflicted-file.txt

67
在使用--ours之前,我必须对路径为path/to/conflicted-file.txt的文件运行“git reset HEAD”命令,否则看起来它没有任何作用。这个命令不会改变原始含义,只是做了一些语言上的调整以使其更通俗易懂。 - Zitrax
7
在运行 git checkout --ours 后,你是否对文件进行了差异比较?根据 man 页面的建议(我个人认为),checkout --ours/--theirs 将会从“both modified, need merge”列表中移除更改,并将其添加到索引中,但我认为这并不正确。我相信你需要在 checkout 后运行 git add - Tim Keating
18
请注意:你仍然需要执行“git add 有冲突的文件.txt”和“git commit”的操作。方便的是,在我尝试时,提交信息预先填写了有关冲突的注释。 - Edward Falk
5
“the branch you are merging in”这种措辞与“the branch you are merging into”非常相似,我认为只需要省略介词会更好:“the branch you are merging”,这也能反映出Git命令(即 git merge branch_name)。请注意,我的翻译会尽力保持原意并使内容更加通俗易懂,但不包含解释和其他额外信息。 - andrybak
20
在解释这个主题时通常会遗漏一些重要的要点。当进行变基(rebase)而不是合并(merge)时,“--their”和“--ours”的含义会交换,即“--their”表示当前检出的分支,而“--ours”则表示你要合并到当前分支中的分支(通常是远程分支或路径规范)。“[空格]--[空格]”选项用于区分同名的分支名和路径规范之间的路径规范(例如,已存在一个分支名为“abc”,并且一个名为“abc”的目录也存在)。 - BoiseBaked
显示剩余6条评论

156

你需要手动解决冲突(复制文件),然后像这样提交文件(无论是复制还是使用本地版本)

git commit -a -m "Fix merge conflict in test.foo"

在合并时,Git通常会自动提交,但当它检测到无法自行解决的冲突时,它会应用所有已确定的补丁,并留下其余的供您手动解决和提交。有关Git如何工作的详细信息,请参阅Git Merge文档页面Git-SVN Crash Course博客文章。

编辑:请参见下面的帖子,您实际上不必自己复制文件,而是可以使用

git checkout --ours -- path/to/file.txt
git checkout --theirs -- path/to/file.txt

要选择您想要的文件版本。只有在您需要混合使用两个版本时,才需要复制/编辑该文件。

请将 mipadis 的答案标记为正确答案。


1
谢谢。我不确定是否有一种内置的方法来标记一个文件为“正确”的文件。这就解释了为什么我找不到不存在的命令! - Kevin Wilson
是的,这有点不直观 - 像 git resolve 这样的东西会很好,但也会是一个额外的步骤... - VolkA

129

您还可以通过以下方式解决这个问题

git mergetool

这将导致 git 在本地创建有冲突的二进制文件的副本,并在它们上面启动您的默认编辑器:

  • {conflicted}.HEAD
  • {conflicted}
  • {conflicted}.REMOTE

显然,您无法在文本编辑器中有用地编辑二进制文件。相反,您可以将新的 {conflicted}.REMOTE 文件复制到未关闭的编辑器中的 {conflicted} 文件上。然后当您关闭编辑器时,git 将会发现未装饰的工作副本已更改,您的合并冲突将以通常的方式得到解决。


12
如果文件很大或您不想冒险在文本编辑器中打开二进制文件,您可以在合并工具提示符处按ctrl+c(“按回车键启动合并冲突解决工具”),git会将额外的文件保留在原地。然后,您可以在外部工具中修改或合并它们(对于像LibreOffice / OpenOffice / MSWord这样的二进制文档格式非常有用),并将结果保存回原始文件名。要告诉git已经解决了冲突,请使用 git add 命令添加原始文件名,然后您可以完成合并提交。 - Felix
这对我来说完美无缺地运作了。谢谢! - Stephan Kristyn

23

若要通过保留当前分支的版本(忽略合并进来的分支中的版本)来解决问题,只需添加并提交该文件:

git commit -a

要通过覆盖当前分支中的版本以从正在合并的分支中获取版本来解决问题,您需要首先将该版本检索到工作目录中,然后再添加/提交:

git checkout otherbranch theconflictedfile
git commit -a

更详细的解释


1
我更喜欢这种变体,因为它更直观,特别是考虑到在变基的情况下,“--ours”和“--theirs”的含义被交换了。 - Antony Hatchkins

17

mipadi的答案对我没有起作用,我需要这样做:

git checkout --ours path/to/file.bin

或者,为了保留正在合并的版本:

git checkout --theirs path/to/file.bin

然后

git add path/to/file.bin

之后,我可以再次运行"git mergetool"并继续处理下一个冲突。


6

来自git checkout文档

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
当从索引中检出路径时,检出未合并路径的第2个(ours)或第3个(theirs)阶段。

由于之前的合并失败,索引可能包含未合并的条目。默认情况下,如果您尝试从索引中检出这样的条目,则检出操作将失败,并且不会检出任何内容。使用-f将忽略这些未合并的条目。可以使用--ours--theirs从索引中检出合并的特定侧面的内容。使用-m,可以放弃对工作树文件所做的更改,以重新创建原始的冲突合并结果。


5

我曾遇到类似问题(想要拉取一个包含某些二进制文件的提交,在合并时引起冲突),但是我找到了一种完全可以使用git解决的不同方法(即无需手动复制文件)。 我觉得我应该在这里包括它,这样至少下次需要时我能记住它。 :) 步骤如下:

% git fetch

此命令可从远程代码库获取最新的提交(根据您的设置,您可能需要指定远程分支名称),但不会尝试合并它们。它将该提交记录在FETCH_HEAD中。
% git checkout FETCH_HEAD stuff/to/update

这个命令会获取我想要的二进制文件副本,并用从远程分支获取的版本覆盖工作树中的内容。Git不会尝试进行任何合并,因此您最终得到的是从远程分支获取的二进制文件的精确副本。完成后,您可以像正常情况下一样添加/提交新副本。


4

此过程是为了解决在您向Github提交拉取请求后发现二进制文件冲突的问题:

  1. 在Github上,您发现您的拉取请求在一个二进制文件上存在冲突。
  2. 现在回到本地计算机上的相同git分支。
  3. 您需要(a)重新制作/重建此二进制文件,并(b)将生成的二进制文件提交到相同的git分支。
  4. 然后再次将这个相同的git分支推送到Github。

在Github上,您的拉取请求中的冲突应该会消失。


1
我遇到了两种在Windows上使用Git管理二进制文件的策略。
  1. Tortoise git允许您根据文件扩展名配置不同的diff/merge工具。请参见2.35.4.3. Diff/Merge高级设置http://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html。当然,这种策略依赖于适当的diff/merge工具的可用性。

  2. 使用git属性,您可以指定一个工具/命令将您的二进制文件转换为文本,然后让默认的diff/merge工具处理。请参见http://git-scm.com/book/it/v2/Customizing-Git-Git-Attributes。该文章甚至给出了使用元数据对图像进行差异比较的示例。

我已经使用这两种策略来管理软件模型的二进制文件,但我们选择了Tortoise git,因为配置很容易。

1
如果二进制文件不仅仅是dll,或者可以像图像或混合文件一样直接编辑(而且您不需要垃圾桶/选择其中一个文件),那么真正的合并应该是这样的:
我建议寻找一个适用于您的二进制文件的差异工具,例如,有一些免费的用于图像文件的工具,例如:
- npm install -g imagediff IIRC from https://github.com/uber/image-diff - 或者 python https://github.com/kaikuehne/mirror.git - 还有其他工具可供选择。
然后进行比较。
如果没有比较文件的 diff 工具,那么如果你有二进制文件的原始生成器(也就是说,存在一个编辑器,例如 blender 3D),那么你可以手动检查这些文件,查看日志,并询问其他人应该包含什么内容。然后使用 https://git-scm.com/book/es/v2/Git-Tools-Advanced-Merging#_manual_remerge 输出这些文件。
$ git show :1:hello.blend > hello.common.blend
$ git show :2:hello.blend > hello.ours.blend
$ git show :3:hello.blend > hello.theirs.blend

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