Git: 只有一些未修改但已删除的文件是合并冲突。为什么?
Git: Only some unmodified but deleted files are merge conflicts. Why?
我想了解为什么会这样:
我已经从 master
分支了 mybranch
并进行了几次涉及文件 A
、B
和 C
的提交。与此同时,其他人已将删除文件 X
和 Y
的提交推送到 master
以及一些其他更改。当我将 master
合并到 mybranch
时,git status
告诉我 X
是“未合并的”,而 Y
是“已删除的”。为什么这些文件被区别对待?
我相信这会减少 http://github.com/borglab/SwiftFusion、
现实生活中发生在我身上的事情
[编辑:我弄错了,所以上面的描述是不准确的。不过,@torek 的 非常出色且具有指导意义,所以我不会尝试删除这个问题]
在标签 conflict-merge-source
上有 master
和在标签 conflict-merge-target
上有 mybranch
,但我发布了实际的回购以防我遗漏了什么。这两个文件是Sources/SwiftFusion/Core/FixedShapeTensor.swift
(冲突)和Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift(删除).
TL;DR
如您所述,两个文件之一存在 modify/delete 冲突,而另一个完全没有冲突。两个文件之一没有冲突的原因是合并的“一侧”根本没有触及文件,但另一侧触及了。
对于有冲突的文件,Git 将修改后的文件留在您的 work-tree 中,将冲突留在 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
extended-options 自己必须选择我们的与他们的,而 rename/rename 冲突,如果有冲突,则必须选择要重命名的名称(如果有)。这些 tie-breakers 引入了不对称性。
git merge
如何合并更改
在所有 git merge
的情况下,Git 将 merge base(我们在上面找到的)与每个要合并的提交进行比较。这会将这两个快照中的每一个都变成 changes-since-a-common-starting-point。我们可以使用 git diff
(见上面的例子)找出哪些文件包含什么样的变化。
找到这些更改后,合并代码的工作现在是合并这些更改。在合并的任何“一侧”进行一些更改与在另一“侧”进行 no 更改的组合,是进行大规模更改。大多数这些文件都是这种情况——例如 M
中的所有 22 个文件。所以 git merge
可以只从 更改 文件的那一侧获取文件的副本,在这种情况下。合并的这一部分很简单:有时,合并必须从 merge-base 提交的文件的基本版本开始,然后添加 双方的 更改。
但我们列出了其他八个状态(不是 M
)文件,一侧 7 个,另一侧 1 个:
从底部到一侧有四个 A
个文件(新文件)。它们对另一个没有 same-named 操作,因此合并操作只是将这些新文件视为新文件。
有两个 R
文件。它们位于另一方未触及的不同文件中,因此 Git 仅保留重命名的副本:我们仅获得新名称(如果内容也已更改,则包含新内容);合并基础提交中原始文件的原始副本被完全删除。 (如果合并更难,情况可能并非如此。)
有两个 D
文件,只有一侧。它们是:
D Sources/SwiftFusion/Core/FixedShapeTensor.swift
D Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift
(与您记下的两个相同)。这是我们在 other 端看到的,对于这两个文件:
M Sources/SwiftFusion/Core/FixedShapeTensor.swift
也就是说,第二个文件根本没有出现:它没有被触及。
应该Git如何将“已删除”与“未修改”结合起来? Git的回答是“保留删除”。 应该Git如何将“删除”与“修改”结合起来? Git 的答案是 将修改后的文件保留在 work-tree 中,并在索引 中将文件标记为冲突。这并不总是正确的答案,但如果不是,您可以手动修改索引内容,例如,从 HEAD
或 MERGE_HEAD
.
恢复已删除的文件
最终的合并提交,一旦完成,将包含您 Git 复制到 Git 索引中的所有文件。您的 work-tree 文件副本对 Git 来说并不重要;它们就在那里,以便您可以与它们一起工作。每个文件的索引副本都是 Git 自己的内部压缩和 de-duplicated 形式。
我想了解为什么会这样:
我已经从 master
分支了 mybranch
并进行了几次涉及文件 A
、B
和 C
的提交。与此同时,其他人已将删除文件 X
和 Y
的提交推送到 master
以及一些其他更改。当我将 master
合并到 mybranch
时,git status
告诉我 X
是“未合并的”,而 Y
是“已删除的”。为什么这些文件被区别对待?
我相信这会减少 http://github.com/borglab/SwiftFusion、
现实生活中发生在我身上的事情[编辑:我弄错了,所以上面的描述是不准确的。不过,@torek 的
在标签 conflict-merge-source
上有 master
和在标签 conflict-merge-target
上有 mybranch
,但我发布了实际的回购以防我遗漏了什么。这两个文件是Sources/SwiftFusion/Core/FixedShapeTensor.swift
(冲突)和Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift(删除).
TL;DR
如您所述,两个文件之一存在 modify/delete 冲突,而另一个完全没有冲突。两个文件之一没有冲突的原因是合并的“一侧”根本没有触及文件,但另一侧触及了。
对于有冲突的文件,Git 将修改后的文件留在您的 work-tree 中,将冲突留在 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
extended-options 自己必须选择我们的与他们的,而 rename/rename 冲突,如果有冲突,则必须选择要重命名的名称(如果有)。这些 tie-breakers 引入了不对称性。
git merge
如何合并更改
在所有 git merge
的情况下,Git 将 merge base(我们在上面找到的)与每个要合并的提交进行比较。这会将这两个快照中的每一个都变成 changes-since-a-common-starting-point。我们可以使用 git diff
(见上面的例子)找出哪些文件包含什么样的变化。
找到这些更改后,合并代码的工作现在是合并这些更改。在合并的任何“一侧”进行一些更改与在另一“侧”进行 no 更改的组合,是进行大规模更改。大多数这些文件都是这种情况——例如 M
中的所有 22 个文件。所以 git merge
可以只从 更改 文件的那一侧获取文件的副本,在这种情况下。合并的这一部分很简单:有时,合并必须从 merge-base 提交的文件的基本版本开始,然后添加 双方的 更改。
但我们列出了其他八个状态(不是 M
)文件,一侧 7 个,另一侧 1 个:
从底部到一侧有四个
A
个文件(新文件)。它们对另一个没有 same-named 操作,因此合并操作只是将这些新文件视为新文件。有两个
R
文件。它们位于另一方未触及的不同文件中,因此 Git 仅保留重命名的副本:我们仅获得新名称(如果内容也已更改,则包含新内容);合并基础提交中原始文件的原始副本被完全删除。 (如果合并更难,情况可能并非如此。)有两个
D
文件,只有一侧。它们是:D Sources/SwiftFusion/Core/FixedShapeTensor.swift D Tests/SwiftFusionTests/Core/FixedShapeTensorTests.swift
(与您记下的两个相同)。这是我们在 other 端看到的,对于这两个文件:
M Sources/SwiftFusion/Core/FixedShapeTensor.swift
也就是说,第二个文件根本没有出现:它没有被触及。
应该Git如何将“已删除”与“未修改”结合起来? Git的回答是“保留删除”。 应该Git如何将“删除”与“修改”结合起来? Git 的答案是 将修改后的文件保留在 work-tree 中,并在索引 中将文件标记为冲突。这并不总是正确的答案,但如果不是,您可以手动修改索引内容,例如,从 HEAD
或 MERGE_HEAD
.
最终的合并提交,一旦完成,将包含您 Git 复制到 Git 索引中的所有文件。您的 work-tree 文件副本对 Git 来说并不重要;它们就在那里,以便您可以与它们一起工作。每个文件的索引副本都是 Git 自己的内部压缩和 de-duplicated 形式。