Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a good centralized DVCS workflow?

Tags:

dvcs

mercurial

I'm leaning toward using Mercurial, coming from Subversion, and I'd like to maintain a centralized workflow like I had with Subversion. Here is what I am thinking:

stable (clone on server)
    default (branch)
    development (clone on server)
        default (branch)
        bugs (branch)
            developer1 (clone on local machine)
            developer2 (clone on local machine)
            developer3 (clone on local machine)
        feature1 (branch)
            developer3 (clone on local machine)
        feature2 (branch)
            developer1 (clone on local machine)
            developer2 (clone on local machine)

As far as branches vs. clones is concerned, does this workflow make sense? Do I have things straight?

Also, the 'stable' clone IS the release. Does it make sense for the 'default' branch to be the release and what all other branches are ultimately merged into?

like image 549
Chad Johnson Avatar asked Jan 22 '23 08:01

Chad Johnson


1 Answers

In Mercurial, branches (created with hg branch inside the same repository) are currently irreversible. Once introduced, you can only remove them from your branch namespace by doing a history rewrite. That's why I would only create real branches if either the project lifetime is low (only a few feature branches) or branches are generic enough to remain current for many years (like "stable", "bugfix" etc.). As far as I know, branches are (as with everything else) created locally without your control, so if anyone decides to use a branch, that branch will also show up in your main repository after a pull/push.

The effect is that - in your structure - after a pull from development into stable you would also get feature1 and feature2 branches merged into stable, being quite useless. Pulling stable into development because you fixed bugs on a stable version will also merge the branch bugs into development. You can try that by creating a stable repository, clone it to development, branch to feature1 in development and pull development into stable (commit some changes between these steps): the branch name will appear with an inactive head in stable although you merged it:

stable $ hg branches
default                        4:1c3cd0d1a523
feature2                       3:82879465c5f3
feature1                       2:5d7480426f21 (inactive)
bugs                           1:116860d2d85e (inactive)

I remember that Git is able to delete branches but Mercurial has some development going on to catch up on that topic; I'm not sure this is still up-to-date, so please correct me if I'm wrong.

[Edit] According to Pruning Dead Branches in the Mercurial wiki there are 4 ways to "remove" a branch. The only way to really permanently remove a branch name and not just to close (deactivate) it is by replacing the repository with a cleaned history. [/Edit]

From what I have heard and seen, it's more common to create clones instead of a branches when using Mercurial. I remember having had the same thoughts as you when I switched from SVN to Mercurial last year. The usual approach is different from centralized version control because branching can happen at any time without central control over it, so clones are the preferred way to "branch" to not pollute the branch namespace and to keep developments seperated and flexible (you will always retrieve the full repository if you pull/clone including all branches and if you just want to branch to test something you would have to choose a unique branch name that's permanent and thus will show up for everyone in your project). Although that approach seems like a waste of disk space and you need to keep track of where your branches are (usually inside some project folder on your user account and inside your IDE), it seems to be a much more flexible and practical way of handling branches. (It reads more difficult than when you actually use it yourself.)

Having had a number of smaller projects using Mercurial, this is what worked for our company so far (with only a few active developers per project):

On the server:

projectname-main
development is being pushed to and pulled from there; this is the "authoritative" development "branch" to keep a team's repositories in sync

projectname-stable
if a version gets released/deployed this is where -main gets pushed to; only bugfixes are done in -stable and then pulled back to -main: Following the advice from the Mercurial Guide by Bryan O'Sullivan, bugfixes to versions considered more stable (e.g. previous releases) can usually be pulled back into development branch but changes in the development branch can contain newer, unstable features that should not be pulled into a maintenance branch unless a release (or similar) happens.

Locally on developer machines:

projectname-main is cloned once, being worked on and synchronized by doing a pull (+merge) and push back to the server regularly.

If there's a feature "branch" needed we clone -main (either locally or from server) and name the clone "projectname-featuredescription". For backup purpose or centralized sharing we also create a clone on serverside and push there. If the feature is ready for -main, we pull -featuredescription into our local -main, merge the changes, pull -main from server, merge again and push -main back to the server. If changes happen to -main while we work on -featuredescription we can easily pull from -main and merge the changes (without pushing back to -main yet because we don't want the feature to be there yet).

The downside compared with real branches is that you won't be able to easily recognize where changesets came from after they are merged with one of their parents. But that hasn't been a problem for us yet (commit messages were useful enough or the separation of feature branches was uninteresting once they were merged with their parent repositories).

Thinking of bigger projects I came up with the following scheme that should work (but which I didn't use yet) similar to a centralized version control. It relies on restricted write access to the server side "authoritative" repositories, so only privileged developers (project lead) are allowed to merge and push there. Additionally, there's a CI server as a gatekeeper to another repository -main-tested which is a subset of -main containing only CI approved changesets with a slight delay.

On server:

projectname-main
development; only a few people have write access, changes going to main need to be pulled by them; they are in control of what feature branches are merged

projectname-main-tested
development; noone should write here unless something went wrong, because tested means a Continuous Integration system succeeded in building -main and pushed that revision into -main-tested, so code in here is verified and should not break compilation or tests

projectname-stable
projectname-stable-tested
same strategy for a stable "branch"; as before, we push -main to -stable on releases and work on bugfixes, -stable-tested is CI approved

And of course there need to be multiple repositories somewhere where teams/developers can actually push their daily work to since -main is now for authoritative changes only (of course they can work entirely locally but they have to sync somewhere if they don't like to peer with each other using hg serve or setup their own servers or care for backup).

Another option to reduce commits and repositories/branches would be to use the mq extension to working with a patch queue. However, I find using clones or branches easier, at least for small projects.

like image 137
Energiequant Avatar answered Feb 26 '23 17:02

Energiequant