我有一个脚本在构建服务器上以非交互模式运行一些Mercurial命令。其中一个命令将合并两个分支,由于构建脚本的设置方式,合并过程中的.hgtags
文件总是会出现冲突。
我该如何强制 Mercurial 总是使用两个文件的更改来合并 .hgtags
文件,先是一个文件的更改,然后是另一个文件的更改?
例如,如果要合并的文件如下:
A
B
C
和
A
B
D
我希望得到的结果是
A
B
C
D
我猜我需要一个自定义合并工具。哪个工具提供这个功能?
我有一个脚本在构建服务器上以非交互模式运行一些Mercurial命令。其中一个命令将合并两个分支,由于构建脚本的设置方式,合并过程中的.hgtags
文件总是会出现冲突。
我该如何强制 Mercurial 总是使用两个文件的更改来合并 .hgtags
文件,先是一个文件的更改,然后是另一个文件的更改?
例如,如果要合并的文件如下:
A
B
C
和
A
B
D
我希望得到的结果是
A
B
C
D
我猜我需要一个自定义合并工具。哪个工具提供这个功能?
是的,您需要为.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
而不是两个标签foo
和bar
。然后,您可以使用这个样式文件代替:
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
现在你可以进行标签自动合并,但是要注意以下几点:
三个或更多的代码分支:该技术仅适用于合并时有两个代码分支。如果合并时有三个或更多的代码分支,则删除的标签可能会重新出现。例如,如果有X、Y和Z三个代码分支,标签A
在X中被删除,那么Mercurial通常能够根据X中.hgtags
文件中的000...0 A
行确定A
已被删除。但是,如果将X和Y合并成W,则上述方法中不会包含任何000...0 A
行。来自Z的A
定义现在突然会生效并重新引入A
。
真正的冲突:如果在.hgtags
文件中存在真正的冲突,则上述方法将为您静默地选择最近的代码分支中的标签。合并工具基本上是在.hgtags
中保存hg tags
,而在多个代码分支中使用hg tags
的行为在维基上有所解释。由于hg tags
无条件地读取并静默地合并所有代码分支中的.hgtags
文件,因此我们不能通过这种简单的方法来解决它。要处理这种情况,需要一个更大的脚本来读取两个.hgtags
文件并检测冲突。
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
.hgtags
ж–Ү件时жҳҜеҗҰй»ҳи®ӨдҪҝз”ЁжӯӨз®—жі•пјҹ - binkimerge-patterns
配置选项 来告诉 Mercurial 在合并 .hgtags 时使用本地分支。将以下内容添加到您的存储库的 hgrc 文件中: [merge-patterns]
.hgtags = internal:local
当进行涉及 .hgtags 文件的合并时,.hgtags 将显示为已修改,但不会被更改。
您无法通过执行不受监督的合并来自动解决合并冲突。 如果不进行合并(即选择“仅我的”或“仅其他”),它将起作用。
恐怕,您的工作流程规划有误——构建服务器不得执行任何修改源代码的操作。这是人类和人类选择的任务。
但我想,在.hgtags中的确切数据对于构建服务器具有价值(它使用自己的克隆版本,没有提供给任何人,希望如此?!),因此您可以在命令中定义任何合并策略,并合并(坏的,有数据丢失的).hgtags
顺便说一句,“先从一个,然后从另一个”在任何语言中,只使用形式逻辑,对成对
A
B
C
并且
A
B
D
意思是 ABCABD
的结果
你应该试试diffmerge,它非常棒!
[merge-tools]
中时,Mercurial开始将其用于所有合并,因为所有默认的合并工具都具有负优先级。我不得不在[merge-tools]
部分中添加gvimdiff.priority = 1
来解决这个问题,正如此线程中所讨论的那样。 - talljoshhgtags.priority = -1000
。我现在没有时间测试,所以请告诉我这是否有帮助。 - Martin Geislerhg log -r "tagged()" --template "{node} {tags}\n" > .hgtags
,我用它来清理零哈希标签。 - ivkremer