Modifying Subversion commit messages

Sometimes when I try to quickly repeat my last command in the terminal, I end up firing off a svn commit. Unlike with Git, you cannot modify commits in Subversion, but you can modify a revision’s properties — like the log message.

Here’s how:

svn propedit --revprop -r 1234 svn:log

This will open your $EDITOR and it lets you edit the log message for the specified commit (1234).

Note: in order to make this work, you repository needs to be configured correctly. This means you should rename /path/to/your/repo/hooks/pre-revprop-change.tmpl to /path/to/your/repo/hooks/pre-revprop-change and chmod +x it.

Issues using VCSCommand with MacVim

I tried to use the VCSCommand-plugin for Vim the other day, but I ran into a strange issue: the plugin tried to use an older version of subversion with my working copy, resulting in “this client is too old” error messages.

The setup

I’ve got two copies of Subversion installed on my system: the default that comes with Mac OS X (1.4.4) and the one I manually installed (1.6.9). I have set my $PATH so that 1.6.9 (in /opt/subversion/bin) gets precedence over 1.4.4 (in /usr/bin). It all works fine from the command line.

The problem

I am using MacVim, which is very nice, but it apparently doesn’t know about my 1.6.9 installation and complains. It appears (from running :!which svn in MacVim) that MacVim (or so it seems any OS X app) ignores my $PATH adjustments in .bash_profile. Hence it is unaware of the /opt/subversion/bin/svn executable.

The fix

I tried adding a file with the extra location to the /etc/paths.d directory, as per this suggestion. That worked but did not help, as it appended rather prepended the new location to MacVim’s $PATH. It gave /usr/bin precedence over /opt/subversion/bin.

I then gave up trying to solve this neatly. Instead I configured the plugin around the issue, which still works rather nicely. I included this line in my .vimrc file:

let VCSCommandSVNExec="/opt/subversion/bin/svn"

This tells the plugin which executable to use. This solution is not very portable (the path to svn may very well be different on other machines), but I have not found another way to solve this. Of course I could mess with my Subversion installations, but down that path madness lies, or so I hear. For now, I’m glad I can get on with it.

zsh arguments-fu

When using Subversion from the command-line I commonly do:

svn copy ^/myproject/branches/FB-branch1 ^/myproject/branches/FB-branch2
svn switch ^/myproject/branches/FB-branch2

This is a lot of typing. One way of working around this a wrapper around svn to automate these patterns, but another is using shell power. I use zsh, but bash and others can do the same with slightly different syntax:

svn copy ^/myproject/branches/FB-branch1 ^/myproject/branches/FB-branch2
svn switch !!:3

Here !!:3 is the third argument of the last command. Neat!

Subversion branching

The main reason why developers should use Git for versioning is cheap, cheap branching. But in Subversion it isn’t so hard that you shouldn’t use it. Here’s a basic bugfix branch workflow. First, create your branch:

svn copy /path/trunk\
         /path/branches/my-new-branch\
         -m "Create my new branch"
svn switch /path/branches/my-new-branch

Of course, /path/ is easy enough to find:

svn info | grep URL

Hack away, make some commits, and when you are ready to merge to branch back into trunk:

# Note the revision that started this branch
# assume this tells you '4362'
svn log --stop-on-copy

# Get back to trunk and merge in your changes
svn switch /path/trunk
svn merge -r 4362:HEAD /path/branches/my-new-branch

Inspect your changes, resolve conflicts and make sure everything is alright. Commit your changes…

svn commit -m "Merge in branch 'my new branch'"

…and then clean up after yourself:

svn delete /path/branches/my-new-branch\
           -m "Remove obsolete branch"

The trick is knowing where your branch started. You can note the revision number when you create the branch, or use svn log to find out.

Beware of changes to trunk before merging in your branch. If trunk has changed since you created your branch (and chances are it has) you should first merge those changes back into your branch, so it stays in sync.

Newer versions of Subversion should make this process a little easier, but this works. Be sure to check out the Subversion manual on branching patterns.