Multiuser Subversion
Pages: 1, 2
Metadata
An interesting feature of Subversion is that it allows an arbitrary amount of metadata to be attached to any versioned resource (files and directories). Metadata, like files, are also versioned. This metadata is a set of key/value pairs, known as properties.
You can use properties to annotate files (let's say,
review-status to this file is being reviewed by Joe), or
directories. For example, on a tag directory frobnizer-1.09b, you
can add a note beta release, for internal use only.
Properties whose names begin with svn: are reserved by
Subversion. Some of them are specifically recognized and handled. For example,
svn:executable marks a file to be checked-out with the executable
flag set on filesystems that support it. Other interesting properties
include:
svn:keywordscontrols keyword expansion. Like CVS, Subversion can replace strings of the form$Keyword$or$Keyword:...$embedded in text files. The keywords that you want to be replaced should be listed in the value of thesvn:keywordsproperty. Subversion provides keywords for the last user that modified the file, the last revision number that affected the file, the date of this last revision, and an absolute URL for the file in the repository. For example, if the standard headers for some of your files contain the keywords$Rev$and$Author$, you can enable their automatic substitution with the following commands:$ svn propset svn:keywords 'Rev Author' *.c $ svn commit -m "Enable keywords Rev and Author on C files" *.csvn:mime-typeattaches a MIME type to a file to be used when delivering the file via HTTP. It's also used to determine whether the file should be stored internally as text or as binary. No MIME type, or a MIME type that begins withtext/, indicates a text file. All other types indicate a binary file. Note that thesvn importandsvn addcommands try to recognize binary files and tag them as such, with the default MIME typeapplication/octet-stream. Subversion does not attempt to make diffs between different versions of a binary file.svn:eol-styleis very useful when several developers work on different platforms. It's used to force the line endings toCR,LF, orCRLF, or to check-out always the file using the native line ending used on the developer's platform.
Branches, Switching and Merging
I presented an overview of tags and branches in the first article. Branches prove to be useful mainly on multiuser projects. With branches, a developer or a team of developers, can work on an experimental feature without interfering with the main development. Branches can also be used to keep track of changes in a maintenance version of a product. They can be used to handle beta releases and the returns of beta-testers. Subversion makes it easy and cheap to create branches, so why shouldn't you use them?
A branch is typically created outside a working copy to spare disk space
with the form of the copy command that operates directly on URLs.
The following creates a maintenance branch from the current project trunk (by
convention, the root directory of your project files):
$ svn copy http://my.host/svn/frobnizer/trunk \
http://my.host/svn/frobnizer/maint-1.0
To start working on a branch, you can of course check out a whole new
working copy corresponding to it, but it's easier to switch your
working copy (or parts of it) to the branch. Assuming that your working copy
already contains the trunk, you can make it point at the maint-1.0
branch with the following command, issued at the root of your working copy:
$ svn switch http://my.host/svn/frobnizer/maint-1.0 .
svn switch works a bit like update, except that it
doesn't conceptually move your working copy through time (revisions), but
through space (branches). Consistently, the output of switch is
similar to that of update.
Finally, to integrate changes from another branch in your working copy, you
can use the powerful svn merge command. merge can be
compared to diff, but instead of outputting changes as a unified
diff to standard output, it applies them to your working copy (as you would
apply a patch).
For example, the following commands integrate a batch of changes from the trunk into your maintenance working copy:
$ svn merge -r149:155 http://my.host/svn/frobnizer/trunk
U foo.c
U foo.h
A bar.c
$ svn status
M foo.c
M foo.h
A + bar.c
$ svn commit -m 'Integrate revisions 150 to 155 from the trunk'
The output of svn merge indicates which files have been
affected by the changes, just like svn update. The svn
status command reports the status of files in your working copy. In this
exmaple, foo.c and foo.h have local modifications,
and bar.c is scheduled for addition in the next commit. The
+ sign in the status line indicates that Subversion knows that
this file has been branched from elsewhere, and will retain this information
when committing it.
Note that you may have to resolve manually potential conflicts between the merge and the commit.
An interesting use of merge is to fetch changes from the
current branch. This way you can roll back a change. The following command
applies the changes of revision 200 to your working copy, in
reverse:
$ svn merge -r200:199 .
Meanwhile, in the Real World
Once you're getting used to Subversion, you'll find that it can help you in ways you didn't expect.
A first example would be dealing with runtime configuration files during upgrades. Working on a software project where some global configuration variables (IP addresses, environment variables or trace levels) are read in a file, I have to modify this file almost every time the application is installed on another machine. A default configuration file is provided with the sources, and it's kept under version control because the set of configuration variables changes over versions. What to do when I want to upgrade a snapshot installed on a test machine, but without losing the local changes to the config file?
The solution is simple. Instead of installing the application on the test
machine from a source tarball, I copied my statically linked svn
client there and performed a check-out. Then, I adjusted the configuration
files to my needs, without commiting the changes. Upgrading the software to
another development snapshot is as easy as an svn update followed
by a make all . The update process integrates the common changes
to the configuration file (e.g., new variables) with the local changes (e.g.,
user/password to access a local database). This can be applied to any evolving
configuration file you need to deploy: an /etc/profile, a
.vimrc, or an httpd.conf.
Branches can also be used in creative ways. I work on an intranet application that ships with several sets of style sheets. For example, some are designed for low resolution screens and provide different font sizes and background images.
I set up two directories, /html/css/800 and
/html/css/1024, to hold those CSS. The 1024
directory, for style sheets adapted to a higher screen resolution, is a branch
of the other. When a CSS is augmented or modified, it's easy to incorporate its
changes into the other branch while leaving the specific font or image
settings untouched.
I'm sure Subversion will be used in ways its designers didn't imagine. That's what makes the success of a tool.
Hints and Links
- The Subversion home page. You can get from there the latest version of the Subversion Book, which is still being written.
- The Apache Software Foundation.
- Sleepycat Software, which provides the Berkeley DB.
- The WebDAV protocol. Subversion uses a subset of the WebDAV and DeltaV protocols, DeltaV being an extension to WebDAV, that adds versioning capabilities to it.
Thanks to Karl Fogel for having kindly reviewed this article.
Rafael Garcia-Suarez is a French software engineer and Unix system administrator.
Return to the Apache DevCenter.