22

我有一个脚本在构建服务器上以非交互模式运行一些 Mercurial 命令。.hgtags其中一个命令合并了两个分支,并且由于构建脚本的设置方式,在合并期间文件中始终存在冲突。

如何强制 Mercurial 始终.hgtags使用两个文件的更改合并文件,首先是一个文件,然后是另一个文件?

例如,如果我要合并的文件是

A
B
C

A
B
D

我希望结果是

A
B
C
D

我猜我需要一个自定义合并工具。什么工具提供这个功能?

4

5 回答 5

31

请参阅以下Magras de La Mancha的答案,以获得 Mercurial 3.1 的更好解决方案。下面是针对旧版本 Mercurial 的更简单、更天真的解决方案。


是的,您需要为您的文件配置自定义合并工具。.hgtagsMercurial 不提供任何特殊的合并工具.hgtags,您需要使用普通的三向合并工具手动合并它。

文件中的冲突.hgtags可以有两种类型:

  • 愚蠢的冲突:这是你的情况,这里并没有真正的冲突。发生的事情是一个分支有

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C
    

    另一个分支有

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    979c049974485125e1f9357f6bbe9c1b548a64c3 D
    

    每个标签都指向一个变更集,因此这里没有冲突。合并当然应该是两个文件的并集:

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C
    979c049974485125e1f9357f6bbe9c1b548a64c3 D
    
  • 真正的冲突:有一个分支

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C
    

    另一个分支有

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    979c049974485125e1f9357f6bbe9c1b548a64c3 C
    

    这里有一个真正的冲突:hg tag C在两个分支上都完成了,但是标签引用了不同的变更集。解决此问题是一项手动任务。

如果您可以保证只会有愚蠢的冲突并且每个变更集只有一个标签,那么您可以使用

hg log -r "tagged()" --template "{node} {tags}\n" > .hgtags

生成一个新.hgtags文件。关键的见解是 Mercurial知道如何在内部合并标签!当您有两个具有不同.hgtags文件的磁头时,它会一直这样做。上面的模板只是.hgtags基于这个内部合并生成一个新文件。

如果每个变更集可能有多个标签,那么上述方法将不起作用 - 所有标签都打印在一行上,因此您会得到一个标签foo bar而不是两个标签foobar. 然后,您可以改用此样式文件

changeset = "{tags}"
tag = "{node} {tag}\n"

每个标签输出一行,而不是变更集。您将此样式保存在某处并配置合并工具:

[merge-tools]
hgtags.executable = hg
hgtags.args = log -r "tagged()" --style ~/tmp/tags-style > $output
hgtags.premerge = False
hgtags.priority = -1000

[merge-patterns]
.hgtags = hgtags

您现在拥有自动标签合并。有一些警告:

  1. 三个或更多头:该技术仅在合并时有两个头时才有效。如果您有三个或更多头像,则可能会重新出现已删除的标签。如果您有正面 X、Y 和 Z,并且标记A在 X 中被删除,那么 Mercurial 通常能够找出A被整体删除的标记。它基于X000...0 A中文件中的一行来执行此.hgtags操作。但是,如果您合并 X 和 Y 以获得 W,那么建议的方法将不包含任何此类000...0 A行。from Z的定义A现在会突然生效并重新引入A

  2. 真正的冲突:如果你有真正的冲突.hgtags,那么上面的方法会默默地为你从最近的 head 中挑选标签。合并工具基本保存hg tags在里面,多头.hgtags的行为在wiki中有解释。由于无条件地从所有磁头读取并静默合并文件,因此使用这种简单的方法我们无能为力。处理这个需要一个更大的脚本来读取这两个文件并检测冲突。hg tagshg tags.hgtags.hgtags

于 2012-03-20T08:27:18.567 回答
13

Mercurial 3.1 (2014-08-01) 引入了internal:tagmerge。它被标记为实验性的,所以要小心。这是变更集的序言(如果您点击链接,您可以找到有关算法的更多详细信息):

添加一个新的 internal:tagmerge 合并工具,它为 mercurial 的标签文件实现自动合并算法

tagmerge 算法能够解决当前会触发 .hgtags 合并冲突的大多数合并冲突。它不(也不能)处理的唯一情况是两个标签指向每个合并父节点上的不同修订,并且它们对应的标签历史具有相同的等级(即相同的长度)。在所有其他情况下,合并算法将选择属于具有最高排名标签历史的父版本。合并的标签历史是两个标签历史的组合(特别注意尝试在可能的情况下组合常见的标签历史)。

该算法还处理从 .hgtags 文件中手动删除标签的情况以及其他类似的极端情况。

除了实际合并来自两个父级的标签外,考虑到基数,该算法还试图最小化合并后的标签文件与第一个父级的标签文件之间的差异(即它试图使合并后的标签顺序与可能是第一个父级的标签文件顺序)。

tagmerge仅适用于标签文件,因此要使用它,您应该设置merge-patterns。要在每个命令的基础上执行此操作,请使用--config选项:

hg merge -r REV --config merge-patterns..hgtags=internal:tagmerge

或者要在每个存储库的基础上执行此操作,请将以下内容添加到您的存储库配置中.hg/hgrc

[merge-patterns]
.hgtags=internal:tagmerge
于 2014-09-24T09:09:40.447 回答
2

您实际上不需要合并 .hgtags 文件。它在不同的分支上可能不同,Mercurial 将正确列出所有分支中的所有标签。

我们使用merge-patterns配置选项告诉 Mercurial 在合并 .hgtag 时使用本地分支。将以下内容添加到存储库的 hgrc 文件中:

 [merge-patterns]
 .hgtags = internal:local

进行涉及 .hgtags 文件的合并时,.hgtags 将显示为已修改,但不会更改。

于 2012-03-20T16:55:40.903 回答
1

您不能通过执行无人参与的合并来自动解决合并冲突。如果没有合并(即选择“仅我的”或“仅其他”),它将起作用。

恐怕,您的工作流程计划不当 - build-server不得执行任何修改源的操作。这是人类和人类选择的任务。

但我想,.hgtags 中的确切数据必须为 build-server 赋值(它使用自己的克隆,而不是填充给任何人,我希望?!),因此您可以在命令中定义任何合并策略并拥有(不好,有数据-loss) .hgtags 合并

顺便说一句,任何语言中的“先从一个,然后从另一个”,仅使用形式逻辑,用于配对

A
B
C

A
B
D

意味着ABCABD结果

于 2012-03-20T07:39:03.093 回答
-1

你应该试试diffmerge,太棒了!

于 2012-03-20T07:04:50.830 回答