命名分支与多个存储库 [英] Named Branches vs Multiple Repositories

查看:72
本文介绍了命名分支与多个存储库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们目前在相对较大的代码库上使用Subversion.每个发行版都有自己的分支,并且针对主干进行修复,并使用svnmerge.py

迁移到发行分支中.

我相信现在是时候进行更好的源代码控制了,而且我一直在和Mercurial玩弄一段时间.

在使用Mercurial管理这样的发布结构方面,似乎有两个流派.每个发行版都有自己的存储库,并且针对发行版分支进行修复,然后将其推送到主分支(以及任何其他较新的发行版分支.),或者在单个存储库(或多个匹配副本)中使用命名分支.

在任何一种情况下,似乎我都可以使用诸如移植之类的方法来挑选更改以包含在发行分支中.

我问你;每种方法的相对优点是什么?

解决方案

最大的区别是分支名称在历史记录中的记录方式.使用命名分支,分支名称在每个变更集中被嵌入,因此将成为历史的不变部分.对于克隆,将没有永久记录特定变更集的来源.

这意味着克隆非常适合您不想记录分支名称的快速实验,而命名分支则适合于长期分支("1.x","2.x"和类似名称). /p>

还请注意,单个存储库可以轻松容纳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]作为父项.因此,您可以修复在main分支中发现的错误并创建变更集[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]

这个故事的重点是:单个克隆可以轻松代表多个发展轨迹.对于不使用任何扩展名的"plain hg"来说,这始终是正确的.不过,书签扩展名是一个很大的帮助.它将允许您为变更集分配名称(书签).在上述情况下,您需要在开发头上有一个书签,在上游头上有一个书签.可以使用Mercurial 1.6来推拉书签,并且书签已经成为Mercurial 1.8的内置功能.<​​/p>

如果您选择进行两个克隆,则制作[x][y]后,您的开发克隆将如下所示:

[a] --- [b] --- [x] --- [y]

您的上游克隆将包含:

[a] --- [b] --- [c] --- [d]

您现在注意到该错误并进行修复.在这里您不必hg update,因为上游克隆已可以使用.您提交并创建[e]:

[a] --- [b] --- [c] --- [d] --- [e]

要将错误修正包括在您的开发克隆中,请将其拉​​到那里:

[a] --- [b] --- [x] --- [y]
           \
            [c] --- [d] --- [e]

并合并:

[a] --- [b] --- [x] --- [y] --- [z]
           \                   /
            [c] --- [d] --- [e]

该图可能看起来有所不同,但是它具有相同的结构,并且最终结果是相同的.使用克隆,您必须减少一些记账工作.

命名分支实际上并没有出现在这里,因为它们是可选的.在我们改用命名分支之前,Mercurial本身是使用两个克隆开发多年的.除了默认"分支外,我们还维护一个名为稳定"的分支,并基于稳定"分支进行发布.有关推荐的工作流程的说明,请参见Wiki中的标准分支页面. >

We're currently using subversion on a relatively large codebase. Each release gets its own branch, and fixes are performed against the trunk and migrated into release branches using svnmerge.py

I believe the time has come to move on to better source control, and I've been toying with Mercurial for a while.

There seems to be two schools of though on managing such a release structure using Mercurial. Either each release gets its own repo, and fixes are made against the release branch and pushed to the main branch (and any other newer release branches.) OR using named branches within a single repository (or multiple matching copies.)

In either case it seems like I might be using something like transplant to cherrypick changes for inclusion in the release branches.

I ask of you; what are the relative merits of each approach?

解决方案

The biggest difference is how the branch names are recorded in the history. With named branches the branch name is embedded in each changeset and will thus become an immutable part of the history. With clones there will be no permanent record of where a particular changeset came from.

This means that clones are great for quick experiments where you don't want to record a branch name, and named branches are good for long term branches ("1.x", "2.x" and similar).

Note also that a single repository can easily accommodate multiple light-weight branches in Mercurial. Such in–repository branches can be bookmarked so that you can easily find them again. Let's say that you have cloned the company repository when it looked like this:

[a] --- [b]

You hack away and make [x] and [y]:

[a] --- [b] --- [x] --- [y]

Mean while someone puts [c] and [d] into the repository, so when you pull you get a history graph like this:

            [x] --- [y]
           /
[a] --- [b] --- [c] --- [d]

Here there are two heads in a single repository. Your working copy will always reflect a single changeset, the so-called working copy parent changeset. Check this with:

% hg parents

Let's say that it reports [y]. You can see the heads with

% hg heads

and this will report [y] and [d]. If you want to update your repository to a clean checkout of [d], then simply do (substitute [d] with the revision number for [d]):

% hg update --clean [d]

You will then see that hg parents report [d]. This means that your next commit will have [d] as parent. You can thus fix a bug you've noticed in the main branch and create changeset [e]:

            [x] --- [y]
           /
[a] --- [b] --- [c] --- [d] --- [e]

To push changeset [e] only, you need to do

% hg push -r [e]

where [e] is the changeset hash. By default hg push will simply compare the repositories and see that [x], [y], and [e] are missing, but you might not want to share [x] and [y] yet.

If the bugfix also effects you, you want to merge it with your feature branch:

% hg update [y]
% hg merge

That will leave your repository graph looking like this:

            [x] --- [y] ----------- [z]
           /                       /
[a] --- [b] --- [c] --- [d] --- [e]

where [z] is the merge between [y] and [e]. You could also have opted to throw the branch away:

% hg strip [x]

My main point of this story is this: a single clone can easily represent several tracks of development. This has always been true for "plain hg" without using any extensions. The bookmarks extension is a great help, though. It will allow you to assign names (bookmarks) to changesets. In the case above you will want a bookmark on your development head and one on the upstream head. Bookmarks can be pushed and pulled with Mercurial 1.6 and have become a built-in feature in Mercurial 1.8.

If you had opted to make two clones, your development clone would have looked like this after making [x] and [y]:

[a] --- [b] --- [x] --- [y]

And your upstream clone will contain:

[a] --- [b] --- [c] --- [d]

You now notice the bug and fix it. Here you don't have to hg update since the upstream clone is ready to use. You commit and create [e]:

[a] --- [b] --- [c] --- [d] --- [e]

To include the bugfix in your development clone you pull it in there:

[a] --- [b] --- [x] --- [y]
           \
            [c] --- [d] --- [e]

and merge:

[a] --- [b] --- [x] --- [y] --- [z]
           \                   /
            [c] --- [d] --- [e]

The graph might looks different, but it has the same structure and the end result is the same. Using the clones you had to do a little less mental bookkeeping.

Named branches didn't really come into the picture here because they are quite optional. Mercurial itself was developed using two clones for years before we switched to using named branches. We maintain a branch called 'stable' in addition to the 'default' branch and make our releases based on the 'stable' branch. See the standard branching page in the wiki for a description of the recommended workflow.

这篇关于命名分支与多个存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆