Question

I have some troubles in checking out a tagged version in my svn repository and most likely because of an inner 'svn:externals' that is not referring to the correct revision. Lets consider simplified situation:

I have a first svn repository which looked like this at revision XXX1:

Repo1 (@ Rev XXX1)
  tags
    ...
  trunk
    Folder1
      ExternalRefToFolder2 (svn:externals '../Folder2')
    Folder2
      SomeFile1.txt
      SomeFile2.txt

And which has been refactored to (at head revision):

Repo1 (@ HEAD1)
  tags
    ...
  trunk
    Folder1
      SomeFile1.txt
      SomeFile2.txt

I.E: For the good or for the bad, the external reference to Folder2 has been removed and replaced by file copy between revisions XXX1 and HEAD1.

I also have a second repository on the same server which looks like this:

Repo2 (@ HEAD2) 
  tags
    1.0.0
      ExternalToRepo1 (svn:externals -rXXX1 ^/../Repo1/trunk)
  trunk
    ExternalToRepo1 (svn:externals ^/../Repo1/trunk)

I.E.: Again, for the good or for the bad, the second repository is referencing first one using an external reference (revision HEAD1 in trunk and revision XXX1 in tagged version so as to freeze everything at correct revision).

The issue

  • When I'm checking-out the trunk of Repo2, I have no issue. That is Repo1 is checked-out with its single Folder1.

  • When I'm checking out the tag 1.0.0 of Repo2, then svn complains that it cannot find http://server//Repo1//trunk//Folder2 at HEAD1 revision.

So it all looks like that even if the tag 1.0.0 is referring to Repo1/trunk in its correct XXX1 revision; the inner external svn:externals '../Folder2' is interpreted as if based from HEAD1 (instead of revision XXX1 as I would have had expected).

Is this behavior normal, and how may I work around the issue ?

NB: Svn version I have is 1.7.8 (r1419671) compiled december 12th, 2012

Edit

Another way to reproduce the issue is to check-out or simply browse Repo1 at revision XXX1. svn:externals '../Folder2' will then still be relative to HEAD1 so guess there's no much solution.

Was it helpful?

Solution 2

Using svn:externals as a poor man's dependency management or code duplication avoidance scheme are the source of your woes. Nesting them is not double bad, it's multiplicative. I recommend this excellent long answer about the badness with externals

You're never going to have great results using svn:externals for internal stuff, however if you keep using them you can mitigate the pain by:

  1. Follow the advice of the red book and never make an external pull in the head:

You should seriously consider using explicit revision numbers in all of your externals definitions. Doing so means that you get to decide when to pull down a different snapshot of external information, and exactly which snapshot to pull. Besides avoiding the surprise of getting changes to third-party repositories that you might not have any control over, using explicit revision numbers also means that as you backdate your working copy to a previous revision, your externals definitions will also revert to the way they looked in that previous revision, which in turn means that the external working copies will be updated to match the way they looked back when your repository was at that previous revision. For software projects, this could be the difference between a successful and a failed build of an older snapshot of your complex codebase.

  1. If you don't do the above, create your tags with svncopy.pl. It will 'pin' the revisions of your externals to whatever they are when you create the tag.

You didn't mention why you have multiple repositories - is it possible you may benefit from consolidation?
You didn't mention what language/tooling your working with. I'm pretty sure there is a better way for you to meet your requirements. For example, if it's a java app with a few librairies you're pulling in via the externals - you'll be happier if you build the libraries separately and publish them using some maven like substance and then resolve them when you build your app.

OTHER TIPS

For the first sight it looks a bit strange, but you will find next it works as intended.

SVN assigns revision numbers for particular commit set which can contain not just changes, but additions or removes of directories, files, properties and links (so called tags or branches) created through the svn copy. SVN does not really copy directories as it comes from the file systems, instead it links it's content to a new directory. When all links (original and copied directories) are removed the content left "suspended" (but not actually deleted) in the depths of the SVN history. You can any time to update to the last revision has contained that last link to the directory content.

Externals are just like the links what you can set to external repository but opposite to the links what always maintained by the same repository the externals content can't be actually "suspended" because it is controlled from other side, from the repository contained external's content. In another words the repository has contained an external link and the repository stored a content for it can maintain totally different addresses and be on different machines.

That's why what kind of error happens where you have to set correct revision number for the external otherwise external link will take the last one, the HEAD. And your ExternalRefToFolder2 takes the head revision when the content is already absent. Either set the external revision explicitly or use svn copy.

But remember, svn copy creates links but with it's own content history. That means all commits to the link-to-revision Folder2 won't change content by the link-to-revision ExternalRefToFolder2/Folder2 and vice versa.

So the same way works the nested links and externals. It is just another level of reference. You have to set (and commit associated properties) particular revision for all externals on the way to take exact directory tree structure/content from the root.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top