问题描述
我试图了解为什么会发生这种情况:
我从 mybranch
分支了master
,并进行了几次提交,这些提交涉及文件A
,B
和C
。同时,其他人已将master
和X
以及其他一些更改一起提交到Y
的提交中。当我将master
合并到mybranch
中时,git status
告诉我X
被“取消合并”,Y
被“删除”。为什么对这些文件进行不同的处理?
我相信,这是为了减少现实生活中http://github.com/borglab/SwiftFusion上发生的事情,
[编辑”:我对此有误,因此上面的描述不准确。 @torek的answer很好而且很有启发性,所以我不会尝试删除此问题]
在标签{{1}处有master
,在标签conflict-merge-source
处有mybranch
,但是我会发布实际的仓库,以防万一。这两个文件是conflict-merge-target
(冲突)和Tests / SwiftFusionTests / Core / FixedShapeTensorTests.swift(已删除)。
解决方法
TL; DR
两个文件之一存在修改/删除冲突,而另一个文件根本没有冲突。这两个文件之一没有冲突的原因是,合并的“一侧”根本没有碰到文件,而另一侧完全没有碰到。
对于有冲突的文件,Git会将修改后的文件保留在工作树中,并将冲突保留在Git的索引中,您必须在其中解决它。 如何解决该问题取决于您,但是如果解决方案是“保留删除”,则可以在该名称上使用git rm
,如果要保留修改后的文件,则可以使用git add
。无论哪种方式,Git的 index (建议的 next 提交)现在都可以更新,并且可以解决此特殊冲突。
长
我克隆了the repository in question并发现了以下内容:
$ git merge-base --all conflict-merge-source conflict-merge-target
a07af749bdd416c5217c363b3f1da509c58d2d14
$ base=$(git merge-base --all conflict-merge-source conflict-merge-target)
$ git diff --find-renames --name-status $base conflict-merge-source
M Sources/BeeDataset/BeeFrames.swift
M Sources/SwiftFusion/Core/DataTypes.swift
D Sources/SwiftFusion/Core/FixedShapeTensor.swift
M Sources/SwiftFusion/Core/MathUtil.swift
A Sources/SwiftFusion/Core/TensorVector.swift
M Sources/SwiftFusion/Image/OrientedBoundingBox.swift
A Sources/SwiftFusion/Inference/AppearanceTrackingFactor.swift
M Sources/SwiftFusion/Inference/FactorGraph.swift
M Sources/SwiftFusion/Inference/FactorsStorage.swift
M Sources/SwiftFusion/Inference/JacobianFactor.swift
A Sources/SwiftFusion/Inference/PPCA.swift
M Sources/SwiftFusion/Inference/PPCATrackingFactor.swift
M Sources/SwiftFusion/Optimizers/CGLS.swift
M Sources/SwiftFusion/Optimizers/LM.swift
M Sources/SwiftFusionBenchmarks/Patch.swift
M Tests/BeeDatasetTests/BeeDatasetTests.swift
A Tests/BeeDatasetTests/BeePPCATests.swift
D Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift
M Tests/SwiftFusionTests/Image/PatchTests.swift
M Tests/SwiftFusionTests/Inference/FactorGraphTests.swift
R062 Tests/SwiftFusionTests/Inference/PPCATrackingFactorTests.swift
Tests/SwiftFusionTests/Inference/PPCATests.swift
M Tests/SwiftFusionTests/Inference/SwitchingMCMCTests.swift
M Tests/SwiftFusionTests/Optimizers/LMTests.swift
$ git diff --find-renames --name-status $base conflict-merge-target
M Sources/SwiftFusion/Core/FixedShapeTensor.swift
M Sources/SwiftFusion/Inference/AnyArrayBuffer+Differentiable.swift
R050 Sources/SwiftFusion/Inference/ValuesStorage.swift
Sources/SwiftFusion/Inference/AnyArrayBuffer+Vector.swift
M Sources/SwiftFusion/Inference/ArrayBuffer+Differentiable.swift
M Sources/SwiftFusion/Inference/ArrayBuffer+Vector.swift
M Sources/SwiftFusion/Inference/PenguinExtensions.swift
M Tests/SwiftFusionTests/Inference/AnyArrayBufferTests.swift
请注意R062
和R050
行:Git检测到,由于合并基本提交$base
(a07af749...
),这些文件在两个选定的提交中被重命名。在这里,这实际上并不是很重要,但是它们很长,我将它们分开用于发布目的。
我不完全确定您已检出两个提交中的哪个作为分支,以及您使用git merge
命令选择了哪个,但是由于合并过程主要是对称的,因此 1 并不重要。
我们可以使用一个分离的HEAD进行合并,但是我希望拥有一个分支名称,因此我现在创建了一个分支名称:
$ git checkout -b t1 conflict-merge-source
Switched to a new branch 't1'
$ git merge conflict-merge-target
CONFLICT (modify/delete): Sources/SwiftFusion/Core/FixedShapeTensor.swift
deleted in HEAD and modified in conflict-merge-target. Version
conflict-merge-target of Sources/SwiftFusion/Core/FixedShapeTensor.swift
left in tree.
Automatic merge failed; fix conflicts and then commit the result.
(再次,我为了发布目的将一行长长的一行。)
1 任何不对称性都是将一个提交视为“我们的”而将另一个提交视为“其”的结果。例如,-X
扩展选项本身必须选择我们的与他们的,而重命名/重命名冲突(如果有)必须选择要采用的重命名(如果有)。这些决胜局引入了不对称性。
git merge
如何合并更改
在所有使用git merge
的情况下,Git都会将合并基础(我们在上面找到)与要合并的每个提交进行比较。由于一个共同的起点,这两个快照中的每一个都变成了更改。我们可以使用git diff
(请参见上面的示例)来找出哪些文件包含哪些更改。
找到这些更改后,合并代码的工作就是组合更改。在合并的任一“侧”进行一些更改与在另一“侧”进行无更改的组合,是要批量进行更改。大多数此类文件就是这种情况,例如M
中的全部22个文件。因此,在这种情况下,git merge
可以从更改了文件的任何一方获取文件的副本。合并的这一部分很容易:有时,合并必须从merge-base提交开始,以文件的基本版本开始,并向其添加两面的更改。
但是我们列出了其他八种状态文件(不是M
),一侧是7,另一侧是1:
-
从基础到一侧有四个
A
文件(新文件)。它们彼此之间没有同名操作,因此合并操作只是将这些新文件作为新文件。 -
有两个
R
文件。它们位于另一侧没有接触的不同文件上,因此Git保留了重命名的副本:我们仅获得新名称(如果内容也被更改,则具有新内容);合并基本提交中原始文件的原始副本被完全删除。 (如果合并比较困难,则可能不是这种情况。) -
有两个
D
文件,仅在一侧。这些是:D Sources/SwiftFusion/Core/FixedShapeTensor.swift D Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift
(您提到的两个)。这是我们在 other 端针对这两个文件看到的内容:
M Sources/SwiftFusion/Core/FixedShapeTensor.swift
也就是说,第二个文件根本没有出现:没有被触摸。
Git如何将“已删除”与“未修改”结合在一起? Git的答案是“保留删除”。 Gem应该如何将“已删除”与“已修改”结合在一起? Git的答案是将修改后的文件保留在工作树中,并将该文件标记为在索引中冲突。这并不总是正确的答案,但是如果不是,您可以手动处理索引内容,例如从HEAD
或MERGE_HEAD
恢复已删除的文件。
完成合并后,最终合并提交将包含Git复制到Git索引中的所有文件。文件的工作树副本对Git并不重要。他们就在那里,以便您可以与他们合作。每个文件的索引副本都采用Git自己的内部压缩和重复数据删除格式。