【问题标题】:Mercurial merge awesomeness - what am I missing?Mercurial 合并真棒 - 我错过了什么?
【发布时间】:2010-11-17 10:05:43
【问题描述】:

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

事实上,我昨天在观看 Fogcreek 制作的视频时突然想到,this video: 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");
}

【问题讨论】:

    标签: mercurial merge merge-conflict-resolution


    【解决方案1】:

    嗯,您目前基本上遇到了任何当前 VCS 的限制之一(无论是否 DVCS,都无所谓)。

    问题是 VCS 当前与语言无关,其合并算法的基础是文本差异。这意味着他们正在寻找哪些变化以及相关的上下文是什么。
    这里的重要部分是上下文。只不过是你所做的更改前后的几行而已。

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

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

    【讨论】:

    • 其实是配置问题。我使用 Beyond Compare 作为我的差异/合并工具,显然,除非我将 TortoiseHg/Mercurial 配置为使用 Beyond Compare myself,否则它不会自动合并它可以处理的冲突。添加必要的配置后,一切都按预期运行。我会更新我的问题。
    • 我意识到缺乏上下文的问题,我对 diff 算法的工作原理有深入的了解,已经为文本和二进制数据实现了很多,但据说这种特定场景需要工作时间和再次使用 DVCS,所以我只是想知道为什么它没有。
    • 嗯,事实上,这里的例子不是一个人修改一个函数,另一个人把它向下移动,而是同一个人做这两个操作(分两步)。这意味着,从理论上讲,您应该能够在 Fonction2 上工作,而其他人会执行其他两个操作,然后合并会表现良好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多