views:

812

answers:

1

I have a number of quasi-related projects that I want to version control. In SVN I would set them up as multiple directories within a single project

/scripts  #updates in sync with project1 & project2
/project1 #requires database
/project2 #requires database
/database

Naturally other SVN layouts are possible for this toy example, but this layout has advantages:

  • I can copy files between branches while preserving history
  • I can check out only a subset of projects, eg svn co repo/project2; svn co repo/database. This saves a considerable amount of storage & time if project1 is large.
  • Easy repository management, since user access is defined once for all projects

This paradigm doesn't map well to mercurial since you can't clone a single directory of a mercurial repo. So my question is: what is the most common way to store large, closely related projects in mercurial?

My ideas:

  • Multiple repositories - loses history of files which move between projects
  • Forests - seems stalled, and I'm not sure how stable this extension is
  • Named branches with mostly unrelated content
  • SubRepos - Unfortunately I'm running Ubuntu 9.04, which only ships hg 1.1.2. Otherwise this would look like a good option
+5  A: 

Multiple repositories, Forests and SubRepos are all variants on the same idea. Forests and SubRepos just make managing projects that also use extremely recent versions of other projects easier, they don't solve the basic problem you have, which is that you lose file history when moving them between projects.

In my opinion, your best bet is to put all the directories in the same repository and wait for the Mercurial feature to allow checkout of subdirectories. The subdirectory feature is one the Mercurial team cares about, but it's not trivial to do either, which is why it hasn't been done yet. I know the Mercurial internals though, and it's definitely doable, just a lot of work.

The second best option, though I consider it really ugly, is the named branches idea you mentioned. You will still have a very weird merge operation to perform whenever you want to copy files between branches though. You will perform these steps:

  1. Update to head of the branch you want to copy the file into: hg update -C project1
  2. Merge in the branch you want to copy the file from: HGMERGE=/bin/false hg merge -r project2
  3. Revert to the head of the branch you want to copy the file into: hg revert -a --no-backup -r project1
  4. Revert the specific file you want to copy from the head revision of the merged in branch: hg revert --no-backup -r project2 path/to/file/in/project2.txt
  5. Move the file into it's place in the branch you want to copy it to: hg mv path/to/file/in/project2.txt project1/file/path/project2.txt
  6. Mark the merge as resolved: hg resolve -am
  7. And finally commit the result: hg commit -m "A merge to copy project2.txt to project1."

As I said, very ugly. And it might well only work well in hg 1.3 since I know some important bugs in the interaction of revert, merge and resolve were fixed fairly recently. (IMHO, I suspect Ubuntu is purposely behind on versions of non-bzr version control systems.)

How often do you really expect to be copying files between projects? Why would it happen? Are you sure that losing history would be that bad of a thing?

I've done something similar in Subversion for a couple of projects of my own, but my experience is that my initial feeling about which project something really belonged in was usually correct, and when it wasn't preserving history wasn't really that big a deal since the history was really only relevant to the original project the file was in anyway.

Omnifarious
Wow, thanks for the named branch steps. That's way too ugly to consider. I'll just deal with losing history–it was a fairly rare case anyway.Actually, a bigger problem than merging changes between projects is synchronizing dependencies. I.e. project1@r50 needs database@r50. This can be done with svn, although it requires a slightly more complicated checkout than I gave above.
Quantum7
Synchronizing dependencies is exactly what SubRepos and Forests are for.
Omnifarious
To further elaborate, I consider SubRepos and Forests to be an implementation of svn:externals for Mercurial, and with the Mercurial mindset that meta-data should be stored explicitly in files rather than implicitly attached to them and managed with special purpose VCS commands.
Omnifarious