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
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?
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/