Mercurial is my first serious foray into distributed version control systems (dvcs). When I started gathering my notes for this entry I knew that this would be a really negative review of Mercurial. The first version control system I actually liked was Perforce. Several years later I encountered Subversion, it took a while to adjust but eventually I grew really fond of it. For the past 3 months, I’ve been using Mercurial… definitely not impressed. Or so I thought, but as I looked through my cons, I saw pros all over the place. So here are my [not-so-negative-after-all] thoughts on using Mercurial!
As background, the setup I’m working with uses BitBucket as a central repository.
The repository
Con: When I clone the repository, I get the whole repository. I don’t need the whole repository. The project I work on is growing, there are lots of files, and I just don’t want or need all of them. Old images that aren’t used any more, get downloaded to my machine. Files that were created and deleted long before I ever joined the project, get downloaded to my machine. Developers discuss whether to push large files to the system or not, because they don’t want them to get downloaded to their machines. It’s a pain!
Pro: or… at least I thought it was a pain. Waiting half an hour for that initial clone is a pain, but I really appreciated having access to the entire repository one day when I had no internet access. I could easily look up the changes made, and to be honest, it was great having the history on files that were long removed. That’s the point right, that you can delete instead of commenting out because you have access to the entire history in the version control system. I had that access in a car without internet. It was great!
Merging
Con: Mercurial is so good at merging. This is one huge selling point for Mercurial, but it just annoyed me. Of course Mercurial has to be good at merging.. since it’s merging all the time. A good 75% of my commits are merges. All I want to do is to push my changes, but I can’t, because I need to merge!! Aaaargh!
Pro: Well… Mercurial is good at merging! When I do change a file that someone else has also changed, it’s a much simpler process to merge and resolve conflicts in Mercurial, what would have taken quite a while in Subversion, ends up being a piece of cake 🙂 And to be honest, the extra step of auto-merging after an update and pull is painless since it usually doesn’t fail.
Pushing partial changes
Con: I can’t push if I have uncommitted files, and I can’t just push some of my commits but not others!! Sometimes, you have to make a quick change that has nothing to do with what you’re working on. You notice that there’s a spelling mistake, or you want to push formatting fixes to a file so you can keep working in it, but you can’t, because you have other uncommitted changes. It’s a pain!
Pro: Well, I actually really like the ideology behind this feature. Really, how do you know if the partial code you want to push actually works without all the other changes you’ve made. Of course it makes sense that you can only push everything. You should have tested the exact configuration that you now want to force on everyone else. How can you not like this feature?! Gone are the days of forgetting to add a file to subversion, committing and only realizing that you forgot the file when the CI build lets you know. Now you know. And if you just want to make a one-off change, it’s pretty easy to make a local clone from your repository, and just push that one little change. So it’s a couple of more steps, but it’s worth knowing that you aren’t accidentally breaking the build.
Branches/tags
Con: Working with branches and tags is a pain! The BitBucket view is not good at showing you the history for a branch, you definitely have to use a different tool. The tags are not “intuitive”, the whole process is frustrating..
Pro: Get over it, I don’t even work with branches that often, and don’t particularly care for them, not sure how this made my con list to begin with!! This is one area where the cons were just a matter of letting go of my Subversion idea of tags and branches. Once you understand how tags and branches work in Mercurial, the whole thing is pretty easy and painless. Moving between branches in particular is so conveniently easy! hg up [branch-name], what’s not to love?
Plugins and tools
Con: Lack of plugin support in IntelliJ. I miss seeing incoming changes in the changes tab. I miss being able to easily see all changes made in a changelist. I also get annoyed at having to see the three separate commits one person made as part of the single bigger push. Sometimes it’s interesting to see the different steps that the person took, but really I mostly just want to see the difference between the original file and the final commit.
Pro: You know, this is one con that I can’t find a pro for. I’ve tried different tools (MacHG) is currently my favorite, but support is still far from perfect. I’ve gotten used to the BitBucket web UI and can get the information I want, but I’m still on the look out for a better solution here.
So, while I still can’t say that I love Mercurial, I definitely don’t hate it, and after writing up this post I can honestly say that I like it.
Anyone else out there making the transition to Mercurial? What about other dvcs?
p.s. A good resource for learning about Mercurial is Brian O’Sullivan’s book “Mercurial: The Definitive Guide”
Get in touch via my homepage if you have questions or comments!
Great article!
I agree the IntelliJ support could (and should) be better. At least it’s equally bad for git.. 🙂
One thing to add is that the “glog” plugin makes it a lot easier to understand the change log. To install it, just add:
[extensions]
hgext.graphlog =
to your .hgrc file. Then run “hg glog” in your repository.
One annoying thing for me is the fact that I get lots of warnings when I run commands against the remote repository from my Mac. Like so:
warning: pvp.repositoryhosting.com certificate with fingerprint … not verified (check hostfingerprints or web.cacerts config setting)
That’s all for me.. 🙂
Thanks for the suggestion! This page has instructions for installing/specifying a certificate to get rid of the annoying warnings: http://mercurial.selenic.com/wiki/CACertificates It took just a couple of minutes to fix on the mac.
That worked like a charm, no more annoying messages, thank you Yassal!
Our company made the translation about 2 years ago. Many of your points reflect what we had to fight with in the beginning, too. Today, though, nobody would want to go back. DVCS just IS a better concept than centralized VCS like Subversion.
“Loving” is a strong term regarding this tool. I wouldn’t say I really love Mercurial, but I love the possibilities it offers. That said, I certainly don’t hate it, either. Now Git, OTOH, I have a bit of a sentiment against. Not for the tool per se – it is a great piece of programmer’s craftsmanship – but against the fanboyism surrounding it.
Since I know that there are a couple of things you can’t see immediately if coming from SVN, let me comment on some of your cons:
When I clone the repository, I get the whole repository. I don’t need the whole repository. The project I work on is growing, there are lots of files, and I just don’t want or need all of them.
This is so true. One of the biggest shortcoming of ALL DVCS out there. I’d like to see the implementation of so-called “shallow” and “narrow” cloning, too. Basically, it would allow you to clone a repository only down to a certain revision (shallow), or only a certain subset of the tree (narrow). For the former, Git already has a partial implementation (unfortunately not of practical use since it only allows you to pull-in, but not to push-out). For the later, Mercurial has a partial implementation (unfortunately only for the “update”, not for the clone itself).
I think regarding narrow cloning, Mercurial is not so far away anymore. Shallow cloning might be better done with Git (due to the object database instead of a revlog database), but the whole concept is much more complicated than with narrow cloning. Let’s see what they’ll come up with…
Of course Mercurial has to be good at merging.. since it’s merging all the time. A good 75% of my commits are merges. All I want to do is to push my changes, but I can’t, because I need to merge!!
This is not completely true. You can use Mercurial’s SVN-style “update to children while merging outstanding changes” to keep linear history. You can use the rebase command to do it after-the-fact. You can also push your changes with force to create 2 heads on the “central” repository. It really is up to your workflow, not to Mercurial. Of course, the merging approach is encouraged, and IMHO rightfully so. It reflects the real history of commits, not a fake you might want due to aesthetically reasons. And the merge engine is running much better with it, too.
I can’t push if I have uncommitted files, and I can’t just push some of my commits but not others!! Sometimes, you have to make a quick change that has nothing to do with what you’re working on. You notice that there’s a spelling mistake, or you want to push formatting fixes to a file so you can keep working in it, but you can’t, because you have other uncommitted changes.
This is plain wrong. You can always push and pull with uncommited files. Maybe some IDE integrations skews this picture for you, but the plain command-line never ever prohibited you from pushing or pulling with outstanding changes.
You can push selectively by means of the “–rev” option. Just issue “hg push –rev [the_commit_up_to_which_my_history_should_be_pushed]”.
You can also commit selectively by means of the file arguments. Just issue “hg commit [file_I_want_to_push]”.
The tags are not “intuitive”, the whole process is frustrating..
Well, IMHO they are even more “intuitive” than SVNs tags. Since in the later case you have a rather cryptic copy command that even comes in different flavors (client copy, server copy, etc.), I much prefer the single “hg tag” command.
Granted, Mercurial’s way of commiting a “tagging commit” seems like crazy at first glance, but keep in mind that it is actually the same with SVN: the “tagging copy” is an additional revision in the log. Now here Git is very different. It treats tags as mere pointers to the history, making them unversioned by concept, and prone to special transfer mechanisms outside the “normal” history transmission.
All in all you made a good post summarizing the pitfalls in this paradigm shift, because in the end that’s what it is.
Thanks for all the feedback!
Hey Yassal, I’m not used to Mercurial since I’m a long running Git user. But they are really quite the same thing. Nice to read your thoughts.
Regarding “Pushing partial changes”, that’s why we have branches. And, at least in Git, stash. As you’ve said, merge is simple, so why not fork (create branches) your commits until everything is stable?
And tag is a very useful tool for mobile/desktop tools. It flags better what users are, really, seeing. Not that useful for websites.
best regards,
Otávio
Yes, forking is the reasonable option here. Thanks for your input!
Great summary of the strengths and weaknesses from a developers point of view!
When I want to quickly get something done on a tangent, I am glad I started using the hg mq extension for patch queues. I am trying to stay more focussed and task driven though, overall. Hence this comment, indeed… Back to work!