如何自动合并Mercurial中的.hgtags文件?

22

我有一个脚本在构建服务器上以非交互模式运行一些Mercurial命令。其中一个命令将合并两个分支,由于构建脚本的设置方式,合并过程中的.hgtags文件总是会出现冲突。

我该如何强制 Mercurial 总是使用两个文件的更改来合并 .hgtags 文件,先是一个文件的更改,然后是另一个文件的更改?

例如,如果要合并的文件如下:

A
B
C

A
B
D

我希望得到的结果是

A
B
C
D

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

5个回答

31
请参见Magras de La Mancha在此回答中为Mercurial 3.1提供的更好解决方案。以下是旧版本Mercurial的更简单和更天真的解决方案。


是的,您需要为.hgtags文件配置自定义合并工具。 Mercurial不提供任何特殊的.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通常能够根据X中.hgtags文件中的000...0 A行确定A已被删除。但是,如果将X和Y合并成W,则上述方法中不会包含任何000...0 A行。来自Z的A定义现在突然会生效并重新引入A

  2. 真正的冲突:如果在.hgtags文件中存在真正的冲突,则上述方法将为您静默地选择最近的代码分支中的标签。合并工具基本上是在.hgtags中保存hg tags,而在多个代码分支中使用hg tags的行为在维基上有所解释。由于hg tags无条件地读取并静默地合并所有代码分支中的.hgtags文件,因此我们不能通过这种简单的方法来解决它。要处理这种情况,需要一个更大的脚本来读取两个.hgtags文件并检测冲突。


1
@LazyBadger:谢谢!在aragost.com上发布这种信息可能是有意义的,我当然希望能吸引更多人来我们的网站。但我也在考虑在aragost.com上创建一个页面,以便指向我最喜欢的Stack Overflow问题,这样我就有了可以向客户指出的东西。我还不确定我会选择哪种方式。 - Martin Geisler
1
当我将这个添加到[merge-tools]中时,Mercurial开始将其用于所有合并,因为所有默认的合并工具都具有负优先级。我不得不在[merge-tools]部分中添加gvimdiff.priority = 1来解决这个问题,正如此线程中所讨论的那样。 - talljosh
1
警告!正如talljosh所指出的那样,这个解决方案略有不正确。Mercurial默认将“原始”合并工具的优先级设为最低,因此每次都会调用hgtags合并!你还需要设置"merge.priority=1"将其设置为高于0,以便对于非hgtags文件,在调用自定义合并之前调用它。 - YMA
1
@YMA 谢谢,我已经更新了答案,加入了 hgtags.priority = -1000。我现在没有时间测试,所以请告诉我这是否有帮助。 - Martin Geisler
特别感谢 hg log -r "tagged()" --template "{node} {tags}\n" > .hgtags,我用它来清理零哈希标签。 - ivkremer
显示剩余3条评论

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

Mercurialзҡ„ж–°зүҲжң¬еңЁеҗҲ并ж¶үеҸҠ.hgtagsж–Ү件时жҳҜеҗҰй»ҳи®ӨдҪҝз”ЁжӯӨз®—жі•пјҹ - binki

2
您实际上不需要合并 .hgtags 文件。它在不同的分支上可能会有所不同,Mercurial 将正确地列出所有分支上的所有标签。
我们使用 merge-patterns 配置选项 来告诉 Mercurial 在合并 .hgtags 时使用本地分支。将以下内容添加到您的存储库的 hgrc 文件中:
 [merge-patterns]
 .hgtags = internal:local

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


1

您无法通过执行不受监督的合并来自动解决合并冲突。 如果不进行合并(即选择“仅我的”或“仅其他”),它将起作用。

恐怕,您的工作流程规划有误——构建服务器不得执行任何修改源代码的操作。这是人类和人类选择的任务。

但我想,在.hgtags中的确切数据对于构建服务器具有价值(它使用自己的克隆版本,没有提供给任何人,希望如此?!),因此您可以在命令中定义任何合并策略,并合并(坏的,有数据丢失的).hgtags

顺便说一句,“先从一个,然后从另一个”在任何语言中,只使用形式逻辑,对成对

A
B
C

并且

A
B
D

意思是 ABCABD 的结果


1
这在大多数情况下是正确的,但是像@MartinGeisler建议的那样,在这种特殊情况下存在一种解决方案。另外,在不了解更多情况的情况下,您不应该批评OP的工作流程。 - krtek
2
@krtek - 构建服务器不得修改代码,仅进行构建。我保留向所有人讲述真相的权利。 - Lazy Badger
1
@Tim 不行!通知我结果,写日志。顺便把仓库像圣诞树一样点亮——每个成功(可构建的)提交都打标签是一个糟糕的想法。把一个标签移开是毫无意义的。 - Lazy Badger
1
@LazyBadger 我们不会为每个成功的构建打标签,只有那些被部署的才会。构建服务器需要在这里执行合并的唯一原因是,在Mercurial中,实际更改标签列表的修订版本与其创建的标签是不同的修订版本。 - Alexey Blinov
2
@LazyBadger - 你如何确保在你执行此操作时,仓库中没有其他更改?你想要在进行可部署构建时封锁中央仓库吗?即使这需要几个小时?这些问题没有简单的答案。像“构建服务器不得修改源代码”之类的规则在理论上很好,但并不是普适解决方案。如果你不知道目标或约束条件,假装它们可以作为统一规则应用于所有情况并不是非常有帮助。 - Tim
显示剩余4条评论

-1

2
我认为楼主正在寻找一种自动合并这些文件的方法。 - krtek
对于一两个冲突,你可以随意编辑冲突的文件,但如果涉及到很多冲突,那将会是一个头疼的问题,这就是为什么我建议OP使用像diffmerge这样的好工具。并且没有这样的工具可以帮助您自动解决冲突,工具只能辅助您完成这项任务。 - neevek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接