Vendor imports with Subversion

NOTE: This page has been migrated from the wiki to http://www.freebsd.org/doc/en_US.ISO8859-1/articles/committers-guide/subversion-primer.html - any future updates should be made there and not here.

This page describes the vendor import procedure.

PLEASE read the entire page before you start your own vendor import!

A note about patches

Patches to vendor code fall into two categories:

The nature of a patch dictates where it should be committed:

Preparing the tree

If this is the first import you do after the switch to Subversion, you will have to flatten and clean up the vendor tree, and bootstrap merge history in the main tree.

Flattening

During the conversion from CVS to Subversion, vendor branches were imported with the same layout as the main tree. This means that the pf vendor sources ended up in vendor/pf/dist/contrib/pf. This is pointless and inconvenient. What you really want is to have the vendor source directly in vendor/pf/dist.

Here's how you flatten the pf tree:

% cd vendor/pf/dist/contrib/pf
% svn mv $(svn list) ../..
% cd ../..
% svn rm contrib
% svn propdel -R svn:mergeinfo .
% svn commit

The propdel bit is necessary because starting with 1.5, Subversion will automatically add svn:mergeinfo to any directory you copy or move. In this case, since you're not going to merge anything from the tree you deleted, they will just get in the way.

You may want to flatten the tags as well (3.4, 3.5 etc); the procedure is exactly the same, with s/dist/3.4/ or whatever. If you do this, put off the svn commit until the end.

Cleaning up

Look through your dist tree and perform any cleanup you deem necessary. One thing you may want to do is disable keyword expansion, as it makes no sense on unmodified vendor code. In some cases, it can even be harmful (OpenSSH includes two files that originated with FreeBSD and still contain the original version tags).

% svn propdel svn:keywords -R .
% svn commit

Bootstrapping merge history

If this is the first import you do after the switch to Subversion, you need to bootstrap svn:mergeinfo on the target directory (in the main tree) to the revision that corresponds to the last change you made to the vendor tree prior to importing new sources.

% cd head/contrib/pf
% svn merge --record-only $FSVN/vendor/pf/dist@180876 .
% svn commit

(on my system, $FSVN expands to svn+ssh://svn.freebsd.org/base)

Importing new sources

If you feel like it, you can repeat this step for every upstream release between the last one you imported and the one you're importing now. You will have to commit twice for every release - once for the import itself and once for the tag.

Preparing the vendor sources

Prepare a full, clean tree of the vendor sources. In CVS, we used to only import the parts we needed, but with Subversion, we can keep a full distribution in the vendor tree without bloating the main tree. We import everything, but merge only what we need.

Note that you will need to svn add any files that were added since the last vendor import, and svn rm any that were removed. To facilitate this, you should prepare sorted lists of the contents of the vendor tree and of the sources you are about to import.

% cd vendor/pf/dist
% svn list -R | grep -v '/$' | sort >../old
% cd ../pf-4.3
% find . -type f | cut -c 3- | sort >../new

With these two files, comm -23 ../old ../new will list removed files (files only in old) while comm -13 ../old ../new will list added files (files only in new).

Importing into the vendor tree

Now copy the new sources into dist, and svn add / svn rm as needed:

% cd vendor/pf/pf-4.3
% tar cf - . | tar xf - -C ../dist
% cd ../dist
% comm -23 ../old ../new | xargs svn rm
% comm -13 ../old ../new | xargs svn --parents add

If any directories were removed, you will have to svn rm them manually. Nothing will break if you don't, but the directories will remain in the tree.

Check properties on any new files. All text files should have svn:eol-style set to native. All binary files should have svn:mime-type set to application/octet-stream, unless there is a more appropriate media type. Executable files should have svn:executable set to *. There should be no other properties on any file in the tree.

You are now ready to commit, but you should first svn stat and svn diff to make sure everything is OK.

Tagging

Once you've committed the new vendor release, you should tag it for future reference. The best and quickest way is to do it directly in the repository:

% svn cp $FSVN/vendor/pf/dist $FSVN/vendor/pf/4.3

Once that's done, you can svn up your working copy of vendor/pf to get the new tag (or not; you probably won't need it anytime soon)

If you choose to create the tag in your working copy instead, don't forget to remove the resulting svn:mergeinfo:

% cd vendor/pf
% svn cp dist 4.3
% svn propdel svn:mergeinfo -R 4.3

Merging to head

% cd head/contrib/pf
% svn up
% svn merge --accept=postpone $FSVN/vendor/pf/dist .

(The --accept=postpone bit tells Subversion not to bother you with merge conflicts; you will take care of them manually)

Resolve any conflicts. This bit is no different than it was with CVS.

Make sure that any files that were added or removed in the vendor tree have been properly added or removed in the main tree.

Check diffs against the vendor branch:

% svn diff --no-diff-deleted --old=$FSVN/vendor/pf/dist --new=.

The --no-diff-deleted part tells Subversion not to bother you with files that are in the vendor tree but not in the main tree: things that you would previously have removed before the vendor import, like the vendor's makefiles and configure scripts and whatnot.

With CVS, once a file was off the vendor branch, you couldn't put it back. With Subversion, there is no concept of on or off the vendor branch. If a file that previously had local modifications no longer does, just remove any left-over cruft, such as FreeBSD version tags, so it no longer shows up in diffs against the vendor tree. Yet another thing that will make your life easier in the long run.

If any changes are required for the world to build with the new sources, make them now - and test, test and retest until you're satisfied that everything builds and runs correctly.

Commit

You are now ready to commit. Make sure you get everything in one go. Ideally, you would have done step 5 in a clean tree, in which case you can just svn commit from the top of that tree; that's the best way to avoid surprises. If you do it properly, the tree will move atomically from a consistent state with the old code to a consistent state with the new code - no pesky race conditions like we had with CVS.

Congratulations, you just completed your first vendor import.

Vendor imports from scratch with Subversion

Importing into vendor

First you need to prepare the directory in vendor:

% svn co --depth immediates $FSVN/vendor
% cd vendor
% svn mkdir byacc
% svn mkdir byacc/dist

Now you can import your sources into the dist directory. Once the files are in place do not forget to svn add all those new files.

You can now just svn commit and after that tag the version you import, to save time and bandwith you can to it directly remotely:

% svn cp -m "Tag byacc 20120115" $FSVN/vendor/byacc/dist $FSVN/vendor/byacc/byacc-20120115 

Merging to head

Since this is the first time it entering, you would need to copy it:

% svn cp -m "Import byacc to contrib $FSVN/vendor/byacc/dist $FSVN/head/contrib/byacc

You can continue to work "normally" with on your freshly imported sources

SubversionPrimer/VendorImports (last edited 2012-05-19 16:48:07 by GavinAtkinson)