Subversion is an open source revision control system, similar in purpose to the well-known, widely deployed, and aging CVS. It is designed to provide state-of-the-art versioning, built from modern technologies.
Subversion is still in development and has not reached version 1.0 yet. However, it's pretty stable and you can use it right now. In this article, we'll cover the basics of Subversion, how to install it, and how to use Subversion for personal projects. A future article will cover installing and using a multi-user, networked Subversion server.
In short, Subversion helps developers to track changes in their project source files. You might ask why you would need a revision control system for your home projects, where you are the only person who decides how and where to make changes. There are several reasons: to retrieve and to compare previous releases, to hunt down regression bugs, to maintain backward-compatible branches, to produce neat changelogs, to work on two different fixes or improvements without confusion. Moreover, you'll get all this with little expense, because Subversion is surprisingly easy to install.
A Subversion repository acts as a filesystem that remembers sets of changes made to it. It does this by storing files in a tree structure, tracking its evolution over time. The repository increments a global revision number with every set of changes committed into the repository. As the whole tree is versioned, it acts as a regular filesystem. Copying and renaming files is possible; creating a project branch is as easy as copying a directory. You can also ask Subversion to produce a difference between two arbitrary revisions, or to check out some subtree at revision N.
This section covers the installation of Subversion on Unix-like systems.
(It's also possible to build and install Subversion on Windows. See the
INSTALL file of the Subversion distribution.) To install Subversion, you may
have to upgrade (or install) some of the tools on your system
(autoconf
, libtool
, python2
). You'll
need also the expat
XML parsing library. For detailed info, see
the BUILD REQUIREMENTS section of the INSTALL file.
Subversion is built completely on open source components.
Subversion requires also a recent version of the Berkeley DB. Be sure to check the README and INSTALL files to make sure you have the correct version. (As of this writing, Berkeley DB 4.0.14 worked.) Subversion uses this database as the underlying storage for its repositories. You can get it from Sleepycat Software.
The Subversion snapshots, available from the main Subversion site, include all of
the other libraries needed to install a local repository. Building a
network-accessible Subversion server requires Apache 2, but that's another
article. The INSTALL file also explains how to check out a fresh new Subversion
from the repository (yes, the developers of Subversion do use their own
software), but that's not absolutely needed as Subversion is becoming more
stable. We'll use a snapshot. As of this writing, the revision number of the
latest snapshot is 3578 (a.k.a. Subversion 0.14.5), but let's call it
XXXX
.
Subversion development proceeds rapidly. To make upgrades easier, we'll
install Subversion in its own subdirectory. We'll also assume that you need to
install the appropriate version of the Berkeley DB. Commands prompted by a
#
should be run as root. (If you don't have root access, install
Subversion in your home directory instead of using /usr/local
as in the
examples below.)
# mkdir /usr/local/subversion-rXXXX
# ln -s /usr/local/subversion-rXXXX /usr/local/subversion
$ gunzip -c db-4.0.14.tar.gz | tar xf -
$ cd db-4.0.14/build_unix
$ ../dist/configure --prefix=/usr/local/subversion-rXXXX
$ make
# make install
Make sure your system can find libraries in
/usr/local/subversion/lib
. This is generally accomplished by
setting your system's equivalent to the environment variable
LD_LIBRARY_PATH
. On Linux, you can also add this path to your
/etc/ld.so.conf
file and run /sbin/ldconfig
.
Then, build Subversion:
$ gunzip -c subversion-rXXXX.tar.gz | tar xf -
$ cd subversion-rXXXX
$ ./configure --with-berkeley-db=/usr/local/subversion-rXXXX \
--prefix=/usr/local/subversion-rXXXX
$ make
$ make check # optional : runs the tests
# make install
Finally, add /usr/local/subversion/bin
to your PATH
. That's
it!
The next step is to create a repository to store your files. I'll put my
repository in /home/rafael/svn
, as I have plenty of room on this
partition.
$ cd /home/rafael
$ svnadmin create svn
I have now a directory, /home/rafael/svn
, containing my
repository. It contains no files and has a revision number of 0. I'll fix
that by importing a source tree.
Suppose I'm working on a frobnizer. To create a directory
frobnizer
at the root level of the repository, and to import the
contents of my tree /home/rafael/frobnizer
, the appropriate
command is:
$ svn import file:///home/rafael/svn /home/rafael/frobnizer frobnizer
Why the URI in the above command? The few svn
commands that need to deal
directly with a repository refer to it by a URL. file://
URLs
refer to repositories on a local disk. Subversion also supports
http://
and https://
URIs for remote, Apache-powered
Subversion servers.
In fact, in order to organize your repository better, it's preferable to create a directory for your project, importing your files into a trunk subdirectory. We'll see the precise reasons for it later. Instead of the above command, use:
$ svn mkdir file:///home/rafael/svn/frobnizer -m 'Create frobnizer project'
$ svn import file:///home/rafael/svn /home/rafael/frobnizer \
frobnizer/trunk -m 'Initial import of frobnizer project'
The first command, mkdir
, creates an empty subdirectory,
frobnizer. It also labels this change with the log message Create
frobnizer project. The second command performs the actual import, adding
its own log message.
You can create as many repositories as you like. If you work on several different, unrelated projects, you may want independent repositories for each. This will enable you to handle and to move them separately later.
You don't work directly in the repository. To make changes to your files,
you must check out a working copy of the whole repository or of one of its
subdirectories. To do this, use checkout
, performed here in a
new frobwork directory:
$ svn checkout file:///home/rafael/svn/frobnizer ~/frobwork
This working copy contains all files that you've checked out, and you can
now safely edit them. Hidden .svn
subdirectories will also
contain client-side state data. These files allow Subversion to perform some
operations without dealing directly with the repository. This allows you to
work off-line even if the repository is normally network accessible.
|
Most svn
commands don't use repository URIs, acting directly on a local
working copy. The most general form of an svn
command is:
$ svn <command> [<options>] [<targets>]
where targets
is the list of files or directories to operate on, and
options
is an optional list of flags, in the familiar fashion of most
Unix command-line interfaces. For most svn
commands,
targets
defaults to the current directory, and the command operates
recursively on each directory it processes.
The first command we'll see is svn commit
(also known as
svn ci
, which should look familiar to CVS users). This commits the
modifications of the local files into the repository. For example,
$ svn commit *.c include
will check all .c files in the current directory, and all files in the include subdirectory, recursively for modifications and incorporate them into the repository. Only modified files will be included in the change set. As a consequence of this, a simple
$ svn commit
commits all modified files in the current directory and its subdirectories.
Note that Subversion requires a log message when committing changes. You can
specify the message via the -m
command-line option, as in the
import
and mkdir
examples above. Lacking this
option, svn
will fire up the editor specified by one of the
environment variables SVN_EDITOR
, VISUAL
, or
EDITOR
.
Log messages can be retrieved by the svn log
command, which
presents a formatted list of changes for its targets. It accepts a
-v
(verbose) option to include in the changelog the list of files
that were modified at each revision. The common -r
option limits
the list to a revision or a range of revisions. For example, updating a
ChangeLog file with all changes since revision #42 is as simple as:
$ cd ~/frobwork/trunk
$ svn log -r42:HEAD >> ChangeLog
$ svn commit ChangeLog -m 'Update ChangeLog'
Here, HEAD
is a keyword that can be used in place of any revision number.
It refers to the last revision number that was checked in the repository.
If you're unhappy with your changes, the svn revert
command
will undo all local edits you've done to its targets. Unlike other
svn
commands, revert
doesn't operate recursively on
directories, unless you pass the -R
option to it.
To add or to remove files, use the svn add
and svn
remove
commands. They mark files or directories to be added or removed
into and from the repository at the next commit
. Similarly, svn
mkdir
creates a new directory under version control in the working
copy.
As a rule of thumb, the set of changes included in a commit
should address a
specific problem or implement a well-defined functionality. Thinking about your
log message before making the changes can help you to focus. A single-purpose
commit
is easily examined (as a diff
), so any bugs it may have
introduced are appear more clearly. Tracking down regressions is more
difficult with several unrelated changes in a single commit
.
At some point in development, you will probably ask yourself which files
have I modified, and what changes did I make? The svn status
and svn diff
commands provide answers.
svn status
scans the specified targets of your working copy for
files that have changed since the last checkout or commit
. For each file,
it reports its status -- modified, added, deleted, or unknown to the
versioning system.
svn diff
produces a diff
file applicable by the
patch(1)
program. By default, it uses the unified diff
format.
It's possible to pass additional options to the underlying diff(1)
utility via the -x
switch. By default, it compares the current
working copy with the latest checked-out revision, but it's also able to
produce a patch between two arbitrary revisions in the repository, or between
your working copy and an older revision with the -r
switch:
$ svn diff -r14:18 *.c *.h > /tmp/r14-to-r18.patch
A simpler way of retrieving any previous state of a file within your working
copy is to use svn update
. This command updates its targets to
their state at a specified revision (defaulting to the HEAD
revision). For
example,
$ svn update -r42 include
reverts the include directory (and its contents) to the 42nd
revision. (update
is also used when you want to integrate changes
from another working copy into your working copy, but we'll cover this in
another article.) Subversion provides a more powerful mechanism to track the
release points of your projects: tags and branches. There is
no difference, from Subversion's viewpoint, between tags and branches; the
difference is in how you use them.
To create a tag or a branch, use the svn copy
command.
svn copy
makes a copy of a versioned resource (a file or a
directory), while retaining history. In other words, it doesn't add a file (or
a whole tree) -- it only marks a new entry in the repository as being
indentical to another one, at a specified revision. Thus, copies occur
done in constant time, although they may logically create huge parallel
trees.
Let's take an example. Suppose I've just released a new frobnizer
, version
2.0, and I want Subversion to remember for me that frobnizer
v2 corresponds to
revision 42. Assuming the current revision level of directory trunk in
my working copy is 42, I'll say:
$ cd ~/frobwork
$ svn copy trunk frobnizer-2.0
$ svn commit -m 'Release v2.0'
My repository has now two main subdirectories: /frobnizer/trunk and /frobnizer/frobnizer-2.0. They branch from the same revision, but can now evolve separately.
If I decide to not commit any changes to the
/frobnizer/frobnizer-2.0 subdirectory, it's called a
tag. Otherwise, it's a branch.
The advantage of a tag is obvious. It's possible to check out
/frobnizer/frobnizer-2.0 to get the source for the frobnizer
v2.
Branches are mainly useful when a team of developers have commit access to a
same repository. If a long, experimental development has to be made, it's
better to create a branch, make the changes in it, and reintegrate them into
the trunk when the development is finished. This avoids interferences.
Subversion provides a mechanism (the svn merge
command) to report
the changes made in one branch into another. Branches may not be very useful
to you if you're the only Subversion user on your system, and that's why I won't
elaborate on this subject. However, the Subversion developers recommend to
create two subdirectories, branches/ and tags/, along the
trunk/, to store branches and tags. (This is how the Subversion repository is
organized.)
Now that you've fixed many bugs, you've decided to release another version of your project as a source tarball.
You can't just tar+gzip your working copy: it contains hidden Subversion
files and probably also some other temporary files (backups, object files,
etc.). The svn export
command is here to help you. It checks out a
specified version without including metadata.
$ svn export file:///home/rafael/svn/frobnizer/frobnizer-2.0
$ tar cf frobnizer-2.0.tar frobnizer-2.0
$ gzip -9 frobnizer-2.0.tar
... to make backups! Your repository holds important information. It's possible to dump the contents of the repository (including all revisions) into a dumpfile. This format is portable, and you can use it to reconstruct a repository if necessary.
For example, it's useful to have, in a crontab
, something like :
svnadmin dump /home/rafael/svn | gzip -9 > dump.gz
This way, the repository can be restored via
gunzip -c dump.gz | svnadmin load /home/rafael/svn
The most useful svn
subcommand, at least for beginners, is
help
. svn help
gives a summary of all subcommands
available, and svn help foo
describes the subcommand
foo
. Read also the svn(1)
and
svnadmin(1)
manpages. svnadmin
is for administrative
commands.
The Subversion home page holds a substantial amount of information. The Subversion Book, a work in progress, is also useful, containing far more information than possible to put in a small article.
Rafael Garcia-Suarez is a French software engineer and Unix system administrator.
Copyright © 2004 O'Reilly Media, Inc.