【问题标题】:why merge does not cause conflict为什么合并不会引起冲突
【发布时间】:2016-03-13 10:44:09
【问题描述】:

这个问题跟随this topic。我想了解merge 做了什么来避免在此过程中出现不必要的错误。

我有两个分支:master,b。我看到了git merge 的奇怪结果。你可以看到 git log 合并前的输出,这里:

* 148c970 (HEAD, master) rename 1 in master to 1_master
| * ad18d9b (b) rename 1 in b to 1_b
|/  
* 15cd89b add 1 in master

所以我在masterb 中有一个名为1 的文件。然后在master 中将其重命名为1_masterb 中的1_b。然后我做了git merge:

git merge b

我猜这会导致冲突,因为合并基础必须是 15cd89b,并且两个分支都在 1 上引入了更改,它们不匹配。

但是合并并没有导致任何conflict,合并后我在工作目录中看到了1_b1_master

注意:

我认为链接答案中的torektwalberg 都预测在上述情况下会发生冲突。

【问题讨论】:

  • 你是如何重命名文件的?使用 git mv 还是只是在文件系统中重命名并在 git 中添加+删除文件?
  • @Pod 这不会有任何区别。 Herehere 是很好的解释。

标签: git version-control merge


【解决方案1】:

如果我尝试重现您的问题,我会遇到重命名/重命名冲突,正如我所料。首先,我创建了一个存储库和一些文件(具有独特的内容):

$ mkdir rename-exp
$ cd rename-exp/
$ git init
Initialized empty Git repository in /home/torek/tmp/rename-exp/.git/
$ cat > 1
This is file "1" in its initial state.
The file is being used
for a test of what happens with
a rename vs rename conflict
in Git.
The file needs some contents
so that git can detect the
rename when we actually
do the rename.
$ cat > 2
This is file "2".         
We give it some contents
so that it has a unique SHA-1.
$ git add .
$ git commit -m initial
[master (root-commit) a4b6f52] initial
 2 files changed, 12 insertions(+)
 create mode 100644 1
 create mode 100644 2

接下来,我创建分支b 并重命名。请注意,我是否使用git mvmv 后跟git rm --cachedgit add 进行重命名并不重要(但git mv 更容易,所以我使用它)。然而,重要的是 git 能够检测到重命名。这要求文件匹配 100% 完全匹配(简单的情况)或匹配“至少 50%”(此阈值可以调整,但 50% 是默认值)当 diff-ed git merge 出现时,旧名称 (1) 不再存在于两棵树中。

$ git checkout -b b
Switched to a new branch 'b'
$ git mv 1 1_b
$ git commit -m 'rename 1 to 1_b in branch b'
[b cc104b1] rename 1 to 1_b in branch b
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename 1 => 1_b (100%)

然后我在master 中使用不同的名称目标进行相同的重命名:

$ git checkout master
Switched to branch 'master'
$ git mv 1 1_master
$ git commit -m 'rename 1 to 1_master in master'
[master b891757] rename 1 to 1_master in master
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename 1 => 1_master (100%)

最后,我运行git merge

$ git merge b
CONFLICT (rename/rename): Rename "1"->"1_master" in branch "HEAD" rename "1"->"1_b" in "b"
Automatic merge failed; fix conflicts and then commit the result.
$ 

您需要展示您的步骤(可能还有您的 git 版本),以便我了解为什么您的合并认为每个更改都是删除和创建(非冲突创建)而不是重命名。

影响这一点的其他变量:

  • 合并期间-X rename-threshold 的任何参数(这是您调整 50% 默认值的方式);
  • 来自git config --get merge.renameLimit 的值
  • git config --get diff.renameLimit 中的值,如果 merge.renameLimit 没有设置。

【讨论】:

  • 我猜问题出在关于文件1 是空的。所以 git 在尝试计算更改时没有检测到它被重命名。你觉得我猜对了吗?
  • 很可能,是的。两个空文件比较相等,但是如果你有额外的空文件,git 将不知道确定文件 1 匹配 1_b 而不是,比如说,1_c 等。或者它可能只是不打扰空文件因为它们不是很有趣。
【解决方案2】:

我认为这是因为 Git 并不真正了解 重命名 文件的概念。请参阅Git FAQ
对于 Git,它只是 add 1_master 后跟 remove 1。你所做的是

在主分支上:

  • 添加文件1_master
  • 删除文件1

在分支b上:

  • 添加文件1_b
  • 删除文件1

总而言之(即合并),这给出了:

  • 添加文件1_master
  • 添加文件1_b
  • 删除文件1

没有冲突。两个分支都对文件 1 应用相同的操作:删除它。

如果您在其中一个分支上编辑文件1,情况将会改变。然后 Git 不知道是应用 edit 还是 deletion

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    相关资源
    最近更新 更多