我使用 Mercurial 一段时间了,有一个“事实”被多次提及。

事实上,昨天在观看 Fogcreek 制作的视频时,我受到了启发, 这个视频:雾溪窑:为您的公司释放 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

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

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:

示例1.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");
}

示例2.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);
}

示例3.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");
}
有帮助吗?

解决方案

好吧,您目前基本上遇到了任何当前 VCS(无论是否为 DVCS,这并不重要)的限制之一。

问题是,VCS 目前与语言无关,其合并算法的基础是文本差异。这意味着他们正在寻找什么变化以及相关的内容是什么 语境.
这里重要的部分是上下文。无非就是你修改前后的一些行。

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top