svn copy
's behaviour when copying directories to paths that already exist does not quite match that of Linux's cp
command.
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 dep2
:
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…
Mystery solved
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.