我正在使用default
分支进行持续开发,现在将创建一个新的命名分支来标记版本。所有进一步的开发将在默认分支上,所有生产错误修正将在新的上进行(随后合并到default
),如下所示:
#>hg branches
aristotle 42:dbd...
default 41:da5...
#>hg branch
default
#>echo "Feature #1 for the next release" >> feature1.txt
#>hg add
#>hg commit -m "Implement feature #1 for the next release"
...... eek, need to make an urgent fix on Production .....
#>hg update aristotle
#>echo "Fixed urgent bug #123 on Production" >> fix123.txt
#>hg add
#>hg commit -m "Fixed bug #123 on Production"
created new head
#>hg update default
#>hg merge aristotle
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, dont forget to commit)
#>hg commit -m "Merge in the fix for bug #123"
#>hg push
以上似乎是要走的路,然而似乎很容易搞砸事情并以相反的方式合并(从default
到aristotle
这意味着所有新的功能将出现在生产分支中。)
也许我的恐惧是毫无根据的,因为人们会在将提交内容推送到中央回购之前注意到混乱,但我想看看是否有可能使这种方法变得更加万无一失。
所以我开始研究钩子:
[hooks]
pretxnchangegroup.branch = hg heads --template "{branches} " | find "aristotle" && exit 1 || exit 0
..但后来意识到这不是我需要的,因为这根本不允许我推动亚里士多德的改变。
所以我不知道该怎么做。理想情况下,我希望开发人员在尝试从default
提交到aristotle
本地的合并时看到“错误的合并方式”消息(显然,应该有一个双重 - 检查中央仓库),同时应该可以从生产分支合并到默认分支。
谢谢!
答案 0 :(得分:1)
这应该这样做。它使用revset query从aristotle
中找到default
的任何合并。
hg log -r 'children(p2(::aristotle and ::default and merge()) and branch(default)) and branch(aristotle)'
::aristotle and ::default and merge()
查找作为aristotle
和default
分支的祖先的所有合并p2(...) and branch(default)
抓取default
分支上的第二个父级(传入变更集)。children(...) and branch(aristotle)
然后抓取aristotle
分支上的实际合并变更集。 I recently needed to figure this out myself但还需要确保default
未间接合并到我的发布分支中,即默认 - >功能 - >释放。
答案 1 :(得分:0)
这与几天前的问题Ensuring a merge between branches happens in one direction
完全相同但是我不喜欢我对那个的答案,那么这个怎么样:
为过去的版本保留单独的克隆。在上面的示例中,当您决定需要对亚里士多德进行紧急修复时,请执行以下操作:
cd ..
hg clone -r aristotle myrepo myrepo-aristotle
然后你有一个只有亚里士多德的克隆,你不能不小心将它合并到那个克隆中的默认值。
那就是说,它仍然不是一个好的答案。唯一真正的安慰是,如果你在一个你不喜欢的方向上合并,你总是可以重新克隆两个头并合并到另一个方向。
答案 2 :(得分:0)
我在寻找相关问题的解决方案时发现了这个问题,我知道这是一个老问题,但我想我会分享我们的解决方案。
我们发布了名为release-x.y.z的分支和默认的持续开发。我们使用基于https://www.mercurial-scm.org/wiki/HookExamples上的示例precommit_badbranch_badmerge的钩子。
我们基本上提取任何合并中涉及的每个分支的版本号,并确保它以正确的方式(默认被视为9999.9999.9999任何不是发布或默认分支获得-1,-1, -1(可以合并为任何东西)。
请注意,这只是一个简单的“立即”检查,它不会捕获有人从默认值转换为blah分支然后合并到发布分支的问题。
作为旁注,我们还有一个策略,即默认合并必须与发布分支上的原始更改同时推送,这样可以避免其他人必须进行合并才能合并自己的更改 - 这是强制我正在寻找解决方案。
请注意,您可以使用server / central repo
的hooks部分调用它[hooks]
pretxnchangegroup.prevent_bad_merges = python:<path_to_hook>\prevent_bad_merges.py:prevent_bad_merges
下面的python hook:
# based on precommit_badbranch_badmerge
# at https://www.mercurial-scm.org/wiki/HookExamples
import re
# this isnt a proper compare, it will just return numbers > 0 if source is after target
def compare_versions(source_version, target_version):
# if either side is -1, ignore it
if (source_version[0] == -1) or (target_version[0] == -1):
return 0;
if source_version[0] > target_version[0]:
return 1
elif source_version[0] == target_version[0]:
if source_version[1] > target_version[1]:
return 2
elif source_version[1] == target_version[1]:
if source_version[2] > target_version[2]:
return 3
return 0
def get_version(branch):
if branch == 'default':
major=9999
minor=9999
revision=9999
else:
# note python uses ?P for named matches
match = re.match('(release-(?P<major>\d)\.(?P<minor>\d)\.(?P<revision>\d))', branch)
if match:
major = int(match.group('major'))
minor = int(match.group('minor'))
revision = int(match.group('revision'))
else:
major = -1
minor = -1
revision = -1
return [major,minor,revision]
def prevent_bad_merges(ui, repo, node, **kwargs):
ui.debug("in hook\n")
for rev in xrange(repo[node].rev(), len(repo)):
ui.debug("in loop\n")
# get context (change)
ctx = repo[rev]
ui.debug("got ctx\n")
if len(ctx.parents()) > 1:
ui.debug("got a merge\n")
branch = ctx.branch()
ui.debug(branch +"\n")
parent1 = ctx.parents()[0]
ui.debug("got parent1\n")
parent2 = ctx.parents()[1]
ui.debug("got parent2\n")
target_branch = repo[parent1.node()].branch()
ui.debug("got parent1 branch\n")
target_version = get_version(target_branch)
ui.debug("got parent1 version\n")
source_branch = repo[parent2.node()].branch()
ui.debug("got parent2 branch\n")
source_version = get_version(source_branch)
ui.debug("got parent2 version\n")
# This could happen if someone does
# hg update 1.1-branch
# hg branch 1.2-branch
# hg merge 1.0-branch
# which is a strange thing to do. So disallow it.
if target_branch != branch:
ui.warn('PREVENT BAD MERGE HOOK FAILED : \n'
'merging to a different branch from first parent '
'is just weird: please don\'t do that\n')
return True
ui.debug(source_branch, "\n")
ui.debug(str(source_version[0]), "\n")
#ui.debug("major:", source_version[0], "\n")
#ui.debug("minor:", source_version[1], "\n")
#ui.debug("revn :", source_version[2], "\n")
ui.debug(target_branch, "\n")
ui.debug(str(target_version[0]), "\n")
#ui.debug("major:", target_version[0], "\n")
#ui.debug("minor:", target_version[1], "\n")
#ui.debug("revn :", target_version[2], "\n")
# Check for backwards merge.
if compare_versions(source_version, target_version) > 0:
ui.warn('PREVENT BAD MERGE HOOK FAILED : \n'
'invalid backwards merge from %r to %r\n'
% (source_branch, target_branch))
return True
else:
ui.debug("Not a merge\n")
# Not merging: nothing more to check.
return False