I recently added two of my pet projects to Google Code. I chose Google's Open Source hosting because they have a very clean UI with integrated issue tracking and also offer native support for Subversion. One of the many aspects that make Subversion a decent choice is the ability to import existing SVN repositories to Google Code. That is, the whole history is uploaded and your soon-to-be open source project doesn't loose valuable undo history. YAGNI? Maybe.
Importing a complete repository to Google Code is well documented, but what if your repository contains several projects and you just want to upload a certain one? Actually Subversion has all you need, there are just a couple of things to prepare. I will provide everything you need here, you may also want to use this excellent write-up (also look here) which I used as a reference. The syntax presented here works on Windows, whereas the author of the above articles was working on a *nix machine, so the command lines differ a bit.
Create your Google Code project and reset the Subversion repository to revision 0
After you created the project on Google Code you can find the "Reset Subversion Repository" link at the bottom of the "Source" tab.
Prepare your Subversion repository
You need local access to the Subversion server, a Remote Desktop or SSH connection would suffice. I'm assuming your repository is accessible over HTTPS on port 8443. Here are the paths used in the command lines below:
| Property | Value |
| SVN repositories root | C:\Subversion\ |
| SVN repository containing the project | C:\Subversion\projects |
| Repository URL | https://localhost:8443/svn/projects/ |
| Project to import to Google Code | https://localhost:8443/svn/projects/foo/Project-FooBar/ |
| Google Code Subversion URL | https://project-foobar.googlecode.com/svn/ |
Dump your repository filtering the project path
First you need to dump the SVN repository containing the project in question. svnadmin dump saves the contents of the repository to the C:\Subversion\project-foobar.dump file on disk. To only take the parts into account we're interested in, use svndumpfilter to exclude everything outside the project path.
Renumbering revisions and dropping empty revisions cleans up the resulting dump and prevents revisions with no changes.
svnadmin dump C:\Subversion\projects\ | svndumpfilter --drop-empty-revs --renumber-revs include /foo/Project-FooBar/ > C:\Subversion\project-foobar.dump
Including (and dropping empty revisions for) prefixes:
'foo/Project-FooBar'
* Dumped revision 0.
Revision 0 committed as 0.
* Dumped revision 1.
Revision 1 skipped.
...
Create a new repository for the project
Now that you have dump in place, create a new repository for Project-FooBar.
svnadmin create C:\Subversion\project-foobar-import
Create directories needed to load the dump
To make the import process succeed, you have to create the paths that are not included in the dump, i.e. all directories above the path that was included by svndumpfilter. In the our case, this is the /foo directory.
svn mkdir https://localhost:8443/svn/project-foobar-import/foo/ -m "Folder created for import"
Committed revision 1.
Load the filtered dump
It's time to import the dump to the repository just created.
svnadmin load C:\Subversion\project-foobar-import < C:\Subversion\project-foobar.dump
<<< Started new transaction, based on original revision 1
* adding path : foo/Project-FooBar ... done.
* adding path : foo/Project-FooBar/trunk ... done.
...
If you didn't create all necessary directories in the last step, you will receive an error message like this:
<<< Started new transaction, based on original revision 1
* adding path : foo/Project-FooBar ...svnadmin: File not found: transaction '1-1', path 'foo/Project-FooBar'
Move directories such that they follow the standard Subversion directory structure
Your can now have a look at the new repository by pointing your browser to https://localhost:8443/svn/project-foobar-import/ where you only should see Project-FooBar.
The next step moves the project to the root of the repository and aligns the directory structure with Subversion's default directory layout.
svn move https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/trunk/ https://localhost:8443/svn/project-foobar-import/trunk/ -m "Folder moved"
svn move https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/tags/ https://localhost:8443/svn/project-foobar-import/tags/ -m "Folder moved"
svn move https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/branches/ https://localhost:8443/svn/project-foobar-import/branches/ -m "Folder moved"
svn delete https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/ -m "Folder deleted"
Upload your Subversion repository to Google Code using svnsync
All set. The last step is to upload your Subversion repository to Google Code using the documented command line below.
svnsync init https://project-foobar.googlecode.com/svn/ https://localhost:8443/svn/project-foobar-import/
Copied properties for revision 0.
svnsync sync https://project-foobar.googlecode.com/svn/
Committed revision 1.
Copied properties for revision 1.
...
The whole import process will take a little bit, depending on the size of your repository. It took me about 40 minutes for a repository with about 100 revisions, time to grab a cup of coffee.
The script
Of course you can script the whole process:
@rem Create dump
svnadmin dump C:\Subversion\projects\ | svndumpfilter --drop-empty-revs --renumber-revs include /foo/Project-FooBar/ > C:\Subversion\project-foobar.dump
@rem Create repository for import
svnadmin create C:\Subversion\project-foobar-import
@rem Create directories needed for the import to succeed
svn mkdir https://localhost:8443/svn/project-foobar-import/foo/ -m "Folder created for import"
@rem Load dump
svnadmin load C:\Subversion\project-foobar-import < C:\Subversion\project-foobar.dump
@rem Move folders around
svn move https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/trunk/ https://localhost:8443/svn/project-foobar-import/trunk/ -m "Folder moved"
svn move https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/tags/ https://localhost:8443/svn/project-foobar-import/tags/ -m "Folder moved"
svn move https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/branches/ https://localhost:8443/svn/project-foobar-import/branches/ -m "Folder moved"
svn delete https://localhost:8443/svn/project-foobar-import/foo/Project-FooBar/ -m "Folder deleted"
@rem Sync with Google Code
svnsync init https://project-foobar.googlecode.com/svn/ https://localhost:8443/svn/project-foobar-import/
svnsync sync https://project-foobar.googlecode.com/svn/