Syncing a remote SVN repository to the local file system under Windows

I had some bad experience with the hosted SVN repositories of my open source projects (first with SourceForge, now with OSDN) so I decided to sync all of them to a local, read only copy on my hard drive. In the worst case that will keep the history even if the hosting service goes down permanently and loses the data. The command for that, according to the book is svnsync. The local repository must be prepared first, though and that turned out a bit more complicated than I expected, so I’m posting this here for future reference.

The following will create a copy of the repository of my dof2cfg tool, currently hosted on OSDN, in the local directory d:\svnmirror-readonly\_OSDN\dof2cfg.

The first part is simple: Create a fresh SVN repository in a local directory, e.g.:

Create the base directory

> mkdir d:\svnmirror-readonly\OSDN

Create the repository

> svnadmin create d:\svnmirror-readonly\OSDN\dof2cfg

Now we have got an empty repository. The next step is to allow property changes in that repository, because otherwise svnsync won’t work. The book does not give any examples of how to do that on Windows, but I found some examples on StackOverflow and modified one to match the Unix shell script given in the book:

@ECHO OFF
set repository=%1
set revision=%2
set userName=%3
set propertyName=%4
set action=%5

rem only allow syncuser to make any changes
if /I not "%userName%" == "syncuser" goto ERROR_USERNAME

goto :eof

:ERROR_USERNAME
echo Only the syncuser user may change revision properties >&2
goto ERROR_EXIT

:ERROR_EXIT
exit /b 1

This script must be put into the hooks sub directory of the repository and be called pre-revprop-change.bat. It checks, that the username is “syncuser”, and if it isn’t, prints an error message to stdout and exits with a error code of 1, telling svn that there was an error. Since there is no other check, changing any property is allowed.

In case I ever forget that this repository is meant to be readonly I added another safe guard (also suggested by the book), which will allow commits only from the user “syncuser”. This is done by another hook called start-commit.bat:

@ECHO OFF
set repository=%1
set userName=%2

rem only allow syncuser to make any changes
if /I not "%userName%" == "syncuser" goto ERROR_USERNAME

goto :eof

:ERROR_USERNAME
echo Only the syncuser user may commit to this repository >&2
goto ERROR_EXIT

:ERROR_EXIT
exit /b 1

This should prevent any accidental commits done with a different user name.

EDIT: While this works in principle, it won’t help much, because any commit will automatically be done with the only user the repository knows about: “syncuser” so the check is totally useless. I’ll leave this here in case I figure out later how to make it work as intended. It works with the example given in the book because there the destination repository is remote and requires a log on.

With these preparations in place, we can now use svnsync to do the rest:

> svnsync init file:///d:/svnmirror-readonly/OSDN/dof2cfg https://svn.osdn.net/svnroot/dof2cfg --sync-username syncuser
Copied properties for revision 0.

Note that the first parameter is the destination repository and the second is the source. Also note that the local repository must be prefixed with “file:///” and use forward slashes rather than backslashes.

This will prepare the local repository to be synced. The next command will do the actual syncing. It must be repeated every time the remote repository changes.

>svnsync sync file:///d:/svnmirror-readonly/OSDN/dof2cfg --sync-username syncuser
Committed revision 1.
Copied properties for revision 1.
.... more lines ....
Transmitting file data .....
Committed revision 17.
Copied properties for revision 17.

Since the initialization saves the url of the source repository, it is not necessary to pass it again. Only the username must be given.

And that’s it.

I’ll try this now with a few more repositories and if I find anything else to keep in mind, I’ll update this post later.