My relationship with Subversion is an ever growing one. Right now it is growing itself straight into git. I’m not sure how happy Subversion is with me. It’s complicated.

But it is nowhere near as complex as my process for committing a Rails upgrade to SVN used to be. First I would delete my current Rails version from the repository. Then I would rake rails:freeze:edge TAG=rel_2-0-2. Finally I would commit the latest Rails version to the repository.

I admit, that doesn’t sound too complex. Problem is this process leads to a completely undeployable revision sitting in SVN. And I’ve also seen very wonky results when looking at svn status for several minutes after completing such a process. I began to wonder if it wasn’t just coincidence that I sometimes convert the phrase “Subversion repository” into “suppository.” I was feeling it.

rsync, friend to the command-line idiot

Enter rsync, the file copy when cp just won’t do. If you’ve ever tried to simply overwrite your vendor/rails directory with a new version, either by using the freeze rake command, a cp command or a simple drag-and-drop in your GUI, you know how much that can mess with your SVN-chi.

Just. Don’t. Do it.

A simple rsync command will take a source directory (a new version of Rails) and copy all new and updated files to a destination directory (an old version of Rails). It will not copy directories themselves, just files. The expectation when using rsync is that you’re dealing with two similar directory trees.

Here is my current process for upgrading an incremental Rails release. From app root:

cd vendor
mv rails rails\_2-0-1
rake rails:freeze:edge TAG=rel_2-0-2
mv rails rails\_2-0-2
cp -rf rails\_2-0-1 rails
rsync -arv --delete-after --exclude='.svn/' rails_2-0-2/ rails

And now a blow-by-blow description of this process:

cd vendor

Don’t ask.

mv rails rails_2-0-1

Move your current version of Rails for safe-keeping.

rake rails:freeze:edge TAG=rel_2-0-2

Freeze your new version of Rails. If you didn’t move vendor/rails in the previous step, well, now you need to start over. Sorry, buddy.

mv rails rails_2-0-2

Now move your new version of Rails for safe-keeping.

cp -rf rails_2-0-1 rails

Put the original version of Rails back in place. Don’t be your own worst enemy. Use a copy command so you have a recovery path that doesn’t involve recreating the working copy of your app from SVN.

rsync -av --delete-after --exclude='.svn/' rails_2-0-2/ rails

This is the secret sauce of the process. The last two parameters are the source (rails_2-0-2/) and destination (rails). The trailing forward-slash on the source parameter is important. If you forget that, rsync will basically copy your rails_2-0-2 directory into rails/rails_2-0-2. Not all that useful.

The other options:

  • -a - archive mode (want recursion and preserve everything)
  • -v - verbose output
  • --delete-after - After merging the directory trees, delete from the destination what didn’t exist in the source
  • --exclude='.svn/' - Don’t even look at .svn directories. Without this, all of your SVN hooks will be destroyed

After completing everything, running tests, fixing it all, committing to SVN, etc you can delete those two safe-keeping copies of Rails in your vendor directory. Now don’t you feel so fresh and so clean?

NOTE: I revert to the first process I describe above with major releases. Jumping from Rails 1.2.* to Rails 2 was jarring enough that there was no real benefit in keeping revision history of such drastic changes. In fact, I’m not entirely sure my new procedure would even work in such a situation.

Mar 03, 2008 · Subscribe · Archive · Projects · Twitter · GitHub · Flickr