A Crash Course in Subversion

Other Differentiating Features

In addition to Subversion's nonlocking workflow, a couple more things differentiate it from other version control systems. First, all changes to the repository are atomic; either all parts of a change go in, or none of them do. As a result, there's a single repositorywide revision number, which describes the state of the entire tree. So when you refer to "version 247 of foo.c," it's really more correct to say "foo.c as it exists in revision 247 of the repository." This is similar to the changeset number in Perforce, and although it may seem odd to not have per-file revisions (which exist in Perforce and are the only kind of revision in CVS), thinking in terms of atomic changes that can encompass multiple separate files rather than several different changes to different files is quite easy to adjust to. In fact, it's a good idea to start thinking in those terms anyway because it helps you focus on forming coherent atomic changes, something that helps ensure the source tree is always in a usable state. Second, Subversion doesn't just keep track of changes to files, it actually versions entire directory trees. This means that directories are first-class items to Subversion, and they can be added and removed just like files can be.

Throughout the rest of this chapter, I'll cover what you need to know to be an effective Subversion user. This crash course includes how to use of the svn command-line client and the concepts you need to be aware of to make effective use of it. By the end of the chapter, you should be well prepared to start making use of Subversion in your daily development work.

The Most Important Subversion Commands

Before you get started with Subversion, it's important to be aware of a few commands that are going to prove very useful to you. Both of the major Subversion executables (svn, the command line client, and svnadmin, the repository administration tool) have built-in help for each of their commands. To access the help, just use the help command, like this:

Many of the subcommands include both a canonical primary name, such as "diff", and some shorter aliases that appear in parentheses after the canonical primary name, such as "di". In the help output, the aliases for each subcommand are always shown in parentheses.

In everyday use, it's common to use the shorter versions of the commands. For example, if someone mentions running svn up to update his working copy, he's really talking about the svn update command. It's probably a good idea to at least become familiar with the various aliases for just this reason. In this book I use the longer names in my examples, because they tend to more clearly represent what the command actually does. The shorter names generally exist for historical reasons (i.e., if CVS uses the same alias for a similar command and there isn't a compelling reason not to support it, Subversion likely has the same alias) or because the aliases are similar to some common command-line utility. Both types of shortcuts serve to help people remember the name of the command.

The remainder of this chapter introduces the commands you're likely to use on a day-to-day basis as a Subversion user. For more specific information about a svn subcommand, just run svn help subcommand, which gives you output like this:

$svn help add
add:Put files and directories under revision control,scheduling
them for addition to repository.They will be added in next commit.
usage:add PATH [PATH [PATH ...]]
Valid options:
--targets arg :pass contents of file ARG as
:additional args
-N [--non-recursive ] :operate on single directory only
-q [--quiet ] :print as little as possible
$

svn help will quickly become your new best friend, as it provides the quick hints you need as you get used to the new commands.

For more in-depth documentation of each of the commands, please see the glossary of Subversion commands in Appendix A.

Revisions and URLs

The majority of Subversion's commands require you to refer to a particular revision of an entity in the repository, where the entity could be a file or a directory. You generally specify this entity by using a URL and possibly a revision. If, for example, your repository is located at /home/repos/projects, then the URL file:///home/repos/projects/trunk/final refers to whatever is located at /trunk/final, in this case most likely a directory, which would likely contain other items. If you're on a Windows system and you need to refer to a repository on a drive different from the one your current working directory is on, the syntax looks like this: file://C:/path/to/repos or file://C|/path/to/repos. In addition to file://-based URLs, Subversion can be built with support for two other URL schemes, each of which refers to repositories that are accessed via a different repository access layer. URLs that start with http:// or https:// refer to repositories that are accessed via ra_dav, which uses a WebDAV-based protocol. svn:// or svn+ssh:// URLs refer to repositories that are accessed via ra_ssh, a custom TCP protocol written just for Subversion. In both cases, the URLs used to access repositories via these protocols include the name of the server the repository is located on after the schema, then a path to the location of the repository, followed by the location within the repository you're interested in. When a URL is used alone, without a specific revision, it refers to the newest revision of the item at that path within the repository.

Table 2-1 breaks down the components that make up a number of different Subversion URLs.

Table 2-1. URL Breakdown

URL

RA Layer

Host

Repository

Path

http://example.org/repos/trunk/README

ra_dav

example.org

/repos

trunk/README

file:///path/to/repos/branches/1.0.x/src/main.c

ra_local

Not applicable

/path/to/repos

branches/1.0.x/src/main.c

svn://example.org/repos/sandbox/tags/0.47/HACKING

ra_svn

example.org

/repos/sandbox

tags/0.47/HACKING

svn+ssh://example.org/home/repos/dev/trunk/include/globals.h

ra_svn over ssh

example.org

/home/repos/dev

trunk/include/globals.h

You can specify a revision in Subversion in several different ways. First off, you can always specify the literal revision number, which is a monotonically increasing integer. Zero is the initial revision of the repository, before any data is added to it, and for each change that is made the revision increases by one. In addition to using literal revision numbers, you can use shortcuts, such as the HEAD keyword, which refers to the most recent revision in the repository. There's also BASE, which refers to the version of an item that you have in your working copy; COMMITTED, which is the revision in which the item was last changed; and PREV, which is the revision before the item was last changed. If you're looking to specify the revision the repository was at on a particular date, you can just use the date enclosed in curly braces. For example, {1978-02-05}indicates the revision the item was at on February 5, 1978. Table 2-2 shows the various ways you can specify revisions to Subversion.

Table 2-2. Revision Specifications

Revision Specification

Meaning

10

Literal revision 10

10:20

A range of revisions from 10 to 20

HEAD

Youngest revision in the repository

BASE

Current revision of the working copy

COMMITTED

Revision in which an entry was last changed

PREV

Revision before the last revision in which the item was changed

{2003-03-25}

Revision the item was at on March 25, 2003

{2003-02-27 10:00}

Revision the item was on at 10:00 on February 27, 2003

In most cases, you specify revisions by using the --revision keyword, which can be abreviated with -r, followed by the revision (e.g., svn update --revision 10 ). If the command refers to a range of revisions, the revisions are separated by colons, as in svn diff --revision 9:10, where you're indicating that the svn diff command should start at revision 9 and end at revision 10. In a few cases, the revision can be associated with the URL directly by appending it and delimiting it with an @. For example, file:///home/repos/projects/trunk/final@4747 refers to /trunk/final as it existed in revision 4747.