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

gets

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!

5 comments:

  1. Actually "That concept was extended to files in version 1.7." is incorrect, it's a 1.6 feature.

    ReplyDelete
  2. David, I'm trying to do this on a repo, but svn fails with an error when the file is in an external repository. Here's a few people discussing in detail the same error i'm getting: http://www.svnforum.org/threads/38006-svn-external-file

    Question is: can you confirm that the file you successfully added was in a EXTERNAL REPOSITORY rather than just in some other dir but in the same repo?
    I can't add files from external repos, just directories, as stated here: http://subversion.apache.org/docs/release-notes/1.6.html#file-externals

    I'm using svn 1.6, not 1.7

    Thanks,
    Daniel.

    ReplyDelete
    Replies
    1. Since I am struggling with the same problem I will ressurect this topic:

      In version 1.7.22 I get:
      svn: warning: W155019: Cannot relocate 'subdir in working copy' as it is not the root of a working copy; try relocating 'root of SVN tree' instead


      Fetching external item into 'subdir/singlefile.inc':
      svn: warning: W200007: Unsupported external: url of file external 'external single file path' is not in repository 'root of SVN tree'

      I am also wondering how the author got the external file working in SVN 1.7
      As you stated: according to the release notes it should not be possible.

      Delete
  3. David.

    Thank you for this article. Finally someone explains how the externals are structured.

    The help file describes things from a UI point of view and not a command line point of view. It certainly didn't give me the understanding that the 'Local path' field should equal the external file name.

    It works just fine now.

    ReplyDelete
  4. Really appreciate this explanation.

    You said, "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. "

    That's exactly my confusion. The documentation is not well worded, so thank you again for clearly explaining how to get this working.

    ReplyDelete