Sunday, April 22, 2012

HOW-TO: Implement single-file externals in Subversion 1.7

Over the last few days, I've managed to become at least competent at a few of the basics of Subversion. One particular issue that had eluded me was the implementation of file-level externals (svn:externals), which was new to Subversion starting with version 1.6. 

Search after search of blog post and commentary about how externals were implemented led me on a frustrating and often circular chase through the same set of mirrored references, and then back to the Subversion online manual. Finally, however, after putting together some pieces of information about how directory externals were implemented, I broke the code for file-level externals.

While most others may have mastered externals at the file level, I'm still a noob, and suspect others may be in the same boat. As a result, even if for no other reason than my own reference, I'm going to toss out my own spin on how to implement file-level externals in Subversion. This is not a ground-up discussion of Subversion - there are plenty of places that offer such information.

Basics: This implementation was tested on a Subversion 1.7.4 setup hosted on a Slackware Linux server, and accessed via TortoiseSVN 1.7.6, Build 22632, 64-bit version under Windows 7.

First, some background. 

Subversion as far back as version 1.5 supported the notion of external directories in a repository, meaning that a directory could actually deliver files from a different location when checked out. That concept was extended to files in version 1.7.

External directories are configured by applying the "svn:externals" property to the directory, and supplying as the value of that property a list of folder/URL pairs that represented local folders that were actually redirections to folders specified in the corresponding URL.

Let's say you have a project with source that will be common to multiple projects, called "Shared", and within that project is a directory called "SourceFiles." Taking a page from Subversion's documentation, suppose their "calc" project needed to avail itself of that SourceFiles folder at its trunk. To accomplish this, change to the local working copy of the calc project (c:\calc\ for our purposes here), and type

svn propset svn:externals "SourceFiles svn://server/Shared/SourceFiles" trunk

property 'svn:externals' set on 'trunk'

Running a simple "svn up" now pulls down the specified external directory.

It turns out that External files are configured by applying the same "svn:externals" property to the directory, but supplying as the value of that property a list of file/URL pairs. What confused me mightily was the Subversion 1.7 docs that said file externals were implemented the same way directories were implemented, which led me to believe you needed to create dummy files to which svn:external properties were added. What they really meant to say is that such external references were declared at the directory level just as external directories were. 

So, in practice, suppose in the above scenario you wanted to reference only the SharedClass.cs folder into calc/trunk from SourceFiles rather than the entire directory. The trunk folder still receives the "svn:externals" property, but this time gets a file alias rather than a directory alias:

svn propset svn:externals "SharedClass.cs svn://server/Shared/SourceFiles/SharedClass.cs" trunk

That, followed by

svn up


Updating '.':

Fetching external item into 'SharedClass.cs':
A   SharedClass.cs
Updated external revision to XX 

And there you have a simple external file logically assigned to one project, but physically residing in another!

I hope this helps any other SVN newcomers out there trying to accomplish the same goal!