Mercurial合并真棒 - 我错过了什么?

ang*_*son 8 merge mercurial merge-conflict-resolution

我已经使用Mercurial一段时间了,并且有一个"事实"被多次给出.

事实上,昨天观看由Fogcreek制作的视频时,它让我感到震惊,这段视频:Fog Creek Kiln:为您的公司解锁DVCS的力量,似乎有些东西对我来说不起作用.

在该视频及其后的1:39左右,它表明当其他版本控制系统跟踪修订版(即快照)时,DVCS'就像Mercurial跟踪更改集(即快照之间发生的事情).

这使它们在合并场景中具有优势,然后它显示了一个示例.如果您在一个分支中移动一个函数,并在另一个分支中更改相同的函数,Mercurial可以合并它.

虽然我现在找不到任何直接链接,但我已经在其他地方看到了这一点.

这对我来说似乎不起作用.


编辑:这是TortoiseHg的默认"beyondcompare3"合并工具配置的问题.我将下面的配置添加到我的Mercurial.ini文件中,现在它按预期工作.当然,如果它不能自动充电,它会向GUI工具发挥作用,但现在这个问题中描述的合并在没有任何提示的情况下运行,并且开箱即可做正确的事情

[ui]
merge = bc3

[merge-tools]
bc3.executable = C:\Program Files (x86)\Beyond Compare 3\bcomp.exe
bc3.args = $local $other $base $output /automerge /reviewconflicts /closescript
bc3.priority = 1
bc3.premerge = True
bc3.gui = True
Run Code Online (Sandbox Code Playgroud)

为了测试这个,我将此文件提交到存储库:

void Main()
{
    Function1();
    Function2();
}

public void Function1()
{
    Debug.WriteLine("Function 1");
    for (int index = 0; index < 10; index++)
        Debug.WriteLine("f1: " + index);
}

public void Function2()
{
    Debug.WriteLine("Function 1");
}
Run Code Online (Sandbox Code Playgroud)

然后在从这一个分支出来的两个不同的并行更改集中,我做了以下两个更改:

  1. 我将Function1函数移动到文件的底部
  2. 我更改了Function1中的消息

然后我尝试合并,Mercurial给了我一个合并冲突窗口,试图弄清楚我做了什么.

基本上,它尝试更改Function2中的文本,该文本现在处于Function1移动之前的位置.

这不应该发生!


这是复制我的例子的源文件:

生成存储库的批处理文件:

@echo off

setlocal

if exist repo rd /s /q repo
hg init repo
cd repo

copy ..\example1.linq example.linq
hg commit -m "initial commit" --addremove --user "Bob" --date "2010-01-01 18:00:00"

copy ..\example2.linq example.linq
hg commit -m "moved function" --user "Bob" --date "2010-01-01 19:00:00"

hg update 0
copy ..\example3.linq example.linq
hg commit -m "moved function" --user "Alice" --date "2010-01-01 20:00:00"
Run Code Online (Sandbox Code Playgroud)

该文件的3个版本,example1.linq,example2.linq和example3.linq:

Example1.linq:

<Query Kind="Program" />

void Main()
{
    Function1();
    Function2();
}

public void Function1()
{
    Debug.WriteLine("Function 1");
    for (int index = 0; index < 10; index++)
        Debug.WriteLine("f1: " + index);
}

public void Function2()
{
    Debug.WriteLine("Function 1");
}
Run Code Online (Sandbox Code Playgroud)

Example2.linq:

<Query Kind="Program" />

void Main()
{
    Function1();
    Function2();
}

public void Function2()
{
    Debug.WriteLine("Function 1");
}

public void Function1()
{
    Debug.WriteLine("Function 1");
    for (int index = 0; index < 10; index++)
        Debug.WriteLine("f1: " + index);
}
Run Code Online (Sandbox Code Playgroud)

Example3.linq:

<Query Kind="Program" />

void Main()
{
    Function1();
    Function2();
}

public void Function1()
{
    Debug.WriteLine("Function 1b");
    for (int index = 0; index < 10; index++)
        Debug.WriteLine("f1: " + index);
}

public void Function2()
{
    Debug.WriteLine("Function 1");
}
Run Code Online (Sandbox Code Playgroud)

giz*_*zmo 7

那么,你目前正在达到一个限制,基本上,任何当前的VCS(DVCS与否,无关紧要).

问题是VCS目前与语言无关,它们的合并算法的基础是文本差异.这意味着他们正在寻找什么样的变化以及相关的背景.
这里的重要部分是背景.在你所做的改变之前和之后,只不过是一些线条.

这意味着他们在处理同一文件中的代码重组时非常糟糕,因为你基本上搞砸了他们可以依赖的所有上下文.
通常,在您的示例中,通过切换这两个函数,您不仅完全颠倒了两个更改集之间的上下文,更糟糕的是,通过在最新函数之后没有多余的行,您隐式地减少了最新更改的上下文,减少了机会合并算法能够弄清楚你真正做了什么.

我目前只知道一个来自msft的XML工具,它试图处理你的变化的语义,而不仅仅是它的文本表示.
我也知道PlasticSCM的人正试图为一些主流语言实现这样的功能,但它确实是一个有改进空间的地方.