Planning a Subversion import

svn import is a bit of a landmine. It's not obvious from the command format, nor from its (almost nonexistent) documentation exactly what shape the imported repository will actually take once it's imported — and it's difficult to impossible to rectify a mistake once you've made one, since Subversion also doesn't offer a way to preview an import or delete an imported project that you created wrong by accident.

For example, let's say you have this structure:

You'd like to put this under version control. svn import is the tool for that... but how, exactly? What you really want is for svn checkout to yield:
$ cd /tmp
$ ls
$ svn checkout /game
$ ls
Right? Or, to be more inline with Subversion standards, you really want this to be:
$ cd /tmp
$ ls
$ svn checkout /game/trunk game
$ ls
Invoking the exact proper incantation to make svn import work this way is
  1. Not documented
  2. Easy to get wrong
  3. Impossible to fix if you do get it wrong
Part of the problem is that it's just not something that you do day in and day out, so it's easy to forget exactly what parts of the syntax go with what.

So, before you import anything into Subversion, I strongly recommend you make a local repository, test the import there, check it out from the test repository, make sure it's right, and only then actually import it into the main production repository. You can create a local repository easily:

$ cd /var
$ sudo mkdir svn
$ sudo chown jdavies svn
$ svnadmin create /var/svn/repos
If you take a look at the created directory, you'll see there's quite a bit in there:
$ ls /var/svn/repos/
README.txt conf       db         format     hooks      locks
Although the repository itself is actually empty:
$ svn list file:///var/svn/repos
So, the first step in getting my new game imported under version control is to reformat its directory structure to match Subversion's preferred "trunk", "tags", "branches" structure. Surprisingly, you have to do this manually; the subversion import process doesn't help with this.
$ cd ~/development/game
$ mkdir trunk
$ mkdir branches
$ mkdir tags
$ mv pom.xml src/ trunk/
Now you have the directory structure:
branches and tags are empty — that's OK. You'll use them when you create some actual branches or tags.

Now it's time to import. Checking the documentation for the import command, you see:

$ svn help import
import: Commit an unversioned file or tree into the repository.
usage: import [PATH] URL

  Recursively commit a copy of PATH to URL.
  If PATH is omitted '.' is assumed.
  Parent directories are created as necessary in the repository.
  If PATH is a directory, the contents of the directory are added
  directly under URL.

So... the URL is the URL of my repository, and the PATH is the directory that I want to put under version control, right?

$ cd game
$ svn import . file:///var/svn/repos -m "Initial import"
Now I've messed up my repository quite a bit:
$ svn list file:///var/svn/repos
Now the trunk, branches and tags directories are at the top of your repository. And because subversion is a revision control system, evidence of your mistake will be preserved in the repository until the end of time:
$ svn log file:///var/svn/repos
r2 | joshuadavies | 2013-10-24 09:06:16 -0500 (Thu, 24 Oct 2013) | 1 line

Delete accidental import
r1 | joshuadavies | 2013-10-24 09:02:12 -0500 (Thu, 24 Oct 2013) | 1 line

Initial import

Some people actually manage their repositories this way deliberately; if you look under trunk, you'll see a list of projects. I don't think that this is a particularly good idea, because projects in a repository have divergent lifespans — even if you're not managing a group of disparate projects now, chances are you will be in the near future. You'll be much better off in the long run maintaining the top level as a list of projects, each with its own trunk, branches and tags subdirectories and subsequently their own revision strategy.

But this problem may strike you as obvious — after all, I never said anything about my game directory when I did the import, right? However, this invocation, which does reference my game directory actually does the same thing:

$ cd development
$ svn import game file:///var/svn/repos -m "Initial import"
The takeaway here is that the first argument to import is not used to form the path that's imported into the repository; the contents of the directory named by the first argument are appended to the second. Subversion starts by navigating to the directory named as the URL; if a subdirectory component isn't found, it will be created. Then it adds every file or directory found underneath the PATH argument to that directory. This means that the following will produce the results you intend:
$ cd development
$ svn import . file:///var/svn/repos/game -m "Initial import"
If game is the only directory in development. Most likely, it isn't, so what you need to do is to repeat it:
$ cd development
$ svn import game file:///var/svn/repos/game -m "Initial import"

Adding         game/trunk
Adding         game/trunk/src
Adding         game/trunk/src/main
Adding         game/trunk/src/main/java
Adding         game/trunk/src/main/java/com
Adding         game/trunk/src/main/java/com/jdavies
Adding         game/trunk/src/main/java/com/jdavies/game
Adding         game/trunk/src/main/java/com/jdavies/game/
Adding         game/trunk/pom.xml
Adding         game/branches
Adding         game/tags

Committed revision 1.

Add a comment:

Completely off-topic or spam comments will be removed at the discretion of the moderator.

You may preserve formatting (e.g. a code sample) by indenting with four spaces preceding the formatted line(s)

Name: Name is required
Email (will not be displayed publicly):
Comment is required
My Book

I'm the author of the book "Implementing SSL/TLS Using Cryptography and PKI". Like the title says, this is a from-the-ground-up examination of the SSL protocol that provides security, integrity and privacy to most application-level internet protocols, most notably HTTP. I include the source code to a complete working SSL implementation, including the most popular cryptographic algorithms (DES, 3DES, RC4, AES, RSA, DSA, Diffie-Hellman, HMAC, MD5, SHA-1, SHA-256, and ECC), and show how they all fit together to provide transport-layer security.

My Picture

Joshua Davies

Past Posts