svn copy's behaviour when copying directories to paths that already exist does not quite match that of Linux's
This week at work we resumed development on a new software feature that we hadn't had time to look at since its initial proof-of-concept phase several months ago. We do feature development on feature-specific SVN branches, so the unfinished code was safely tucked away in its own pocket universe whilst we applied a whole ton of new functionality and API changes on the trunk in the meantime. Today it came time to update this branch so that its code was up-to-date and we could continue working.
Now, we also have a couple of levels of dependencies linked in by SVN externals:
project/trunk \ |- dep1/trunk@SomeRecentRev |- dep2/trunk@SomeRecentRev
The proof-of-concept feature's project branch had a feature-specific branch for
dep1, but not for
project/branches/thefeature \ |- dep1/branches/thefeature |- dep2/trunk@SomeOldRev
How we caused a problem
Today, to clean things up and to obtain a full working environment for the new feature, we needed to create a branch for
dev2 as well. Using version 1.6.6 of the command-line client:
svn copy \ https://repohost/svn/dep2/trunk/ \ https://repohost/svn/dep2/branches/thefeature/ \ -m"Created new branch for thefeature development"
One would think that the result would be:
project/branches/thefeature \ |- dep1/branches/thefeature |- dep2/branches/thefeature
and, well, it was.
However, something went wrong. Having done this, upon building
project/branches/thefeature, it became evident that the code under
dep2/branches/thefeature was old. Really old. Probably from around
@SomeOldRev, dating back to development on the original proof-of-concept. But didn't we just copy from the trunk
HEAD? Sure we did…
Closer inspection revealed that there was now an unexpected subdirectory "trunk" underneath this outdated code, which contained the expected recent code:
project/branches/thefeature \ |- dep1/branches/thefeature |- dep2/branches/thefeature \ | old code | "trunk/" \ | new code
Where on Earth did this come from?
Around this time it became known that there had in fact been an orphaned
dep2/branches/thefeature already in existence from the days of
@SomeOldRev that had never been used. Still, I'd guessed that
svn copy's mechanism would follow the convention of Linux
cp, which when copying directories has significance in trailing slashes on the source-dir. That is, with
cp, if the destination directory already exists and you do not use a trailing slash on the source-dir, then you are actually putting a copy of source-dir inside dest-dir. But our
svn copy invocation used trailing slashes on both the source and destination arguments!
Some chatter on the SVN mailing list included this:
I did a bit of research in the list archive, and came across this snippet,
posted by someone basically saying this was reasonable behaviour because
that's how *nix does it:
cp path/A path/B --> if path/B doesn't exist, creates path/B if path/B does exist, creates path/B/A
with no mention of the trailing-slash rule. Indeed, from our experience, the above would seem to be the case whether you include the trailing slash or not.
Nuking the entire
dep2/branches/thefeature directory and re-copying from trunk solved all the build problems and left the directory structure as expected.