The Mercurial Mindset - Food for Thought
By kto on Apr 17, 2007
The Mercurial Mindset
So I'm sitting in my office at home and I hear this noise in our Ornamental Pear tree outside. It's not a Mercurial user, just a squirrel, eating fruit from a fruitless tree. Why a fruitless tree is bearing fruit is beyond me, but the squirrel likes it. Hopefully the new Mercurial users will be as happy as Rocky here. ;\^)
I've been deep into the technical and developer concerns around Mercurial conversion issues for a few months now. I see the light at the end of the tunnel, most of the time anyway. ;\^) So consider this a perspective from deep in the trenches.
One brave documentation team inside Sun has actually stepped up and done the conversion from Teamware to Mercurial, and although these are not software developers, and Mercurial isn't managing Java or C source files, the experience is interesting. Some of the problems they ran into:
Using NFS, file/directory ownership and permissions for the groups was a
The standard Unix rules on user/group permissions seem to be a problem for teams that have members that belong to different Unix groups. Now you might think this is obvious, but it's often not. Teams using Mercurial with NFS or local file systems need to make sure that they have their umask and groups setup right for standard Unix file sharing.
As far as I can tell Mercurial is obeying the umask/group rules and doing the right thing, but Teamware appeared to have the avoided this issue by making sure all directories created with a 'putback' (e.g. 'hg push') had wide-open permissions (read-write for everyone), and then I assume it re-creates files as needed in those directories. In any case, Teamware did not seem to care that multiple team members didn't share the same groups, or it did this on purpose.
Multiple Heads (by accident?)
Mercurial allows for multiple branches of development, but in general I don't think this is a good idea for anyone starting out. In many cases repositories would end up with multiple heads, which is normal after an 'hg pull' that has a conflict. But the state was very confusing for new users. Doing an 'hg push' will fail telling you to 'hg update', and it would tell you to 'hg merge' and it would tell you to 'hg commit'. Well, in fact, you do need to 'hg update', 'hg merge', and 'hg commit', but the error messages didn't seem to help explain what was happening.
One confusing item in particular was the fact that even if the merge was empty, you still need to follow the 'hg merge' with an 'hg commit'. Quiting the editor when the file says "no changes", will often terminate the commit and leave you in the same state. Once the pattern is understood, they could conform, but it was considered 'odd' to be committing what appeared to be nothing.
Repeated 'hg pull' actions after this state just created more and more heads or unmerged changesets, which made it even more confusing. Once the pattern of 'hg pull && hg update && hg merge && hg commit' was established, things went much smoother.
The basic steps.
The basic steps of doing a change and pushing the change were not obvious to some people.
With Teamware you would:
bringover -p /nfs-path/parent-workspace -w /path/workspace . cd /path/workspace (cd some_dir && sccs edit files && vi/emacs files && sccs delget filename) bringover -p /nfs-path/parent-workspace . resolve putback . -OR putback some_directory/filename
The Teamware bringover and putback is a per-file operation, with the default operation being the entire workspace, but the "I'm putting back files" attitude seems to be rather burned into the soul or something. When a resolve happens, it's on a per-file basis, and you each file is resolved separately.
With Mercurial you would:
hg clone /nfs-http-ssh-path/parent-repository /path/repository cd /path/repository vi/emacs any files you want hg commit hg pull && hg update hg merge && hg commit hg push
The merge could be unnecessary, but if 'hg heads' lists more than one head, you need to 'hg merge && hg commit' to lop it off. (The 'hg commit' creates the changeset).
With Mercurial you push and pull changesets, not files. Although you can create a changeset for one file change, you still don't push files. And if changeset A was created after changeset B, you can't skip B, you'd need to push both, even if these two changesets change completely unrelated files.
No partial workspaces.
I've come to the conclusion that this is a good thing. Over the years I have been amazed at the times two supposedly unrelated file changes can cause a build failure or a runtime failure. Allowing partial workspaces or partial pushes is a risk to anyone that pulls these changes into their own repository. The integrity of the repository should be a top priority, and you can only guarantee that when you operate on the entire repository.
Maybe after we get more experience with the merge issues I'll change my mind.
I've gotten myself into a merge nightmare a few times, tried kdiff3 on the Mac but it didn't seem to work for me, or I need to RTFM. Simple merges were fine, but the nasty ones where the same lines were changed were challenging for me, and for others too. The Teamware filemerge tool ('f' command during a resolve) was quite nice, and I'm beginning to miss it. Hooking filemerge into Mercurial is possible but on a file by file basis, and when you get those 100 files to merge, that may be awkward. But it's only a matter of time before I find a good merge tool and configuration.
Hope this helps someone. I'll try and talk about the poor CVS or Subversion mindset problems with Mercurial next time, although I'm not an experienced CVS or Subversion expert, I can address the benefits of a DSCM or Distributed Source Code Management system like Mercurial.