Will the real hack please stand up

posted on April 15, 2007

I think I've changed my mind re: SVK and svn:externals, because it turns out this works just like you'd hope it would1:

svk mirror svn://project1/ //mirror/project1
svk mirror svn://project2/ //mirror/project2
svk sync --all
svk cp //mirror/project1 //local/project1
svk cp //mirror/project2 //local/project1/vendor/project2
svk push //local/project1

Then later do:

svk pull //local/project1/vendor/project2
svk push //local/project1

I've decided that svn:externals is the real hack. I've generally seen it used to solve two different problems: (a) exporting common modules as part of different projects stored in the same repository; and (b) importing "vendor branches" from other repositories. The problem is that it doesn't really do either well.

First, svn:externals requires a fully-qualified URI. This causes it to break if either the repository moves or the repository is accessed by different protocols. Both of those problems can be "solved" with "don't do that," but I've personally had cause for both. Obviously either of these will break people vendoring from your repo, but a URI-change shouldn't break internal module sharing. The fact of the matter is that the URI for a repo is a non-canonical name — and Subversion even accounts for this fact by generating a UUID for each repository.

Second, directly incorporating some chunk of repo into your project is rarely what you want to do. I've been guilty of this before — and am rather embarrassed thinking about it. I might be going out on a limb, but I think most vendor branches need to (a) be pinned to a known-stable version; and (b) include local modifications. For the former, svn:externals depends on either good tagging in the source project or (shiver) pinning to a specific revision. For the latter, svn:externals provides no help whatsoever. In fact, the Subversion manual chapter on vendor branches barely mentions svn:externals, preferring instead careful branch-management and merge practices2.

So I think SVK's way of doing things is quite a bit closer to a solution, although still not quite. It solves the problems discussed above, but still requires the local mirror exist (i.e., external configuration), and breaks when switching the actual source (tag, etc.) of the vendor branch3. "Here's 2 cents — go get yourself a real distributed version control system," I hear some of you saying...

1 For the SVK-unfamiliar, this is almost exactly what Piston lets you do, only in both directions.

2 And a Perl script, apparently.

3 Breaks pull and the UUID-tracking, that is. A generic smerge will still work just fine.

Commentary most sage