Mercurial 功能、稳定版本等的存储库结构
如果需要的话,我会更具体地提出一个问题,或者如果你们都认为它适合的话,我会将其制作成社区维基,但我的问题是:
我的开发团队最近开始使用 Mercurial(从 subversion 迁移),我们到目前为止很喜欢它。我想知道是否有关于存储库架构的“最佳实践”资源。我感兴趣的是,在处理功能和新版本时留下稳定的存储库副本(用于运输/紧急错误修复)的最佳方法是什么。我读过很多关于命名分支与克隆存储库的文章,我希望你们中的一些人能够阐明什么对您的团队有用。
在某个功能经过测试并为下一个版本做好准备后,什么更容易合并?我提到的两种方法有什么严重的缺点吗?还有其他回购管理策略吗?
我们即将部署 2.0.0 版本,我希望在它发布后以一种使用 hg 的新方式重新开始。
让我重新表述一下我仍在努力解决的一些基础问题 - 假设我明天完成 2.0.0...我想开始开发 2.1.0,我该怎么办?克隆我的存储库,将其命名为“working/projects/widgets2.1”并继续滚动,让我的“workin/projects/widgets2.0”坐在那里准备好用于错误修复情况?
此外,如果客户打电话说有bug,并且widget机器摇晃并且开始冒烟,我是否要弹出widgets2.0,修复bug,部署到服务器,然后提交/推送?然后我是否要返回到 widgets2.1 并拉动/合并该错误修复?
I will be more specific with a question if I need to be, or make this into a community wiki if you all think that's where it fits, but my question is:
My dev team has recently started using Mercurial (moved from subversion) and we love it so far. I'm wondering if there is a 'best practices' resource out there about repository architecture. What I'm interested in is, what is the best way to leave a stable copy of the repo (for shipping/emergency bug fixes) while working on features and new versions. I have read a lot about named branches vs. cloned repositories and I'm hoping some of you hg guys can shed some light on what works for your team.
What is easier to merge after a feature has been tested and is ready for the next release? Are there any serious drawbacks to the 2 methods I have mentioned? Are there other repo management strategies out there?
We are nearing the deployment of our 2.0.0 release and I'm looking to start fresh once it is out with a new way of working with hg.
Let me rephrase to hit on some basics that I'm still struggling with - Let's say I finish 2.0.0 tomorrow... I want to start work on 2.1.0, what do I do? Clone my repo, name it "working/projects/widgets2.1" and keep rolling along, having my "workin/projects/widgets2.0" sitting there ready to be used in bug fixing situations?
Further, if the customer calls and says there is a bug and the widget machine is shaking and smoke is starting to billow, do I pop open widgets2.0, fix the bug, deploy to server, then commit/push? Do I then go back over to widgets2.1 and pull/merge that bug fix?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
据我所知,您所问的是如何处理 Mercurial 中的不同开发分支。在您的示例中,您希望能够轻松地发布对发布版本的修复,而不必处理自上次发布以来开发分支中发生的所有内容。
Mercurial 中有多种处理分支的方法。您可以使用单独的存储库、命名分支和书签扩展等。您选择如何在 Mercurial 中处理分支与您拥有的工作流程类型相关,但有许多可能的组合。
考虑到这一点,我将为分支之间的工作流程提供一些一般性建议,无论它们在 Mercurial 中如何表示(作为单独的存储库、命名分支等)。如果您想了解有关选择哪种分支模型的更多信息,我建议您阅读 Steve Losh 的 Mercurial 分支指南 以及我关于 在 Mercurial 中选择分支模型。
首先,即使根本没有分支,您仍然可以随时返回到代码的早期版本,例如 2.0 版本,并修复那里的错误。这将使标记和发布新版本(例如 2.0.1)变得容易,唯一的变化是错误修复。
您只需更新、修复和提交即可完成此操作:
上面假设您已标记 2.0 修订版,因此很容易获取它,否则您将必须提供哈希或修订 ID。
这将为您提供两个头,您可以使用
hg merge
合并它们,将修复带回到开发版本中。如果您有 2.0 版本的单独存储库,则可以在那里进行修复,然后将其拉入开发存储库,然后在其中进行合并。基本原则是 Ry4an 概述的,您可以在尚未进行大量您不想要的其他更改的情况下进行更改。
这是一个例子:
在我工作的地方,我们有许多代表不同分支的存储库。大多数开发发生在“dev”分支中。当版本临近时,我们将该存储库克隆到一个名为“release-2.4”的新存储库中。在此分支/存储库中,我们测试并修复即将发布的版本的错误。更多的实验性开发要等到下一个版本才能准备好,可以在“dev”中并行进行。
当版本经过测试并准备发布时,我们将“release-2.4”中的所有内容提取到“prod”中,其中仅包含已发布版本的代码。我们用版本号标记它并向全世界发布。然后我们可以删除“release-2.4”分支,并将所有内容从“prod”拉到“dev”中。这可能需要合并,但随后我们将发布过程中所做的所有更改都返回到“dev”中,并且可以继续开发下一个版本。
如果我们想修复更大的计划版本之外的错误,我们可以通过几种方法来实现。如果修复很小(几次提交)或者不涉及很多开发人员,我们可以直接提交到“prod”,标记发布并发布它。之后,我们从“prod”拉入“dev”,以确保修复也存在于下一个版本中。
如果错误修复版本更大并且需要更多时间,我们可以从“prod”创建一个新分支,在那里完成发布上的所有工作,然后将更改拉入“prod”。当它发布到“prod”时,我们可以从“prod”“拉”到“dev”以获取其中的更改。然后可以删除特殊发布分支。
As far as I can tell, what you're asking about is how to handle different branches of development in Mercurial. In your example, you want to easily be able to release fixes to the release version without having to deal with all the stuff that has happened in the development branch since the last release.
There are many ways to handle branches in Mercurial. You can use separate repositories, named branches and the Bookmarks extension among others. How you choose to handle branches in Mercurial is related to the type of workflow you have but there are many possible combinations.
With that in mind, I will give some general suggestions for workflow between branches, regardless of how they're represented in Mercurial (as separate repositories, named branches etc). If you want to learn more about what branching model to choose I suggest you read Steve Losh's guide to branching in Mercurial and my blog post on choosing a branching model in Mercurial.
First of all, even with no branches at all, you can still always go back to an earlier revision of the code, e.g. the 2.0 release, and fix the bug there. This will make it easy to tag and release a new version (say 2.0.1) with the only change being the bug fix.
You do this by simply updating, fixing and committing:
The above assumes you have tagged the 2.0 revision so it's easy to get at it, otherwise you will have to supply a hash or revision id instead.
This will give you two heads, which you can merge with
hg merge
, bringing the fix back into the development version.If you have a separate repository for the 2.0 release, you make the fix there and then pull it into the development repository where you then merge. The basic principle is the one Ry4an outlined, you make the change where there isn't already a bunch of other changes made that you don't want.
Here's an example:
Where I work we have many repositories representing different branches. Most development happens in the "dev" branch. When a release nears, we clone that repository into a new one called say "release-2.4". In this branch/repo we test and fix bugs for the upcoming release. More experimental development that won't be ready until the next release can happen in "dev" in parallel.
When the release is tested and ready to go out, we pull everything from "release-2.4" into "prod", which only contains released versions of code. We tag it with a version number and release it to the world. We can then delete the "release-2.4" branch, and pull everything from "prod" into "dev". This might require a merge, but then we have all the changes made during the release process back in "dev" and can continue working on the next release.
If we want to fix a bug outside the bigger planned releases, we can do it a couple of ways. If the fix is small (a couple of commits) or doesn't involve many developers, we can just commit directly to "prod", tag the release and the ship it. After that we pull from "prod" into "dev" to make sure the fix is there in the next release as well.
If the bug fix release is larger and will take more time, we can instead make a new branch off "prod", do all our work on the release there, and then pull the changes into "prod". When it's released into "prod", we can then "pull" from "prod" into "dev" to get the changes there. The special release branch can then be deleted.
我希望早些时候听到的建议是“尽早修复错误”,我的意思不是在编码之后立即修复。我的意思是,如果您正在修复两年前第 400 号变更集中引入的错误,您应该这样做:
Mercurial 会说“已创建新头”,这乍一看似乎令人震惊,但您所做的是创建一个变更集(实际上是一个匿名分支)可以将其
hg pull
插入到任何有错误的分支中。在我弄清楚这一点之前,我们会修复发布分支、开发分支或其他一些活跃的开发线上的错误,然后我们希望将该修复移至其他分支,但无法做好。原因是当您拉动(分支作为克隆)或合并(命名或匿名分支)时,有严格的要求,如果您拉动/合并变更集 X,那么您正在拉动/合并变更集 X 的所有祖先 - 但是您不一定想要所有这些祖先(这可能是新的、实验性的功能),你只是想要错误修复。
在没有其祖先的情况下移动更改需要通过导入/导出或移植或其他一些带外机制“挑选”一种形式的另一种形式。
但是,如果您制作错误修复变更集,使其唯一的祖先是首次创建错误的变更集,那么您始终可以将修复“hg pull”到任何有错误的分支中,而无需携带任何其他内容。
只是为了将其更多地带回您的原始查询,如果您使用克隆作为分支(我的偏好)或命名分支,我上面的建议同样适用。
The piece of advice I wish I'd heard earlier on is to "fix the bug as early as possible", and I don't mean right after you code it. I mean that if you're fixing a bug that introduced in changeset number 400, two years ago, you should do:
Mercurial will say "new head created", which seems alarming at first, but what you've done is create a changeset (an anonymous branch actually) that can be
hg pull
ed into any branch that has the bug.Before I figured that out, we'd fix the bug in the release branch, or in a development branch, or on some other active line of development, and then we'd want to move that fix to other branches, and couldn't do it well. The reason being when you pull (branches as clones) or merge (named or anonymous branches) there's the firm requirement that if you're pulling/merging changeset X then you're pulling/merging all the ancestors of changeset X -- but you don't necessarily want all of those ancestors (which might be new, experimental features) you just want the bug fix.
Moving a change without its ancestors requires "cherry picking" of one form of another, either via import/export or transplant or some other out-of-band mechanism.
If, however, you make your bugfix changesets such that their only ancestor is the changeset in which the bug was first created then you can always 'hg pull' that fix into any branch that has the bug without bringing anything else with you.
Just to bring it back to your original query a little more, what I'm suggesting above is equally applicable if you're using clones as branches (my preference) or named branches.
这是一个很好的“结构”教程:
http://hginit.com/05.html
我也开始使用Mercurial 在非常熟悉 Subversion 后,我对这次切换感到非常满意 —— hg 确实为我解决了一些问题。我基本上不理会任何“命名分支”,只依靠负责人来完成我的工作。我确保充分使用日志来确定当我需要返回到旧版本时需要去哪里。当然,标签也非常好,本教程涵盖了这一点。
Here's one nice "structure" tutorial:
http://hginit.com/05.html
I too started using Mercurial after being quite familiar with Subversion, and I'm quite happy with the switch -- hg definitely solved some problems for me. I basically don't bother with any of the "named branches" and just rely on the heads to do my work. I make sure that I use the log adequately to figure out where I need to go when I need to go back to an older revision. Of course, tags are really good too, and the tutorial covers that.
我工作的公司很乐意迁移到 Mercurial,并考虑为正在开发的每个功能支持“功能分支”。功能分支是一个命名分支,其中包含一些新的开发或对现有功能的更新 - 基本上,无论您想要什么。
功能分支仅存在于用户的存储库克隆中,直到它们准备好集成到开发主线中,此时它们会合并回活动开发分支中。如果您有人担任构建经理角色,则可以将功能分支推送到未合并的共享存储库,并且经理可以根据需要合并它们。如果不这样做,开发人员可以将它们合并到克隆的存储库中,然后推送已合并的分支。 (旁注:Hg 仍会在共享存储库中显示合并的功能分支)
一旦共享存储库更新到稳定点,就可以对其进行标记和发布。错误修复可以应用于标记版本,如果需要延长或并行开发,可以使用标记版本作为父版本创建第二个活动开发分支。 Ry4an 的错误修复方法也可以应用在这里。
可以使用功能克隆而不是功能分支来复制整个工作流程,但它改变了一些开发动态。如果您有能力尝试每个版本,那应该有助于您和您的团队做出决定。
进行编辑以解决您新添加的具体问题
在此方案中,您将在 2.0.0 完成时创建一个标记,然后在 default 分支上继续处理 2.1.0。后续提交到 default 分支以及从此时开始的任何新功能分支都将支持 2.1.0。
2.0.0 的错误修复将通过更新到 2.0.0 变更集(即:标签)然后创建一个新的命名分支(可能称为version2.0.0)来进行。该分支永远不会完全合并到默认分支中,该分支现已转移到 2.1.0 开发,并且该分支可能会无限期地保持开放状态。它将包含所有基于 2.0.0 的错误修复。
一旦修复了 2.0.0 的错误,您可以通过多种方法将特定的 chagneset 从 2.0.0 移动到默认 (2.1.0) 分支。您可以创建特定变更集的补丁并将其应用到 default 分支,也可以执行从 version2.0.0 到 default 的合并如果有道理的话。
The company I work for is entertaining migrating to Mercurial and thinking about supporting 'feature branches' for each feature being developed. A feature branch is a named branch that contains either some new development, or updates to an existing feature - basically, whatever you want.
The feature branches exist only in a user's repo clone until they are ready to be integrated into the main line of development at which point they get merged back into the active development branch. If you have someone in a build manager role, the feature branches can be pushed to a shared repo un-merged and the manager can merge them as needed. If you do not, the developers can merge them in their cloned repos and then push the already merged branch. (Side note: Hg will still show the merged feature branch in the shared repo)
Once the shared repo has been updated to the point of stability, it can be tagged and released. Bugfixes can be applied to the tagged version, and if prolonged or parallel development is required, a second active development branch can be created with the tagged version as the parent. Ry4an's method for bugfixing can be applied here as well.
This whole workflow can be duplicated using feature clones instead of feature branches, but it changes some of the development dynamics. If you can afford to give each a try for a release, that should help you and your team decide.
edit to address your newly added specific question
In this scheme you would make a tag when 2.0.0 is completed and then continue work on 2.1.0 on the default branch. Subsequent commits to the default branch and any new feature branches starting from this point on will support 2.1.0.
Bugfixes for 2.0.0 would be made by updating to the 2.0.0 changeset (ie: the tag) and then creating a new named branch (maybe called version2.0.0). This branch is never merged wholly into the default branch which has now moved on to 2.1.0 development, and this branch will likely remain open indefinitely. It will contain any 2.0.0-based bugfixes.
Once you have made a 2.0.0 bugfix, there are several ways you can move a specific chagneset from 2.0.0 to the default (2.1.0) branch. You can create a patch of a specific changeset and apply it to the default branch, or you can perform a merge from version2.0.0 to default if it makes sense.