Abstract
Subversion (SVN hereafter) is a version
managament system designed as a replacement for, and general
improvement on, CVS. Subversion is designed to be a distributed,
concurrent, expandable version control system.
This is a walkthrough on setting up and
running the pre-alpha release of Subversion, aimed at people
perhaps familiar with CVS, but not experts at SVN.
Subversion has some aspects which can
be confusing for people coming from a CVS background. Currently,
SVN is pre-alpha software, and should be treated as such: back
up your database. However, that said, Subversion in its current
state offers immediate benefits over CVS.
- Better control over directories.
Directories, like any other file, are versioned in Subversion.
This means that you can track, copy, and delete them as
you would any other file. This sort of directory management
was an administrative nightmare in CVS.
- Offline mode. Subversion, being
designed with the network in mind, allows many functions
to be performed off-line. This includes "tagging"
and "branching", as well as copying, status, and
diffs. CVS had no off-line commands.
- Atomic commits. A commit is completed
as a single operation. This means that if something should
happen in the middle of a commit, the repository will be
left in a valid state. This was not the case with CVS.
- Subversion has a WebDAV interface
to the repository. While I haven't played around with it,
this should replace several add-ons to CVS.
I'm not going to go into great detail
about how to install Subversion, but I will point out a few
things which I either had trouble with, or which you should
watch out for. Nearly all of these pertain to the SVN server,
so if you aren't installing that, you can ignore them. Installing
the SVN client is pretty painless.
The Subversion server requires Apache
2. Follow the instructions in subversion/notes/dav_setup.txt
before you do anything else! I installed Apache 2 with no problem,
and set it to run on a different port than :80 so that it wouldn't
conflict with my Apache 1 server. Eventually, I'll migrate to
Apache 2, so this is a Good Thing. The server also requires
neon; make sure you download that, unpack it into the subversion
directory, and then rename the directory to "neon".
After you get Apache installed, go ahead
and build and install Subversion, but don't use the recommended
--disable-shared option; if you do, WebDAV won't work,
and neither will your server. Make sure that you do use the
--with-apxs=/usr/local/apache2/bin/apxs option mentioned
in the dav_setup.txt file, but not mentioned in the INSTALL
file.
If you build Subversion from the self-hosted
repository, it requires bleeding-edge autoconf, automake, and
libtool installations. I had problems installing the Subversion
server on a couple of machines because of this. If you do as
well, don't call me. I still have one older server that Subversion
refuses to compile on. If this is the case for you, just use
the tarball distribution from the subversion webpage.
After you get Apache and Subversion installed,
create a subversion user. Then make a subdirectory named repos
in ~subversion and run svnadmin ~subversion/repos[1].
You'll also need to add some lines into Apache2's httpd.conf
to make the repository accessible. This is documented in the
dav_setup.txt file. The installation instructions mention creating
the repository after they talk about testing the tools,
which is confusing. Make sure that you run svnadmin before
you attempt to test accessing the repository.
Security is not handled by subversion,
but by Apache. Secure your repository using the normal Apache
configs.
I set my subversion server with the Apache
config file:
<Location /svn/repos>
DAV svn
SVNPath /home/subversion/repos
</Location>
This allows me to access my repository
at http://localhost:8080/svn/repos, with, for example:
svn co http://localhost:8080/svn/repos myproject/trunk -d
myproject (I'll explain this below).
When you import a project into Subversion,
or start one there, it is recommended that you change your directory
structure around a little to accomodate how Subversion handles
"tags" and "branches". There are three things
to note at this point: the first is that this restructuring
isn't neccessary, but recommended, to make your life easier.
The second is that Subversion doesn't have "tags"
and "branches" per se, as CVS does, but only has copies.
Some SVN people you talk to will use the words "tags"
and "branches", but others will insist on only talking
about "copies". The third is that "version"
means something different in SVN than in CVS.
Last thing first: versions. This is actually
a pretty simple concept, unless you're coming from CVS. SVN
doesn't store a version number for each file, it stores a global
version number per repository. Therefore, it doesn't make sense
to talk about "version 5 of file X". You should think
about it like "file X from version 5 of the repository".
I'll outline the recommended directory
structure for reference; we'll discuss it below. Here's an example
directory structure for "myproject"
myproject/
trunk/
tags/
branches/
When you make a copy with SVN (via svn
copy), SVN makes as light a copy as possible. For example,
if you svn copy a directory, the you'll get a copy on
your client side, but on the server, SVN will only store a delta,
telling it that a copy has been made (I'm simplifying here).
This is similar to what happens when you edit a file; just like
CVS, the server only stores the differences between the
two versions, not a whole new file.
SVN doesn't know anything about tags
or branches; it only knows about deltas. Therefore, a tag is
just a copy of the main directory. Consider our example directory
structure above. In CVS, all of my project files would normally
be in myproject/, and various subdirectories. When we import
a project to or start a new project in SVN, we put all of the
files and subdirectories in trunk/. When we want to make a snapshot
(tag, in CVS) of a given version, say "r1.0", we simply
do an svn copy: svn cp trunk http://localhost:8080/svn/repos/myproject/tags/r1.0.
This makes a cheap copy, and the name of the new directory is
now the tag. The only difference between a tag and a branch,
then, is that you don't ever change any of the files or directories
in a tag.
I'll go into more detail about the commands,
but this explains why you want to set up your directory structure
this way. Make sure that you do this restructuring before
you import your project into SVN.
We'll start from the top: importing a
project. We'll assume we're working with a CVS project; if you
aren't you can ignore the CVS-related items.
To import a new project, clean up your
project directory and prepare it for SVN. For the example below,
assume that we start in the parent directory of your project
directory.
$ find myproject/ -name CVS -exec rm -rf {} \;
$ mkdir myproject_svn myproject_svn/tags myproject_svn/branches
$ mv myproject myproject_svn/trunk
$ svn import http://localhost:8080/svn/repos svn_myproject myproject
The "myproject" in the last
command is very important. Don't forget this!! If you
do, all of the files in svn_myproject will be imported directly
into the root directory of the repository, and you'll have a
big mess. If you're using a different repository per project,
you don't have to bother with this, but if you want multiple
projects per repository, this is neccessary.
To check the project out, you would execute:
svn checkout http://localhost:8080/svn/repos/myproject/trunk
-d myproject. This checks out the main trunk into a subdirectory
called "myproject". The argument to -d can be any
name. This is where SVN is really cool, and just how cool sort
of creeps up on you. You can do things like: svn checkout
http://localhost:8080/svn/repos/myproject/tags/r1.0 -d myproject_release_1_0
to check out a given tag. Tags and branches always were a difficult
concept to work with in CVS, and after you get used to it, they're
much easier with SVN.
Commits and updates are performed almost
the same as with CVS via svn commit and svn update,
with a minor difference; you must pass 'svn commit'
a -m or -e argument if you want to supply a log
message, because it try to force you to give one. The reason
for this is given in the SVN documentation, and I agree with
them. SVN updates do conflict resolution differently than CVS.
CVS embeds the conflicts in the source file. SVN puts conflicts
into a .rej file, rather than in the source directly. This is
nice, because it allows more orthoganal difference management
techniques on heterogeneous file types; CVS conflicts only worked
on text files. It also means that you can ignore conflicts until
you have to commit (commit won't let you commit if you have
rejects laying around). The SVN status command, unlike the CVS
status command, is actually useful, and gives you decent, human-readable
output. The status command can also be performed "off-line".
As I mentioned earlier, files and directories
can be renamed and deleted. Renames are performed with the svn
copy command; remember that all copies start out as cheap
copies. Deletes are performed with the svn delete command.
The documentation states that the delete on the client side
occurs when you commit the change, but I've noticed that you
have to update to have the files removed from your local copy.
For example: svn delete file && svn commit &&
svn update, to have svn remove the file from your directory.
A current gotcha to watch for is when
making copies of branches. Before you svn copy any branch or
other directory copy that has changed, make sure that you perform
an svn update to make sure the version is current. I'm not sure
what happens if you don't, but whatever it is, it probably isn't
good.
Subversion is already very usable, and
functionality is added daily. In my opinion, SVN already surpasses
CVS in usefulness; being able to delete and rename directories
alone would justify the switch. My only disagreement with SVN
is that the versions are repository-wide, not project-wide,
neccessitating (in my opinion) multiple repositories, which
equates to additional administrative work. However, this is
an issue which will be resolved, one way or another, and is
not a reason to not use SVN.