March 24, 2019
Hot Topics:

A Crash Course in Subversion, Part 2

  • May 6, 2005
  • By Garrett Rooney
  • Send Email »
  • More Articles »


To provide something roughly analogous to CVS's modules, Subversion offers the svn:externals property. This property is set on a directory and contains a newline-separated list of module specifications. Each module specification contains a relative path to the directory the module should be checked out into, an optional revision (which is specified as -r REVNUM), and a URL pointing to a location in a Subversion repository. When the directory with the svn:externals property is checked out, the modules will also be checked out into the same working copy. This allows you to pull directories from other parts of the repository, or even completely different repositories, into your working copy, which can be useful if you're sharing code between multiple projects, or if you need to modify the directory layout of your working copy in certain situations.

$ svn list file:///path/to/repos
$ svn propget file:///path/to/repos/application/trunk/libs svn:externals
libedit file:///path/to/repos/libedit/trunk
libnetwork file:///path/to/repos/libnetwork/trunk
$ svn checkout file:///path/to/repos/application/trunk application
A application/README
A application/main.c
A application/libs
Checked out revision 47.
Fetching external item into libedit
A application/libs/libedit/Makefile
A application/libs/libedit/README
A application/libs/libedit/edit.c
A application/libs/libedit/history.c
A application/libs/libedit/prompt.c
Checked out revision 47.
Fetching external item into libnetwork
A application/libs/libnetwork/Makefile
A application/libs/libnetwork/README
A application/libs/libnetwork/socket.c
A application/libs/libnetwork/marshal.c
Checked out revision 47.
$ svn info application/libs | grep ^URL
$ svn info application/libs/libedit | grep ^URL
$ svn info application/libs/libnetwork | grep ^URL

Here you can see an example of using svn:externals to allow everyone who checks out the source for an application, which lives in file:///path/to/repos/application/trunk, to also get the source for several libraries that the application depends on. In this case, the libraries are stored in the same repository as the application, but there's nothing that says they have to. The URLs in the svn:externals property could just as easily have pointed to a completely different repository, and it would work just the same.

Revision Properties

In addition to the standard versioned properties Subversion can store for each file or directory in your repository, there are properties stored for each revision in the repository. These "revprops" are used to record information such as the author of each revision (author), the date and time the revision was created (date), and the log entry for the revision (log). Most of the time, you don't need to care about these properties. They're created automatically, and Subversion is perfectly capable of using them for the commands that require the information they store without any intervention from you.

The exception to this rule, of course, is when you need to go back and edit them. Most of the time, you find people doing this when they want to adjust a log entry on an old revision. Because these properties are stored on a per-revision basis, they aren't themselves versioned. That means that if you change them, the previous version is lost for good (unless you resort to looking in your repository backups or something like that). Because of this, Subversion won't allow you to change revision properties unless you explicitly turn this capability on. To do this, you need to enable the pre-revprop-change hook script. The procedure for doing so is documented in the next chapter, so for now, all you need to know is that you should look inside the repository, in the hooks directory. There, you'll see a file named pre-revprop-change.tmpl. This is the sample pre-revprop-change hook script. Assuming you're on a Unix machine, you should be able to just copy pre-revprop-change.tmpl to pre-revprop-change, make it executable with a quick chmod +x pre-revprop-change, and you're all set. The default script in pre-revprop-change.tmpl will let you change only the svn:log revprop, so let's take a look at how you can do that.

$ ls /path/to/repos/hooks
post-commit.tmpl        pre-commit.tmpl        start-commit.tmpl
post-revprop-change.tmpl pre-revprop-change.tmpl
$ cp /path/to/repos/hooks/pre-revprop-change.tmpl \
$ chmod +x /path/to/repos/hooks/pre-revprop-change
$ svn log --revision 10 file:///path/to/repos
r10 |  rooneg |  2003-06-30 18:12:07 -0400 (Mon,30 Jun 2003) | 1 line
This is revision 10's log entry
$ svn propget --revprop svn:log --revision 10 file:///path/to/repos
This is revision 10's log entry.
$ svn propset --revprop svn:log --revision 10 \
      "This is revision 10's new log entry"file:///path/to/repos
property 'svn:log'set on repository revision '10'
$ svn propget --revprop svn:log --revision 10 file:///path/to/repos
This is revision 10's new log entry.
$ svn log --revision 10 file:///path/to/repos
r10 |  rooneg | 2003-06-30 18:12:07 -0400 (Mon,30 Jun 2003) | 1 line
This is revision 10's new log entry

There you have it—changing an incorrect log entry is that easy. All you have to do is enable the pre-revprop-change script, use the standard commands you normally use to access Subversion properties, add a --revprop argument and a --revision, and you're done.

Miscellaneous Commands

And now you're down to it, those last few client-side commands that just don't fit into any other specific section of the chapter. Not that svn blame and svn cleanup aren't important, it's just that they both don't fit in with any of the groups of commands we've already talked about. They're still useful though, and you'll most likely find yourself needing them at least every now and then.

svn blame

When you're working on a file that has changed many times over the course of its history, it's often nice to be able to ask the question "What revision introduced this particular line?" Although it's possible to manually go back through the revision history diffing files until you find the revision responsible, it's much more convenient to use the svn blame command.4 svn blame takes a working copy path or URL and optionally a range of revisions, and outputs a formatted version of the file in which each line is prefixed with the revision that line originates from and the username of the author of that revision. The output looks like this:

$ svn blame svn://svn.example.org/repos/project/trunk/hello.c
12          steve #include <stdio.h>
10           greg
10           greg int
10           greg main (int argc, char *argv)
10           greg {
11         robert printf ("hello world \n");
10           greg return 0;
10           greg }

From this output, you can see that most of the file originated in revision 10, which was committed by greg, with line 6 being changed by robert in revision 11, and line 1 being changed by steve in revision 12.

It's worth noting that although the output from svn blame can be exceptionally useful, Subversion's repository design doesn't make it particularly efficient to implement. Because Subversion stores differences using a binary diffing algorithm that doesn't track changes on a line-by-line basis, the current implementation involves downloading each individual revision of the file in question and manually diffing them on the client machine to determine the origin of each line. Thus the command may take quite a while to execute when the file in question has many revisions or when it's quite large. Also keep in mind that svn blame is meaningless when applied to a directory or to a binary file.

Page 5 of 6

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date