我们每年有三个主要版本,有共同响应的分支:例如2013A,2013B和2013C。当我们创建每个分支时,它是从默认值开始的。每个分支中的更改只能向前合并,例如 2013A -> 2013B -> 2013C ->默认值。 我们在服务器上有一个推送钩子,用于检查推送的合并是否方向错误,即默认 -> 2013C、2013C -> 2013B 等。
我们还有特定于团队的分支,其中一些正在开发一个版本的功能,而另一些正在开发下一个版本,例如默认。 当团队处理发布时,他们会合并到发布分支/从发布分支合并。 当团队准备好处理下一个版本时,他们开始合并到默认分支/从默认分支合并。
前几天我们遇到了这样一种情况:新开发人员在团队准备进入下一个版本之前将默认合并到他的团队分支中,然后将团队分支合并到以前的版本中,即默认 -> TeamBranch -> 2013B。 不幸的是,我们的钩子没有考虑到这种情况。
从本质上讲,这就是发生的事情:
2013B A---o---o---o---o---B---o
/ /
Team / o---o---o---C---o---o
/ /
Default D---o---o---o---o---o---o---o---o
A = 创建 2013B 分支
B = 合并到发布分支
C = 错误的合并。 我们希望在合并到发布分支时检测并防止这些。
D = 发布分支和默认值的第一个公共祖先。
因此,我重写了我们的钩子,以检查当更改合并到发布分支时,它不会向后合并。 对于每个合并到发布分支中,我检查是否有来自转发分支的任何祖先合并。 这是我正在使用的 revset 查询:
> hg log -r "limit(descendants(p1(first(branch('2013B')))) and reverse(p2(ancestors(branch('2013B'))) and branch('default')),1)"
这行得通。 但是,我们有一个大型存储库(111,000+ 变更集),检查需要 30 到 40 秒。我想知道是否有更快/更快/更有效的方法来编写我的 revset 查询,或者另一种我没有看到的方法。
我将同样的问题发送到Mercurial邮件列表并收到了答案。 branch()
查询是性能瓶颈。 它会导致 Mercurial 展开分支上的所有变更集。 Mercurial 不会缓存此结果,因此每个调用都将展开变更集。
我没有使用branch()
而是改用descendants()
和ancestors()
:
limit(children(p2(2013BBaseline:: and ::2013B and merge()) and branch(default)) and reverse(::2013B))
-
p2(2013BBaseline:: and ::2013B and merge()) and branch(default)
获取第二个父分支(传入分支)进行2013B
分支的开头与其头部之间的所有合并,并仅返回默认分支上的合并。[1] - 然后将上面的子句用
children()
包裹起来,以返回到该父母的子项。 - 然后
and reverse(::2013B)
得到作为2013B
分支祖先的子分支,即错误的合并。 - 然后,
limit()
只返回这些错误合并中的第一个。
上面的查询大约需要 1.5 秒。
感谢Matt Mackall提出解决方案。
2013BBaseline
是一个标记,用于标识从中创建分支2013B
default
分支中的变更集,否则我将不得不2013BBaseline::
替换为:p1(first(branch(2013B)))::
来发现发布分支的基线,这性能不是很好。
要检测合并C
,您应该能够使用
$ hg log -r "parents(branch(Team) and merge()) and branch(default)"
这为您提供了合并到 Team
中的default
的变更集。如果有,则有人错误地合并到他们的团队分支中。我认为您需要从团队分支的角度来攻击这一点:您不能禁止与发布分支的合并,因为其中一些将是合法的。
如果您的团队分支遵循一致的命名方案(它们应该),则可以使用带有branch()
谓词的正则表达式来选择它们。类似的东西
$ hg log -r "branch('re:team-.*')"
将匹配以 team-
开头的分支。