【问题标题】:Why is it resulting in a merge conflict?为什么会导致合并冲突?
【发布时间】:2015-12-22 12:45:25
【问题描述】:

这是我的 git 存储库的初始快照

在分支master,文件m1 包含

L1

在分支dev,文件m1 包含

L1
L2

如果我尝试将 devmaster 合并,则会导致冲突。

$ git checkout master
Switched to branch 'master'

$ git merge dev
Auto-merging m1
CONFLICT (content): Merge conflict in m1
Automatic merge failed; fix conflicts and then commit the result.

$ git diff
diff --cc m1
index 078f94b,9f46047..0000000
--- a/m1
+++ b/m1
@@@ -1,1 -1,2 +1,5 @@@
  L1
++<<<<<<< HEAD
++=======
+ L2
++>>>>>>> dev

虽然我没有在master中修改m1的第2行,但是怎么会导致冲突呢?

验证文件的实际内容并确定这是否是由空格引起的:

在分支master

git branch
  dev
* master

$ xxd m1
0000000: 4c31 0a                                  L1.

在分支dev

$ git checkout dev
Switched to branch 'dev'

$ xxd m1
0000000: 4c31 0a4c 320a                           L1.L2.

这是我用来创建这个 repo 的脚本。

#!/bin/bash

mkdir git_demo
cd git_demo
git init

touch m1
git add .
git commit -m "Added file: m1"
# sleep is needed, otherwise a different repo is being created, probably because of *some* filesystem issue!
sleep 1

git branch dev
echo L1 >> m1
git add .
git commit -m "Added line L1 to m1"
# sleep is needed, otherwise a different repo is being created, probably because of *some* filesystem issue!
sleep 1

git checkout dev
echo L1 >> m1
git add .
git commit -m "Added line L1 to m1"
# sleep is needed, otherwise a different repo is being created, probably because of *some* filesystem issue!
sleep 1

echo L2 >> m1
git add .
git commit -m "Added line L2 to m1"
# sleep is needed, otherwise a different repo is being created, probably because of *some* filesystem issue!

gitg --all
git checkout master
git merge dev

【问题讨论】:

  • 文件的最后一行可能会有一个“文件结尾”字符?
  • 我不这么认为。请看我更新帖子的结尾。
  • 您的流程是快进合并的完美示例,这真的很奇怪。自您创建回购以来,您能否发布确切的说明?
  • @MarounMaroun 或者,如果我上传未修改的 repo 的 ZIP,对您来说会更容易吗?我有一份原始副本用于测试目的。而且我不认为这是一个快进。相反,我希望merge 跳过重复提交(我有意引入)并应用另一个。
  • 请随意发布链接到 repo 以便我查看。

标签: git git-merge git-merge-conflict


【解决方案1】:

答案是存在冲突,因为这两个分支没有任何merge-base 提交。

以下是如何以更少的步骤生成问题。
创建孤立分支(孤立分支是没有任何历史记录的分支)

您可以在这里看到他们没有共享同一棵树

[]

【讨论】:

  • 你是不是刚刚解压压缩包并执行git status
  • 是的,解压缩(Unix),你可以看到我在那里得到了什么。我很快就会找到一些隐藏的角色:-)
  • 即使 stash 也不起作用,这个文件有些奇怪。
  • 我正在尝试将命令放在一起来重新创建我用来创建这个奇怪片段的脚本!请稍等几分钟。
  • “修复”它的唯一方法是添加文件并提交,但这不是我们想要的
【解决方案2】:

因为共同祖先是空的。

在 master 中,您在一个空文件中添加了一行。在 dev 分支中,您已将两行添加到一个空文件中。

其中一条线是共同的没关系,你要选择你想走哪一边;有一条线的一侧或有两条线的一侧。

【讨论】:

  • 从这个讨论中,我可以看到 git 的 merge 行为在很大程度上仍然被误解,即使在老用户中也是如此。这么多相互矛盾的理论!但是,我仍然无法理解 3 路合并如何改善这种情况。我认为git应该检测到master-ancestorL2之间dev-ancestor之间没有变化。后者应该支配早期。不应该只在同一行发生变化时才发生冲突吗?
  • 但是master和祖先之间有变化。祖先是一个空文件。如果祖先与主人相同,那么您将是正确的。
  • 当 (a) 祖先与要合并的两个版本不同并且 (b) 文件的同一行没有变化时,git 3-way merge 不能正确处理吗?
  • 是的,但同样,这不是您在这里所做的。在您的示例中,您 正在 更改每个中的相同行(实际上,这不是关于 lines 而是 regions。)
  • 区域边界如何确定?单行,就其本身而言,也可以被视为一个region。从你所说的情况来看,显然情况并非如此。
【解决方案3】:

这很容易重新创建:

% git init                                                                                                                                                                                                        [8:33:13]
Initialized empty Git repository in /home/martin/tmp/gitte/.git/
% touch m1                                                                                                                                                                                                        [8:33:16]
% git add m1                                                                                                                                                                                                      [8:33:40]
% git commit -m "Added file: m1"                                                                                                                                                                                  [8:33:48]
[master (root-commit) 72a9740] Added file: m1
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 m1
% git checkout -b dev                                                                                                                                                                                           [8:34:05]
Switched to a new branch 'dev'
% echo L1 >> m1                                                                                                                                                                                                   [8:34:08]
% git commit -am "Added line L1 to file m1"                                                                                                                                                                     [8:34:29]
[dev b16538c] Added line L1 to file m1
 1 file changed, 1 insertion(+)
% git checkout master                                                                                                                                                                                             [8:34:33]
Switched to branch 'master'
% echo L1 >> m1                                                                                                                                                                                                   [8:34:38]
% git commit -am "Added line L1 to file m1"                                                                                                                                                                       [8:34:46]
[master 7b952c8] Added line L1 to file m1
 1 file changed, 1 insertion(+)                                                                                                                                                    [8:35:59]
HEAD is now at 7b952c8 Added line L1 to file m1
% gitk                                                                                                                                                                                                            [8:36:04]
% echo L2 >> m1                                                                                                                                                                                                                                                                                                                                                                                                                [8:36:28]
% git commit -am "Added line L2 to file m1"                                                                                                                                                                       [8:36:28]
[master f336d77] Added line L2 to file m1
 1 file changed, 1 insertion(+)
% git merge dev  # merge conflict!

出现问题是因为两个文件中的第 2 行不同。在您的 master 分支中,第 2 行只是一个“EOF”,而在 dev 分支中,第 2 行是“L2”。

【讨论】:

  • 你确定吗?如果您在两个分支的m1 上看到xxd 的输出,则0a 似乎存在换行符。文件的任何一个版本中都没有单独的 EOF。
  • 请查看我原帖中的xxd 输出。
  • 技术上没有 EOF 字符,所以我已经澄清了我的答案。但是,您可以清楚地看到合并冲突在第 2 行。该文件曾经被认为是 EOF,现在是 L2,Git 认为这是一个冲突。
  • 在这种情况下,当从文件中添加或删除一行时,git 总是会在最后显示冲突。不是吗?并且master 中的0a 字符(第3 个字符)应该与dev 分支中的0a 字符(第3 个字符)匹配。
  • 它似乎仅在您更改两个分支中文件的最后一行时才会发生。在一个分支中,EOF(不是字符)在第 2 行引入,在另一个分支中,L2 在第 2 行引入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多