Development and Howto02 Mar 2008 03:25 pm

I have been a big supporter of Subversion for a long time. I have used it off and on for about 3 years now and have never really had very many troubles while using it. It has always suited my needs and actually allowed me to really learn what version control is, why it’s useful and how to use it. Until recently, I have been very satisfied with its capabilities.

A Distributed Problem

When I created the MyEPICS 2.0 application, I had a vision to make a general framework which can be used outside the context of a service learning management program. Well, fast forward about two years later and I feel I have a stellar framework. I have one tiny problem though, which is that I need to make modifications inside the framework’s directory structure, without changing the main subversion repository. In other words, I have a project that I want to base upon the MyEPICS Framework, but I don’t want to use the main Subversion repository for its version control because not everything I do is going to back into the framework.

An example directory structure is below:

/
-/ME
--Core.php
--...
-/Modules
--/<--- Here is where I want to change things

Purely Subversion Option

If I were to want to do something like this, I would have to check out each Module directory individually from my own repository, and manually do each svn command in each module directory to get up to speed. Not to mention, if I want to update it server side, I must update each directory individually.

On the other hand, I could just set up a new repository for my own work, and any changes outside of the Modules directory I could manually generate a diff, and apply it to the main repository and commit, and vice versa for getting changes from the main repository. It's tedious, but can work.

Mercurial managed

With using a mercurial managed repository, I can check out the repository to some directory, and make a mercurial repository on top of that. From there, I can hg clone the repository to do any of my own work. I can play around with the modules directory, do all of my own changes, without effecting the main Subversion repository. Any time I have a change to add to the main Subversion repository, I just svn commit them. If I have a change to pull from the main Subversion repository, I just
svn update
hg commit

And I have an updated repository! The only downside is that for some reason, any clone of my main mercurial repository doesn't allow me to do my Subversion commands, such as updating and committing. There are a few directories that Mercurial doesn't see in the .svn directory, which I will have to find out why at a later date.

Making the Switch

No Central Repository

Probably the biggest difference is that there is no "central" repository to work with. This means, that any changes you create can be isolated to your environment. You can totally fork an entire project and set up your own version control, and sync up with it whenever you want w/o them really knowing. In fact, that's the entire problem that I've had working with Subversion... I couldn't find a way to do this. Now, trying to argue that there isn't a "main" repository and you'll just be wasting energy. In every project, there has to be some "official" repository which contains the "official" code. In the Linux kernel, that's Linus' repository. For other projects, they may have an "official" repository which is delegated by a select group of people.

Ignoring Files

Mercurial uses a file named .hgignore to tell it to ignore files, as opposed to Subversion using a property on the file, namely svn:ignore. In this file, you can either add single files, or regular expressions. The man page on hgignore is helpful in this case.

Meta Repositories, Tagging, and Branching OH MY!

In the case of Subversion, it is recommended that each repository contain all the tags and branches in it's repository layout, and even allows for multiple repositories contained within one large repository, thus making a meta-repository.

In Mercurial, there is no repository layout. Your repository is just your project itself, so there is no trunk, branches or tag directory. In subversion, if you wanted to branch or tag, you just copy a directory in the repository to the branches or tags and work from there. In Mercurial if you wish to make a branch, you simply hg clone hg branch (thanks luke!) it. When you want your changes to be seen, you push it back or wait for someone to pull from you. If you want to tag something, it's accomplished via hg tag.

Helpful Hint

While I was reading the mercurial red-bean book, I came across such an excellent note, I'm going to repeat it verbatim:

Note: If you’re new to Mercurial, you should keep in mind a common “error”, which is to use the “hg pull” command without any options. By default, the “hg pull” command does not update the working directory, so you’ll bring new changesets into your repository, but the working directory will stay synced at the same changeset as before the pull. If you make some changes and commit afterwards, you’ll thus create a new head, because your working directory isn’t synced to whatever the current tip is.

I put the word “error” in quotes because all that you need to do to rectify this situation is “hg merge”, then “hg commit”. In other words, this almost never has negative consequences; it just surprises people. I’ll discuss other ways to avoid this behaviour, and why Mercurial behaves in this initially surprising way, later on.

Conclusion

After working with Mercurial for a few weeks, I have a little bit better of an understanding of how it works, and enjoy using much better than I did when working on the Rubix Cube project. For now, this will allow me to have my own version control while keeping in sync with the main Subversion repository.

3 Responses to “Using Mercurial To Manage Subversion”

  1. on 07 Mar 2008 at 12:28 am Luke Hoersten

    Distributed revision control can be thought of as a repository of repositories so its not a far leap to wrap a svn repo in hg.

    Anyway, when you say that “in Mercurial if you wish to make a branch, you simply hg clone it.” This isn’t entirely correct. Cloning makes a whole new tree (repo), branches and all. So you do effectively get a new branch, but also a whole new tree. The easier and more appropriate way to branch is with the branch command. It creates a new branch in the current repository. Using clone to branch is intended for something called “big-picture branch” (like a major 1.0 release) which is not in the spirit of cheap branching. “Small-picture branches” can be used for every little feature etc. Small-picture branches are the bread and butter of Hg.

    Finally, Mercurial has a few perceived downsides. They aren’t fundamental show-stoppers but they are hurtles that some aren’t willing to take on in order to get a better revision control model.

  2. on 12 Mar 2008 at 7:53 pm Logan

    Luke,

    Thanks for pointing that out. For some reason your comment was held for approval because it thought it was spam, so I didn’t see it right away. Have you passed a turing test lately? Maybe once disqus allows importing of comments, I’ll use it :P

  3. on 18 Aug 2009 at 11:30 am Frank

    Good article, thank you.

    I also wanted to note that Luke’s last link is dead… The one enclosing the text “Mercurial has a few perceived downsides”