svn commit “unable to lock” error under Mac OS X — May 3, 2010

svn commit “unable to lock” error under Mac OS X

This will be interesting to approximately none of you, but I feel I need to spread the knowledge of hell to a wider world.

I will perhaps go into greater detail at a future date about all the *other* problems preceding this one while I used svn (and Maven, and Eclipse) under OS X. They all essentially stem from the fact that OS X’s filesystem is case-insensitive. … Or rather, not case-insensitive: you can’t do

(16:41) slaniel@Steve-Laniels-MacBook-Pro:~$ mkdir test_dir
(16:42) slaniel@Steve-Laniels-MacBook-Pro:~$ mkdir test_Dir
mkdir: test_Dir: File exists

But you can do

(16:42) slaniel@Steve-Laniels-MacBook-Pro:~$ mv test_dir test_Dir
(16:42) slaniel@Steve-Laniels-MacBook-Pro:~$ rm -rf test_dir

Since it’s not entirely case-insensitive, it is *sometimes* — but not always — a problem to have both ‘foo’ and ‘Foo’ in the same svn checkout. More to the point here: what if you have ‘Foo’ and want to rename it to ‘foo’? You’d want to do `svn mv Foo foo`. There will be bequeathed unto you a sadness:

(16:45) slaniel@Steve-Laniels-MacBook-Pro:~/svn/sandbox/slaniel$ svn mkdir foo
A foo
(16:45) slaniel@Steve-Laniels-MacBook-Pro:~/svn/sandbox/slaniel$ svn mv foo Foo
svn: Unable to lock ‘Foo’

The reason it can’t lock ‘Foo’ is that it already has ‘foo’ locked, and it thinks that ‘foo’ is the same as ‘Foo’. So it can’t move, in other words, because the filesystem is case-insensitive.

To redress this just now, I had to do something like

svn mv foo bar &&
svn ci -m “Temporarily moving foo to bar” &&
svn mv bar Foo &&
svn ci -m “Moving bar to Foo”

You need to do the commit after each move; you can’t just do

svn mv foo bar && svn mv bar Foo

Maybe all of this was obvious to all OS X svn users other than me. I assure you that it was *not* obvious to me.

Mac filesystem case-insensitivity just wasted an inordinate quantity of time and money from some of my company’s smartest engineers. I am displeased. Perhaps this post will save someone else some time in the future.

At a later date, after I’ve actually completed some work, perhaps I will explain all the *other* badness that resulted from this case-insensitivity.

A Subversion problem: who was first responsible for an errant line? — May 2, 2010

A Subversion problem: who was first responsible for an errant line?

Suppose you want to find the first Subversion checkin where a particular string appeared. `svn blame [filename]` gets you some distance toward that goal, but it doesn’t entirely work: `svn blame` will tell you the person *most recently* responsible for tweaking the particular line of code where that string appears. If someone came along between when that line was introduced and now and, say, changed all Unix line endings to DOS ones, `svn blame` will suggest that the interloper is the one responsible for that line.

So what you want is the *first* revision number in which that change appeared. So far as I can tell, there’s no built-in svn command to give you this information. This shell-scripting business is the best I could come up with:

#!/bin/bash
string=$1
filename=$2

if test -z $string; then
echo “Must supply a string to search for”
exit 1
fi

if test -z $filename; then
echo “Must supply a filename to search”
exit 1
fi

# Get all svn revision numbers in which $filename
# was involved, in ascending order.
all_rev_nums=`svn log $filename
|grep -o ‘^r[0-9]+’
|grep -o ‘[0-9]+$’
|sort -n`

for revnum in $all_rev_nums; do
if svn cat -r$revnum $filename |grep -q $string; then
svn blame -r $revnum $filename |grep $string
# Since they’re in ascending order, we’ve found
# the first one. So we can quit now.
exit 0
fi
done

# If we never found $string in any revision
# of $filename, return an error.
exit 1