TL;DR
您将需要git add 最终分辨率,除非您使用不同的方法来提取“我们的”或“他们的”版本。
长
每个合并工具都独立于 Git(Git 只是运行它们并让它们做自己的事情),因此对于这个问题的特定子部分,您必须咨询合并工具本身。
至于git checkout --ours 或git checkout --theirs,这就是Git 所称的索引 显示其全部复杂性的地方。请记住,索引,否则有点神秘,也称为 暂存区,有时也称为 缓存,本质上是您和 Git 构建 next 的地方提交你会做的。
当你运行时:
git merge <commit-or-branch-specifier>
Git 发现 三个 提交:
- 一个是您的当前提交,它是您在任何给定时间一直使用的那个,所以这并不特别,除了您可以通过名称
HEAD 来引用它或单个字符 @(例如,git rev-parse HEAD 或 git rev-parse @ 以获取其哈希 ID)。
- 一个是您刚刚命名的提交。如果您运行了
git merge otherbranch,您可以运行git rev-parse otherbranch 来查看它的提交哈希ID 现在是什么。 (分支名称具有 moving: 的属性,即现在由分支名称标识的提交不一定是昨天或明天由该名称标识的提交。分支名称的这种运动是如何分支增长。)当然,如果您运行 git merge a123456,另一个提交,即 --theirs 的提交,是哈希 ID a123456。
- 最后一次提交是 merge base,Git 会自动为您找到。它通过使用来自您的提交和另一个提交的父链接来找到此提交,通过两个分支向后工作,直到找到两个分支首先重新组合在一起的适当点。
找到三个提交后,Git 运行,生效:
git diff --find-renames <merge-base> <ours> # see what we changed
git diff --find-renames <merge-base> <theirs> # see what they changed
合并过程——合并 就像一个动词一样——包括查找这三个提交、进行 diff 以及合并更改。当两组更改影响相同的行时,您会遇到合并冲突。
在没有合并冲突的文件中,Git 将结果放入您的工作树(作为普通文件)和索引(作为文件的特殊 Git 形式,准备提交)。因此,对于不冲突的文件,您通常无需执行任何其他操作。
但是,当发生合并冲突时,Git 会做两件不寻常的事情:首先,它将合并冲突的版本写入工作树,以便您可以将其作为纯文件进行编辑。其次,它写入索引,而不是文件的一个版本,而是所有三个:合并基础版本、“我们的”版本和“他们的”版本.
Git 将这些额外的版本称为更高的阶段。阶段号是合并基数,没有--base 选项可以访问它,但您可以使用git show :1:<em>path</em> 来查看它。第二阶段是“我们的”版本:有--ours,但您也可以运行git show :2:<em>path</em> 来查看它。第 3 阶段是“他们的”版本,可通过git show :3:<em>path</em> 获得。这三个阶段替换正常的阶段零条目,现在缺少。
实际上,当您运行git mergetool 时,它所做的就是在索引中找到三个版本,将它们提取到常规(非 Git 化)文件中,然后对这三个文件运行实际的合并工具。假设合并工具做正确的事(无论结果如何)将三个文件合并为一个合并文件,之后git mergetool 可以在结果上运行git add。
不过,从命令行——这就是我的合并方式——你可以编辑工作树文件及其冲突标记,并找出正确的结果是什么。写出来,git add 结果文件,你很好,因为git add 注意到文件以三阶段版本形式存在并删除这三个版本,而是写入阶段编号为零。
一旦有阶段 0(不再是阶段 1-3),文件就被认为已解决。
现在,git checkout --ours -- <em>path</em> 只是告诉 Git:从索引中取出 stage-2 版本并将其放入工作树中。 带有--theirs 的版本告诉 Git 上台-3 版本。在这两种情况下,索引及其三个分阶段的版本都被单独留下。这only 从索引中提取到工作树。 (这里的-- 是为了以防 path 部分是一个名为 --theirs 的文件。如果文件名与选项不同,则不需要--。一直使用-- 是一种好习惯,但大多数人不这样做。)
由于索引仍然具有所有三个暂存版本,因此该文件尚未解析。运行 git add 获取工作树文件并将其放入插槽 0,清除 1 到 3 条目,现在文件已解析。
奇怪的是,运行 git checkout HEAD -- <em>path</em> 或 git checkout <em>otherbranch</em> -- <em>path</em> 会导致文件被解析。这是 Git 让实现决定接口的工件:在内部,当您使用 git checkout <em>name</em> -- <em>path</em> 时,Git 必须首先在给定的 name 中找到文件的 Git 形式(提交哈希或HEAD 或 otherbranch 之类的名称)。然后它必须 复制 Git 表单 into 索引......并且这种复制会清除插槽 1-3 条目,写入正常的插槽零条目。最后,Git 然后将(Git-form)文件从索引条目 0 提取到工作树。
这种“先写入索引,然后从索引提取到工作树”的副作用是,如果文件处于冲突状态(阶段 1-3 处于活动状态),则不再发生冲突!因此:
git checkout --ours -- file
不解析文件(因为它从索引槽 2 中提取),但是:
git checkout HEAD -- file
是否解析文件(因为它从当前提交中提取,进入索引插槽 0,清除 1-3;然后从插槽 0 条目中提取它刚刚写的)。