Vendor Branches in Subversion

Subversion vendor branches are something I've always ignored. Over the years I've developed a healthy fear of branching and merging, although it is common in developing Sound Juicer. Systems like Arch make it less scary as it keep track of atomic changesets, so making it harder to loose half of a change, but I'm using Subversion at the moment until Bazaar or bzr-ng is convincing enough (and well documented enough) for me to switch. Of course, at some point I knew I I'd need to use vendor branches but I put off learning exactly how they work (beyond "you branch and merge and it works") until I needed to. That point happened last week.

I read the Subversion book, which confused me a bit and pointed me towards svn_load_dirs, which has both a man page and a README, neither of which make a great deal of sense. So here I presume my summary, titled Vendor Branches In Subversion Without The Scary Details You Don't Need To Know.

Step 1 is to grab a copy of the upstream source. If you are taking snapshots from CVS use cvs export and not cvs checkout, otherwise you'll be committing the CVS/ directories into Subversion.

$ cvs export -r HEAD -d foo-20050504 foo

This will grab a copy the foo module from the tip, and put it into a directory called foo-20050504. As this is an exported copy of the source and not a checkout you cannot run any CVS commands on it, but that is not a problem as it will be deleted again in a few minutes.

If the upstream source is a tarball, extract it and make sure these is nothing hanging around which should not be in Subversion (such as generated files). Now to import it into Subversion.

$ svn_load_dirs svn+ssh://svn/repos/foo/ -t upstream/foo-20050504 upstream/current foo-20050504/

This needs some explaining. The first argument is the location of the repository, I assume that this has already been created. The second argument specifies that this import should be tagged upstream/foo-20050504, the third argument specifies the location to import the source too (upstream/current), and the forth and final argument is the path locally to import. Running this command will result in it asking a few questions to verify the tags, and then will churn for a few minutes as it does the import.

You'll want to import into a vaguely named directory such as current so that Subversion keeps a history of the upstream changes. Creating a tag for each version imported is essential for sanity: it will be used later on and if anything breaks it is trivial to extract known-good versions.

Now that the source is imported, it is time to create a local branch.

$ svn copy svn+ssh://svn/repos/foo/upstream/foo-20050504 svn+ssh://svn/repos/foo/trunk -m "Bring foo-20050504 into main branch"

This makes a copy of the imported source into /trunk/, which you can happily hack away on.

time passes...

Now it's the 1st June, and there is a new copy of Foo to be imported. Again, get a pristine copy and repeat the svn_load_dirs.

$ svn_load_dirs svn+ssh://svn/repos/foo/ -t upstream/foo-20050601 upstream/current foo-20050601/

This is where the magic really happens. svn_load_dirs will grab the current copy of current and compare it with the new drop. If there are any deleted or added files it will show them to you, so you can identify any file renames (thus both preserving history and saving space). It will then commit the new files into Subversion, and create a new tag. Then you can go into your working copy of trunk and merge the upstream changes with your own.

$ svn merge svn+ssh://svn/repos/foo/upstream/foo-20050504 svn+ssh://svn/repos/foo/upstream/current

This command will get the changes made in inbetween the 20050504 drop and the latest drop, and apply them to the current working directory. There are bound to be a few conflicts so resolve those, and then commit.

$ svn commit -m "Merged foo 200601 into trunk"

All done. Now you should go back and read the Subversion book and svn_load_dirs manual page, and I can ensure you they'll make a lot more sense this time.

NP: If You Can't Join Them, Beat Them, DJ Format

13:55 Wednesday, 04 May 2005 [#] [computers] (6 comments)

Posted by gary ng at Fri May 6 10:51:54 2005:
I find svk's import much better(and faster) than svn_load_dirs. It use the same subversion repository and don't need to checkout a working copy when doing the import.
Posted by A Nonomouse Canuck at Fri May 6 20:54:27 2005:
Thanks. The documents do make more sense now.
Posted by Dave at Sun Oct 1 15:16:22 2006:
Thanks - this is helpful indeed. I just performed these steps using TortoiseSVN.
Posted by Mike at Wed Nov 29 00:08:25 2006:
Thanks for going to the trouble to explain this.
Posted by Taylor at Thu Mar 29 06:04:01 2007:
I too am a bit nervous about getting the vendor branch right. 

What do you mean by this: You'll want to import into a vaguely named directory such as current so that Subversion keeps a history of the upstream changes.

Why is it true that if you import into a vaguely named directory, subversion will keep a history of the upstream changes.  What are "upstream" changes?
Posted by Micah at Wed Jul 4 23:17:46 2007:
Wow, you really simplified svn_load_dirs.  I fumbled with it once or twice and just got so frustrated that I gave up.  I have been trying to handle vendor branches in other ways, but I think I can do it right now that I've read this.

Thanks a ton for putting this up.

Now to link you in as a reference in this post:
http://blog.aisleten.com/2007/05/18/subversion-vendor-branches-in-action-going-from-07-to-085-of-acts_as_solr/

Name:


E-mail:


URL:


Add 5 and 5 (required):


Comment: