如何在Mercurial中自动合并.hgtags?

Ale*_*nov 21 merge mercurial dvcs merge-conflict-resolution .hgtags

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

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

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

A
B
C
Run Code Online (Sandbox Code Playgroud)

A
B
D
Run Code Online (Sandbox Code Playgroud)

我希望结果如此

A
B
C
D
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*ler 31

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


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

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

  • 愚蠢的冲突:这是你的情况,这里没有真正的冲突.会发生什么是一个分支有

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C
    
    Run Code Online (Sandbox Code Playgroud)

    而另一个分支有

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    979c049974485125e1f9357f6bbe9c1b548a64c3 D
    
    Run Code Online (Sandbox Code Playgroud)

    每个标记只涉及一个变更集,因此这里没有冲突.合并当然应该是两个文件的联合:

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C
    979c049974485125e1f9357f6bbe9c1b548a64c3 D
    
    Run Code Online (Sandbox Code Playgroud)
  • 真正的冲突:有一个分支

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    12e0fdbc57a0be78f0e817fd1d170a3615cd35da C
    
    Run Code Online (Sandbox Code Playgroud)

    而另一个分支有

    f40273b0ad7b3a6d3012fd37736d0611f41ecf54 A
    0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 B
    979c049974485125e1f9357f6bbe9c1b548a64c3 C
    
    Run Code Online (Sandbox Code Playgroud)

    这里存在一个真正的冲突:hg tag C在两个分支上完成,但标签指的是不同的变更集.解决这个问题是一项手动任务.

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

hg log -r "tagged()" --template "{node} {tags}\n" > .hgtags
Run Code Online (Sandbox Code Playgroud)

生成一个新.hgtags文件.关键的见解是Mercurial 知道如何在内部合并标签!当你有两个不同.hgtags文件的头时,它会一直这样做.上述模板只是.hgtags根据此内部合并生成一个新文件.

如果您有可能每变更一个以上的标签,则上述不会工作-所有的标签都印上一条线,所以你得到一个标签foo bar,而不是两个标签foobar.然后,您可以使用此样式文件:

changeset = "{tags}"
tag = "{node} {tag}\n"
Run Code Online (Sandbox Code Playgroud)

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

[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
Run Code Online (Sandbox Code Playgroud)

您现在有自动标记合并.有一些警告:

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

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


mag*_*ras 12

Mercurial 3.1(2014-08-01)介绍了内部:tagmerge.它被标记为实验所以要小心.以下是changeset的序言(如果您按照链接,可以找到有关算法的更多详细信息):

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

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

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

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

tagmerge仅适用于标记文件,因此要使用它,您应该设置合并模式.要在每个命令的基础上执行此操作,请使用--config选项:

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

或者在每个存储库的基础上执行此操作添加到您的repo配置.hg/hgrc:

[merge-patterns]
.hgtags=internal:tagmerge
Run Code Online (Sandbox Code Playgroud)