Monday, March 14, 2011

Mercurial Branches

One of the best things about a distributed version control system, like Mercurial, is how easy it is for many people to collaborate and share code and changes with each other.

In hg there are many ways of sharing changes. You can export changesets w/ the export command and send them to people. You can bundle up a bunch of changesets together with the bundle command. Or you can share your repository and other developers and can pull directly from you.

That last method where people can pull from you is the easiest, fastest, and generally the best. But it can be a real pain to make sure everyone you want can see your repo. This is where named branches can be useful.

In Mercurial you can "branch" by creating clones in "path space." This is the generally recommended way to go. But you can also create branches within the same repository without cloning a new repository. The benefit of this is you can push and pull those branches through a central repository or any other shared repository. This makes is much easier to share changes with people! It's also more efficient, both from a network traffic and disk space perspective.

For example, you could start work on a new feature in a named branch and make a fair amount of progress and decide you want some feedback from the team. You share your changes, and the team can then commit new changes and share them back to you.

If we were using clones instead of named branches, your feature changes would be in a cloned repository. If your team has a central repo, you wouldn't be able to push your clone there because you're not ready to "finalize" your work yet. So instead, you would have to host your clone so your team could pull from it. Then each team member would have to host THEIR cloned version of your clone so you could pull back their feedback.

With named branches you can leverage the shared repos you already have setup, in this case a central repo. You just create a branch, work on it, and push it to the central repo. Your team pulls from the central repo, makes updates to the branch, and pushes them back.

Here's what this would look like:
hg branch new-feature

# do some work and commit some changes...

hg push -b new-feature --new-branch #push to central repo
Note the --new-branch switch. If you don't include this switch hg will abort with a warning that the push will add new branches to the remote repo. This warning prevents you from accidentally sharing branches that haven't been shared yet. Also note that you don't have to include "-b new-feature". Hg will push all changesets in the repository by default.

Your teammates would then do this:
hg pull
hg up new-feature

# review and add feedback commits...

hg push
If the default branch has had commits added since new-feature was branched, the pull command here will print a message telling you that 1 head has been added to the repository. This head is on the new branch. If you run hg merge at this point it will abort telling you that branch 'default' only has one head. If you want to actually merge branches, you have to explicitly give it the branch name, as we'll see next.

When you're all done with the feature you can merge it back to the default branch, and close your feature branch. That looks like this:
hg up default
hg merge new-feature
hg ci -m "merge"
hg up new-feature
hg ci --close-branch -m "close" #closes the branch
hg up default

If you don't close the branch it will remain listed in the hg branches command.

And that's all there is to named branches! Just hg branch to create them, hg update to move between them, hg merge to merge them back together again, and hg commit to work on them. Easy, fast, and efficient!

No comments:

Post a Comment