Git:只有一些未修改但已删除的文件是合并冲突.为什么



我正在努力理解为什么会发生这种情况:

我已经从master分支了mybranch,并进行了几个涉及文件ABC的提交。同时,其他人向master推送了一个提交,该提交删除了文件XY以及一些其他更改。当我将master合并到mybranch时,git status告诉我X"未合并",Y"已删除"。为什么这些文件会有不同的处理

我相信这会减少我在现实生活中发生的事情http://github.com/borglab/SwiftFusion,

[编辑:我错了,所以上面的描述不准确。@torek下面的回答很好,很有启发性,所以我不会试图删除这个问题]

master在标签conflict-merge-sourcemybranch在标签conflict-merge-target,但我会发布实际的回购,以防我错过了什么。这两个文件是Sources/SwiftFusion/Core/FixedShapeTensor.swift(冲突)和Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift(已删除)。

TL;DR

正如您所指出的,这两个文件中的一个存在修改/删除冲突,而另一个根本没有冲突。两个文件中的一个没有冲突的原因是;侧面";合并的一方根本没有接触到文件,但另一方接触到了。

对于有冲突的文件,Git会将修改后的文件留在您的工作树中,并将冲突留在Git的索引中,您必须在索引中解决它;保持删除";您可以在该名称上使用git rm,如果要保留修改后的文件,则可以使用git add。无论哪种方式,Git的索引——建议的next提交——现在都被更新了,并且这个特定的冲突得到了解决。

Long

我克隆了有问题的存储库,发现了以下内容:

$ 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

请注意R062R050行: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(参见上面的示例)来找出哪些文件包含哪些类型的更改。

发现这些更改后,合并代码的工作现在是合并这些更改。对";侧面";在合并的另一个上使没有改变的情况下;"侧";,就是全盘接受零钱。这些文件中的大多数都是这种情况——例如,所有22个M文件。因此,在这种情况下,git merge可以从更改文件的任何一侧获取文件的副本。合并的这一部分很容易:有时,合并必须从合并基本提交的文件的基本版本开始,并将双方的更改添加到其中。

但我们列出了其他八个状态文件(不是M),其中7个在一侧,1个在另一侧:

  • 从底部到一侧有四个A文件(新文件)。这些文件在另一个文件上没有相同的命名操作,所以合并操作只是将这些新文件作为新文件。

  • 有两个R文件。它们位于另一方没有接触的不同文件上,因此Git只保留重命名后的副本:我们只获得新名称(如果内容也发生了更改,则会有新内容);合并基提交中原始文件的原始副本将被完全删除。(如果合并更加困难,情况可能并非如此。)

  • 有两个D文件,仅在一侧。这些是:

    D       Sources/SwiftFusion/Core/FixedShapeTensor.swift
    D       Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift
    

    (和你提到的一样)。以下是我们在另一个侧看到的内容,用于这两个文件:

    M       Sources/SwiftFusion/Core/FixedShapeTensor.swift
    

    也就是说,第二个文件根本没有出现:它没有被触摸。

应该如何Git组合"删除";用";未被触及";?Git的回答是";保持删除";。应该如何Git组合"删除";用";修改的";?Git的答案是将修改后的文件保留在工作树中,并在索引中将该文件标记为冲突。这并不总是正确的答案,但如果不是,您可以手动调整索引内容,例如,从HEADMERGE_HEAD恢复已删除的文件。

最终的合并提交一旦完成,将包含Git复制到Git索引中的任何文件。文件的工作树副本对Git来说并不重要;他们就在那里,这样你就可以和他们一起工作了。每个文件的索引副本都是Git自己的内部压缩和消除重复的形式

最新更新