Mercurial:命名分支与多个存储库
我们目前在相对较大的代码库上使用颠覆。 每个发行版都有自己的分支,并且修复是针对主干执行的,并使用svnmerge.py
迁移到发布分支
我相信现在已经到了更好的源代码控制的时候了,我已经在Mercurial玩了一段时间了。
虽然使用Mercurial来管理这样的发布结构似乎有两个学派。 每个版本都有自己的repo,并且针对发布分支进行修复,并将其推送到主分支(以及任何其他更新版本的分支)或使用单个存储库(或多个匹配副本)中的命名分支。
无论在哪种情况下,似乎我可能会使用类似移植的方式来挑选更改以包含在发布分支中。
我问你; 每种方法的相对优点是什么?
最大的区别在于分支名称如何记录在历史记录中。 通过命名分支,分支名称被嵌入到每个变更集中,并因此成为历史的不可变部分。 有了克隆,就不会有特定变更集来自何处的永久记录。
这意味着克隆对于不想记录分支名称的快速实验非常有用,并且命名分支对于长期分支(“1.x”,“2.x”等)很有用。
还要注意,单个存储库可以轻松地容纳Mercurial中的多个轻量级分支。 这些资源库分支可以加书签,以便您可以再次轻松找到它们。 假设你看起来像这样克隆了公司存储库:
[a] --- [b]
你破解并使[x]
和[y]
:
[a] --- [b] --- [x] --- [y]
这意味着有人把[c]
和[d]
放入存储库,所以当你拉你得到一个这样的历史图:
[x] --- [y] / [a] --- [b] --- [c] --- [d]
这里有一个存储库中有两个头。 您的工作副本将始终反映一个变更集,即所谓的工作副本父变更集。 检查与此:
% hg parents
假设它报告[y]
。 你可以看到头
% hg heads
这会报告[y]
和[d]
。 如果你想将你的版本库更新为[d]
的清理结果,那么简单地做(用[d]
的版本号替换[d]
):
% hg update --clean [d]
然后你会看到, hg parents
报告[d]
。 这意味着你的下一次提交将有[d]
作为父项。 因此,您可以修复您在主分支中发现的错误并创建变更集[e]
:
[x] --- [y] / [a] --- [b] --- [c] --- [d] --- [e]
要仅推送变更集[e]
,您需要这样做
% hg push -r [e]
其中[e]
是变更集散列。 默认情况下, hg push
将简单地比较存储库并查看[x]
, [y]
和[e]
缺失,但您可能不想共享[x]
和[y]
。
如果错误修正也会对您产生影响,您希望将其与功能分支合并:
% hg update [y]
% hg merge
这会让你的版本库看起来像这样:
[x] --- [y] ----------- [z] / / [a] --- [b] --- [c] --- [d] --- [e]
其中[z]
是[y]
和[e]
之间的合并。 你也可以选择抛开分支:
% hg strip [x]
这个故事的主要观点是:一个克隆可以很容易地代表几个发展轨道。 没有使用任何扩展名的情况下,对于“简单hg”一直是这样。 虽然书签扩展是一个很大的帮助。 它将允许您为变更集分配名称(书签)。 在上面的情况下,您需要在开发人员头上和上游头上的书签。 书签可以通过Mercurial 1.6进行推送和拉取 ,并且已经成为Mercurial 1.8中的一项内置功能。
如果您选择制作两个克隆,那么在制作[x]
和[y]
之后,您的开发克隆就会看起来像这样:
[a] --- [b] --- [x] --- [y]
你的上游克隆将包含:
[a] --- [b] --- [c] --- [d]
您现在注意到该错误并修复它。 在这里你不需要hg update
因为上游克隆已经可以使用了。 你提交并创建[e]
:
[a] --- [b] --- [c] --- [d] --- [e]
要将bug修复包含在开发克隆中,请将其纳入其中:
[a] --- [b] --- [x] --- [y] [c] --- [d] --- [e]
并合并:
[a] --- [b] --- [x] --- [y] --- [z] / [c] --- [d] --- [e]
该图可能看起来不同,但结构相同,最终结果相同。 使用克隆你必须做一点点心理簿记。
这里命名的分支机构并没有真正涉足,因为它们非常可选。 在我们改用命名分支之前,Mercurial本身是使用两个克隆开发的。 除了“默认”分支之外,我们还维护一个名为“稳定”的分支,并根据“稳定”分支制作我们的发布。 请参阅wiki中的标准分支页面,以获取推荐工作流程的说明。
我想你想要一个回购整个历史。 产生短期回购是为了短期实验,而不是像发布这样的重大事件。
Mercurial的失望之一是,似乎没有简单的方法来创建一个短暂的分支,玩它,放弃它,并收集垃圾。 分支是永远的。 我很同情从来没有想放弃的历史,但超低价,一次性分支是一个git
功能,我真的想在看到hg
。
你应该两个都做。
从@Norman接受的答案开始:在每个版本中使用一个具有一个命名分支的存储库。
然后,为每个发布分支创建和测试一个克隆。
需要注意的一点是,即使使用多个存储库,也应该避免使用transplant
来移动它们之间的更改集,因为1)它会更改散列,2)它可能会引入在更改集之间发生冲突时很难检测到的错误你移植和目标分支。 你想做一般的合并,而不是合并(总是在视觉上检查合并),这将导致@mg在他的回答结束时说:
该图可能看起来不同,但结构相同,最终结果相同。
更详细地说,如果您使用多个存储库,则“主干”存储库(或默认,主要,开发,不管)包含所有存储库中的所有更改集。 每个发行版/分支库都只是主干中的一个分支,所有发行版/分支库都会一路或另一路合并回主干,直到您想要放弃旧版本。 因此,在主要的回购和指定的分行计划中的单个回购之间唯一的真正区别就是分支是否被命名。
这应该很明显,为什么我说“从一个回购开始”。 该单一回购是您在任何版本中唯一需要查找任何变更集的地方 。 您可以在版本分支上进一步标记版本控制的变更集。 它在概念上是清晰和简单的,并且使得系统管理更简单,因为它是唯一必须始终可用和可恢复的唯一东西。
但是,您仍然需要为每个分支/版本维护一个您需要构建和测试的克隆。 这是微不足道的,因为你可以hg clone <main repo>#<branch> <branch repo>
,然后hg pull
入分支仓库只会在该分支上提取新的变更集(加上先前合并的分支上的祖先变更集)。
这种设置最适合单个拉取者的Linux内核提交模型(对于像Linus领主那样行事是不是很好,在我们公司我们称之为角色集成者),因为主要的回购是开发者需要克隆的唯一东西,拉拔者需要拉入。 维护分支回购纯粹是为了发布管理,并且可以完全自动化。 开发人员从不需要从分支机构回购/推送到分支机构回购。
这里是@ mg的例子,用于这个设置。 初始点:
[a] - [b]
在发布alpha版本时,为发布版本创建一个命名分支,比如说“1.0”。 提交bug修复:
[a] - [b] ------------------ [m1]
/
(1.0) - [x] - [y]
(1.0)
不是一个真正的变更集,因为直到您提交之前,命名分支才存在。 (你可以做一个简单的提交,比如添加一个标签,以确保命名分支被正确创建。)
合并[m1]
是此设置的关键。 与可以有无限数量的头的开发人员存储库不同,您不希望在主要的存储库中拥有多个头(除前面提到的旧的,已释放的分支之外)。 因此,无论何时在发布分支上有新的变更集,都必须立即将它们合并回默认分支(或更高版本的分支)。 这可以保证所有后续版本中都包含一个版本中的任何错误修复。
与此同时,默认分支上的开发继续朝着下一个版本发展:
------- [c] - [d]
/
[a] - [b] ------------------ [m1]
/
(1.0) - [x] - [y]
和往常一样,您需要合并默认分支上的两个头:
------- [c] - [d] -------
/
[a] - [b] ------------------ [m1] - [m2]
/
(1.0) - [x] - [y]
这是1.0分支克隆:
[a] - [b] - (1.0) - [x] - [y]
现在是添加下一个发行版分支的练习。 如果它是2.0,那么它肯定会分出默认值。 如果它是1.1,你可以选择分支1.0或默认值。 无论如何,1.0上的任何新变更集应首先合并到下一个分支,然后合并到默认值。 如果没有冲突,这可以自动完成,只导致空的合并。
我希望这个例子能让我早先的观点清楚。 总之,这种方法的优点是:
更新hg本身执行此操作:主repo包含默认和稳定的分支,稳定的repo是稳定的分支克隆。 不过,它并没有使用版本分支,因为稳定分支上的版本标签足以满足其发布管理的需求。
链接地址: http://www.djcxy.com/p/37531.html