Git 由 Git “建议 [文件] 应该移动”引起的文件级合并冲突

Git file-level merge conflict caused by Git “suggesting [the file] should perhaps be moved”

我有一个 Git Markdown 文章回购,人们在其中创建拉取请求(每篇 Markdown 文章一个),最终合并到 master,然后直接在 master,我将该文章移动到名为 wordpressed 的文件夹中,然后提交并推送到 master.

我有一个非常古老的拉取请求,它仍然存在于一个名为 home-base 的分支中,由一个文件 dan/homebase.md 我正在考虑通过更多提交进行编辑,然后合并到 master.

这个 home-base 分支 旧了,从它的角度来看,回购与今天在 master 中的样子完全不同.因此,我认为将 master 反向合并到 home-base 中可能会更好,只是为了使其更新并使合并基础向上移动很多。

但是当我尝试这样做时,我遇到了无法理解的合并冲突。


为了向您展示情况,我将展示 ls 个文件和文件夹在每个分支中的样子。我将从 master:

开始
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean

$ ls -1 -R
README.md
dan
instructions.md
wordpressed

./dan:

./wordpressed:
AppDelegateRefactor.md
BareListContentView.md
CellContentConfiguration.md
ControlTargetActioniOS14.md
GetStartedWithPods.md
MultipleTrailingClosures.md
StatesAndBackgrounds.md
Swift52notes1.md
Swift52notes2.md
Swift52notes3.md
UserInteractiveCells.md
bdd-common-pitfalls.md
bdd.md
brantsMenuBar.md
collectionViewContentConfig.md
collectionViewLists.md
collectionViewLists2.md
collectionViewOutline.md
debuggingLinks.md
diffableDataSources.md
diffableDataSources2.md
forwardCompatibity.md
haptics.md
iOS13deprecations.md
images
inAppPurchases.md
logging.md
miscSwiftTricks1.md
miscSwiftTricks2.md
miscSwiftTricks3.md
miscSwiftTricks4.md
multipleSelection.md
mysteriesOfLayout.md
newInIOS14.md
packages.md
photoPicker.md
protocolParadox.md
splitViewControllers.md
splitViewControllers2.md
swiftTrickTwoClasses.md
targetActionRant.md
typescript-shape-of-things.md
untappableButton.md
what-vs-how.md
xcode12Editing.md
xcode12testing.md
xcodeWhereAmI.md
xcodeWorkInTwoPlaces.md

./wordpressed/images:
argumentsInScheme.png
bigFlags.png
callHierarchy.png
callersMenu.png
chooser.png
config.png
createdTester.png
dataOrUrl.png
ipadportraitoverlay.png
listOfPepBoys.png
listWithSectionHeaders.png
littleFlags.png
looksLikeADuck.png
newTester.png
outlineIndicatorsWrong.png
outlineIndicatorsWrong2.png
perfectAfterHack.png
pickAPeppa.png
rootOnly.png
sandboxAccountOnDevice.png
selfSizingStringDrawer.png
simpleList.png
split1.png
split2.png
splitViewControllerPadLandscape.png
tableViewAsChoice.png
threecolumns.png
twoPossibilities.png
twoscreensphone.png
variableRowHeights.png
workingOutline.png

如您所见,主文件夹本身大部分是空的。所有文章都在 wordpressed 中,连同它们的图片在 wordpressed/images.


好的,现在是home-base:

$ git switch home-base
Switched to branch 'home-base'
Your branch is up to date with 'origin/home-base'.

$ ls -1 -R
GetStartedWithPods.md
README.md
Swift52notes1.md
Swift52notes2.md
Swift52notes3.md
dan
debuggingLinks.md
images
logging.md
miscSwiftTricks1.md
miscSwiftTricks2.md
miscSwiftTricks3.md
miscSwiftTricks4.md
packages.md
wordpressed
xcode12Editing.md
xcode12testing.md
xcodeWhereAmI.md
xcodeWorkInTwoPlaces.md

./dan:
bdd.md
homebase.md

./images:
chooser.png
config.png
split1.png
split2.png

./wordpressed:
images

./wordpressed/images:

如您所见,那是更早的情况。尚未将任何内容移至 wordpressed。顶层飘了几篇文章,dan文件夹里有两篇文章,包括我这里感兴趣的一篇,homebase.md.


最后,为了完整起见,我将向您展示masterhome-base之间的合并基础:

$ git merge-base master home-base
b5d7355fe42eddad96beb200df2cba65381c288a
$ git checkout b5d7355fe
$ ls -1 -R
GetStartedWithPods.md
README.md
Swift52notes1.md
Swift52notes2.md
Swift52notes3.md
dan
debuggingLinks.md
images
logging.md
miscSwiftTricks1.md
miscSwiftTricks2.md
miscSwiftTricks3.md
miscSwiftTricks4.md
packages.md
wordpressed
xcode12Editing.md
xcode12testing.md
xcodeWhereAmI.md
xcodeWorkInTwoPlaces.md

./dan:
bdd.md

./images:
chooser.png
config.png
split1.png
split2.png

./wordpressed:
images

./wordpressed/images:

嗯,看起来很像 home-base 现在的样子,不是吗?主要区别在于 homebase.md 出现在 dan 文件夹之前。


那么现在。请问问自己,当我尝试将 master 合并到 home-base 时会发生什么。合并双方的贡献是什么?在我看来,Git 应该意识到在 master 中出现了很多新文件,在 wordpressed 中出现了很多新文件,其中一些是以前的文件的重命名在顶层。另外,当然,在home-base中,homebase.md中出现了一个新文件dan

这些贡献不应该冲突(在我看来)。

好吧,我们试试吧。

$ git switch home-base
$ git merge master
CONFLICT (file location): dan/homebase.md added in HEAD inside a directory that was renamed in master, suggesting it should perhaps be moved to wordpressed/homebase.md.
Automatic merge failed; fix conflicts and then commit the result.

$ git status
On branch home-base
Your branch is up to date with 'origin/home-base'.

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:
    deleted:    dan/homebase.md
    new file:   instructions.md
    new file:   wordpressed/AppDelegateRefactor.md
    new file:   wordpressed/BareListContentView.md
    new file:   wordpressed/CellContentConfiguration.md
    new file:   wordpressed/ControlTargetActioniOS14.md
    renamed:    GetStartedWithPods.md -> wordpressed/GetStartedWithPods.md
    new file:   wordpressed/MultipleTrailingClosures.md
    new file:   wordpressed/StatesAndBackgrounds.md
    renamed:    Swift52notes1.md -> wordpressed/Swift52notes1.md
    renamed:    Swift52notes2.md -> wordpressed/Swift52notes2.md
    renamed:    Swift52notes3.md -> wordpressed/Swift52notes3.md
    new file:   wordpressed/UserInteractiveCells.md
    new file:   wordpressed/bdd-common-pitfalls.md
    renamed:    dan/bdd.md -> wordpressed/bdd.md
    new file:   wordpressed/brantsMenuBar.md
    new file:   wordpressed/collectionViewContentConfig.md
    new file:   wordpressed/collectionViewLists.md
    new file:   wordpressed/collectionViewLists2.md
    new file:   wordpressed/collectionViewOutline.md
    renamed:    debuggingLinks.md -> wordpressed/debuggingLinks.md
    new file:   wordpressed/diffableDataSources.md
    new file:   wordpressed/diffableDataSources2.md
    new file:   wordpressed/forwardCompatibity.md
    new file:   wordpressed/haptics.md
    new file:   wordpressed/iOS13deprecations.md
    new file:   wordpressed/images/argumentsInScheme.png
    new file:   wordpressed/images/bigFlags.png
    new file:   wordpressed/images/callHierarchy.png
    new file:   wordpressed/images/callersMenu.png
    renamed:    images/chooser.png -> wordpressed/images/chooser.png
    renamed:    images/config.png -> wordpressed/images/config.png
    new file:   wordpressed/images/createdTester.png
    new file:   wordpressed/images/dataOrUrl.png
    new file:   wordpressed/images/ipadportraitoverlay.png
    new file:   wordpressed/images/listOfPepBoys.png
    new file:   wordpressed/images/listWithSectionHeaders.png
    new file:   wordpressed/images/littleFlags.png
    new file:   wordpressed/images/looksLikeADuck.png
    new file:   wordpressed/images/newTester.png
    new file:   wordpressed/images/outlineIndicatorsWrong.png
    new file:   wordpressed/images/outlineIndicatorsWrong2.png
    new file:   wordpressed/images/perfectAfterHack.png
    new file:   wordpressed/images/pickAPeppa.png
    new file:   wordpressed/images/rootOnly.png
    new file:   wordpressed/images/sandboxAccountOnDevice.png
    new file:   wordpressed/images/selfSizingStringDrawer.png
    new file:   wordpressed/images/simpleList.png
    renamed:    images/split1.png -> wordpressed/images/split1.png
    renamed:    images/split2.png -> wordpressed/images/split2.png
    new file:   wordpressed/images/splitViewControllerPadLandscape.png
    new file:   wordpressed/images/tableViewAsChoice.png
    new file:   wordpressed/images/threecolumns.png
    new file:   wordpressed/images/twoPossibilities.png
    new file:   wordpressed/images/twoscreensphone.png
    new file:   wordpressed/images/variableRowHeights.png
    new file:   wordpressed/images/workingOutline.png
    new file:   wordpressed/inAppPurchases.md
    renamed:    logging.md -> wordpressed/logging.md
    renamed:    miscSwiftTricks1.md -> wordpressed/miscSwiftTricks1.md
    renamed:    miscSwiftTricks2.md -> wordpressed/miscSwiftTricks2.md
    renamed:    miscSwiftTricks3.md -> wordpressed/miscSwiftTricks3.md
    renamed:    miscSwiftTricks4.md -> wordpressed/miscSwiftTricks4.md
    new file:   wordpressed/multipleSelection.md
    new file:   wordpressed/mysteriesOfLayout.md
    new file:   wordpressed/newInIOS14.md
    renamed:    packages.md -> wordpressed/packages.md
    new file:   wordpressed/photoPicker.md
    new file:   wordpressed/protocolParadox.md
    new file:   wordpressed/splitViewControllers.md
    new file:   wordpressed/splitViewControllers2.md
    new file:   wordpressed/swiftTrickTwoClasses.md
    new file:   wordpressed/targetActionRant.md
    new file:   wordpressed/typescript-shape-of-things.md
    new file:   wordpressed/untappableButton.md
    new file:   wordpressed/what-vs-how.md
    renamed:    xcode12Editing.md -> wordpressed/xcode12Editing.md
    renamed:    xcode12testing.md -> wordpressed/xcode12testing.md
    renamed:    xcodeWhereAmI.md -> wordpressed/xcodeWhereAmI.md
    renamed:    xcodeWorkInTwoPlaces.md -> wordpressed/xcodeWorkInTwoPlaces.md

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    added by us:     wordpressed/homebase.md 

好的,所以最后一行是我不明白的。说“我们添加的”是wordpressed/homebase.md是什么意思? 不! 那不是我们添加它的地方。我们在dan.

中添加了它

masterhome-base 都没有文件 wordpressed/homebase.md。那么 Git 是从哪里得到的???它似乎与它认为根本存在合并冲突的相同原因有关:

dan/homebase.md added in HEAD inside a directory that was renamed in master, suggesting it should perhaps be moved to wordpressed/homebase.md.

所以:Git在说什么?为什么Git认为dan/homebase.md 应该是 wordpressed/homebase.md,没有我能找到的任何证据?我怎样才能防止这种合并冲突并使 Git 对此更加简单?我可以使用不同的合并策略吗?或者我怎样才能简单地解决冲突,比如说,不,Git,请不要管 dan/homebase.md,好吗?

再次对问题中的细节长度表示歉意。

这个特殊的冲突:

CONFLICT (file location): dan/homebase.md added in HEAD inside a
directory that was renamed in master, suggesting it should perhaps
be moved to wordpressed/homebase.md.

是Git中比较现代的发明。 Git 现在尝试在合并基础提交和每个提示提交之间查找 目录重命名 。也就是说,有 运行 git diff --find-renames <base> <left>git diff --find-renames <base> <right>,它在左侧检测到一些重命名,在右侧检测到一些重命名(总数为正)。至少其中一些重命名意味着目录名称更改。所以 Git 现在认为合并的 other 端应该应用相同的目录名称更改。

(Git 中间 2.teens 左右的预发布版本添加了此代码的各种实验版本,我忘记了它真正稳定的时间。仔细阅读发行说明,它看起来像 2.17是什么时候进去的,然后有一个后续的corner case在2.19修复了。)

[编辑,2021 年 4 月 15 日:]当这个新功能出现时,一个新的控制旋钮也出现了:merge.directoryRenames。它的默认值是 conflict,但你可以将它设置为 true(意思是总是做出它已经做出的假设,但不要称之为冲突)或 false(意思是从不做出新的假设,因此不要称之为冲突)。

这是 Git 宣布的唯一冲突,因此它是唯一出现在最终“未合并文件”部分中的文件:

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    added by us:     wordpressed/homebase.md

Git 在这里采用了自己的内部建议:它认为合并基础和 HEAD 之间添加到 dan/ 的所有内容都应该添加到 [=20] =] 由于它在合并基础和 master 的尖端之间看到的变化。

如果这对您来说是正确的,Git 希望您通过 运行ning git add 在该路径名上确认这一点。如果没有,Git 希望您将文件移动到您认为它应该去的任何地方,并且 git add 结果(并删除,使用 git rm 或可能使用 git add,使用的名称 Git)。