8

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

事实上,昨天在观看 Fogcreek 制作的视频时,我突然想到了这个视频:Fog Creek Kiln: Unlock the power of DVCS for your company似乎有些东西对我不起作用。

在该视频的大约 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

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

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");
}

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

  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"

该文件的 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");
}

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);
}

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");
}
4

1 回答 1

7

好吧,您目前基本上遇到了任何当前 VCS(DVCS 与否,没关系)的限制之一。

问题是 VCS 目前与语言无关,它们的合并算法的基础是文本差异。这意味着他们正在寻找什么变化以及相关的上下文是什么。
这里的重要部分是上下文。您所做的更改之前和之后的一些行仅此而已。

这意味着他们在处理同一文件内的代码重组方面真的很糟糕,因为你基本上搞砸了他们可以依赖的所有上下文。
通常,在您的示例中,通过切换两个函数,您不仅完全反转了两个变更集之间的上下文,而且更糟糕的是,由于在最新函数之后没有额外的行,您隐式减少了最新更改的上下文,从而减少了机会合并算法能够弄清楚你真正做了什么。

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

于 2010-11-17T10:30:07.763 回答