Repository Administration
*************************

How to administer a Subversion repository.

In this section, we'll mainly focus on how to use the svnadmin and svnlook programs to work with repositories.

Creating a repository
=====================

Creating a repository is incredibly simple:

     $ svnadmin create path/to/myrepos

This creates a new repository in a subdirectory myrepos.

(Note that the svnadmin and svnlook programs operate directly on a repository, by linking to libsvn_fs.so. So these tools expect ordinary, local paths to the repositories.  This is in contrast with the svn client program, which always accesses a repository via some URL, whether it be via http:// or file:/// schemas.)

A new repository always begins life at revision 0, which is defined to be nothing but the root (/) directory.

As mentioned earlier, repository revisions can have unversioned properties attached to them.  In particular, every revision is created with a svn:date timestamp property.  (Other common properties include svn:author and svn:log)

For a newly created repository, revision 0 has nothing but a svn:date property attached.

Here is a quick run-down of the anatomy of a repository:

     $ ls myrepos
     conf/
     dav/
     db/
     hooks/
     locks/

conf
     Currently unused; repository-side config files will go in here someday.

dav
     If the repository is being accessed by Apache and mod_dav_svn, some private housekeeping databases are stored here.

db
     The main Berkeley DB environment, full of DB tables that comprise the data store for libsvn_fs.  This is where all of your data is!  In particular, most of your files' contents end up in the ``strings'' table. Logfiles accumulate here as well, so transactions can be recovered.

hooks
     Where pre-commit and post-commit hook scripts live.  (And someday, read-hooks.)

locks
     A single file lives here; repository readers and writers take out shared locks on this file.  Do not remove this file.

Once the repository has been created, it's very likely that you'll want to use the svn client to import an initial tree.  (Try svn help import, or see Other Commands.)

You may want to give your repository an initial directory structure that reflects the trunk, branches, and tags of your project(s) (see Branches and Tags.)  You can do this via svn mkdir:

     $ svnadmin create /path/to/repos
     $ svn mkdir file:///path/to/repos/projectA -m 'Base dir for A'
     Committed revision 1.

     $ svn mkdir file:///path/to/repos/projectA/trunk -m 'Main dir for A'
     Committed revision 2.

     $ svn mkdir file:///path/to/repos/projectA/branches -m 'Branches for A'
     Committed revision 3.

     $ svn mkdir file:///path/to/repos/projectA/tags -m 'Tags for A'
     Committed revision 4.

     $ svn co file:///path/to/repos/projectA/trunk projectA
     Checked out revision 4.

     # ... now work on projectA ...

With svn import, you can create the structure with a single commit:

     $ svnadmin create /path/to/repos
     $ mkdir projectA
     $ mkdir projectA/trunk
     $ mkdir projectA/branches
     $ mkdir projectA/tags
     $ svn import file:///path/to/repos projectA projectA -m 'Dir layout for A'
     Adding         projectA/trunk
     Adding         projectA/branches
     Adding         projectA/tags
     Committed revision 1.

     $ rm -rf projectA/
     $ svn co file:///path/to/repos/projectA/trunk projectA
     Checked out revision 1.

     #  ... now work on projectA ...

Examining a repository
======================

Transactions and Revisions
--------------------------

A Subversion repository is essentially a sequence of trees; each tree is called a revision.  (If this is news to you, it might be good for you to read Transactions and Revision Numbers.)

Every revision begins life as a transaction tree.  When doing a commit, a client builds a transaction that mirrors their local changes, and when the commit succeeds, the transaction is effectively ``promoted'' into a new revision tree, and is assigned a new revision number.

At the moment, updates work in a similar way: the client builds a transaction tree that is a ``mirror'' of their working copy.  The repository then compares the transaction tree with some revision tree, and sends back a tree-delta.  After the update completes, the transaction is deleted.

Transaction trees are the only way to ``write'' to the repository's versioned filesystem; all users of libsvn_fs will do this.  However, it's important to understand that the lifetime of a transaction is completely flexible.  In the case of updates, transactions are temporary trees that are immediately destroyed.  In the case of commits, transactions are transformed into permanent revisions (or aborted if the commit fails.)  In the case of an error or bug, it's possible that a transaction can be accidentally left lying around -- the libsvn_fs caller might die before deleting it.  And in theory, someday whole workflow applications might revolve around the creation of transactions; they might be examined in turn by different managers before being deleted or promoted to revisions.

The point is: if you're administering a Subversion repository, you're going to have to examine revisions and transactions.  It's part of monitoring the health of the repository.

svnlook
-------

svnlook is a read-only (Why read-only?  Because if a pre-commit hook script changed the transaction before commit, the working copy would have no way of knowing what happened, and would therefore be out of sync and not know it.  Subversion currently has no way to handle this situation, and maybe never will.) tool that can be used to examine the revision and transaction trees within a repository. It's useful for system administrators, and can be used by the pre-commit and post-commit hook scripts as well.

The simplest usage is

     $ svnlook repos

This will print information about the HEAD revision in the repository ``repos.''  In particular, it will show the log message, author, date, and a diagram of the tree.

To look at a particular revision or transaction:

     $ svnlook repos rev 522
     $ svnlook repos txn 340

Or, if you only want to see certain types of information, svnlook accepts a number of subcommands.  For example,

     $ svnlook repos rev 522 log
     $ svnlook repos rev 559 diff

Available subcommands are:

log
     Print the tree's log message.

author
     Print the tree's author.

date
     Print the tree's datestamp.

dirs-changed
     List the directories that changed in the tree.

changed
     List all files and directories that changed in the tree.

diff
     Print unified diffs of changed files.

the shell
---------

The svnadmin tool has a toy ``shell'' mode as well.  It doesn't do much, but it allows you to poke around the repository as if it were an imaginary mounted filesystem.  The basic commands cd, ls, exit, and help are available, as well as the very special command cr -- ``change revision.''  The last command allows you to move between revision trees.

     $ svnadmin shell repos
     <609: />$
     <609: />$ ls
       < 1.0.2i7>  [   601]  1           0    trunk/
       <nh.0.2i9>  [   588]  0           0    branches/
       <jz.0.18c>  [   596]  0           0    tags/

     <609: />$ cd trunk
     <609: /trunk>$ cr 500
     <500: /trunk>$ ls
       <   2.0.1>  [     1]  0        3462    svn_config.dsp
       <  4.0.dj>  [   487]  0        3856    PORTING
       <  3.0.cr>  [   459]  0        7886    Makefile.in
       <  d.0.ds>  [   496]  0        9736    build.conf
       <  5.0.d9>  [   477]  1           0    ac-helpers/
       <   y.0.1>  [     1]  0        1805    subversion.dsp
     ...
     <500: />$ exit

The output of ls has only a few columns:

       NODE-ID  CREATED-REV HAS_PROPS?  SIZE  NAME

       < 1.0.2i7>  [   601]  1           0    trunk/
       <nh.0.2i9>  [   588]  0           0    branches/
       <jz.0.18c>  [   596]  0           0    tags/

Repository hooks
================

A hook is a program triggered by a repository read or write access.  The hook is handed enough information to tell what the action is, what target(s) it's operating on, and who is doing it.  Depending on the hook's output or return status, the hook program may continue the action, stop it, or suspend it in some way.

Subversion's hooks are programs that live in the repository's hooks directory:

     $ ls repos/hooks/
     post-commit.tmpl*  read-sentinels.tmpl  write-sentinels.tmpl
     pre-commit.tmpl*   start-commit.tmpl*

This is how the hooks directory appears after a repository is first created.  It doesn't contain any hook programs -- just templates.

The actual hooks need to be named start-commit, pre-commit and post-commit.  The template (.tmpl) files are example shell scripts to get you started; read them for details about how each hook works.  To make your own hook, just copy foo.tmpl to foo and edit.

(The read-sentinels and write-sentinels are not yet implemented. They are intended to be more like daemons than hooks.  A sentinel is started up at the beginning of a user operation.  The Subversion server communicates with the sentinel using a protocol yet to be defined.  Depending on the sentinel's responses, Subversion may stop or otherwise modify the operation.)

Here is a description of the hook programs:

start-commit
     This is run before the committer's transaction is even created.  It is typically used to decide if the user has commit privileges at all.  The repository passes two arguments to this program: the path to the repository, and username which is attempting to commit.  If the program returns a non-zero exit value, the commit is stopped before the transaction is even created.

pre-commit
     This is run when the transaction is complete, but before it is committed.  Typically, this hook is used to protect against commits that are disallowed due to content or location (for example, your site might require that all commits to a certain branch include a ticket number from the bug tracker, or that the incoming log message is non-empty.) (At this time, this is the only method by which users can implement finer-grained access control beyond what httpd.conf offers.  In a future version of Subversion, we plan to implement ACLs directly in the filesystem.)  The repository passes two arguments to this program: the path to the repository, and the name of the transaction being committed.  If the program returns a non-zero exit value, the commit is aborted and transaction is removed.

     The Subversion distribution includes a tools/hook-scripts/commit-access-control.pl script that can be called from pre-commit to implement fine-grained access control.

post-commit
     This is run after the transaction is committed, and we have a new revision.  Most people use this hook to send out descriptive commit-emails or to make a hot-backup of the repository.  The repository passes two arguments to this program: the path to the repository, and the new revision number that was created.  The exit code of the program is ignored.

     The Subversion distribution includes a tools/hook-scripts/commit-email.pl script that can be used to send out the differences applied in the commit to any number of email addresses.  Also included is tools/backup/hot-backup.py, which is a script that perform hot backups of your Subversion repository after every commit.

Note that the hooks must be executable by the user who will invoke them (commonly the user httpd runs as), and that same user needs to be able to access the repository.

The pre-commit and post-commit hooks need to know things about the change about to be committed (or that has just been committed).  The solution is a standalone program, svnlook (see Examining a repository.) which was installed in the same place as the svn binary.  Have the script use svnlook to examine a transaction or revision tree.  It produces output that is both human- and machine-readable, so hook scripts can easily parse it.  Note that svnlook is read-only -- it can only inspect, not change the repository.

Repository maintenance
======================

Berkeley DB management
----------------------

At the time of writing, the subversion repository has only one database back-end: Berkeley DB.  All of your filesystem's structure and data live in a set of tables within repos/db/.

Berkeley DB comes with a number of tools for managing these files, and they have their own excellent documentation.  (See http://www.sleepycat.com/, or just read man pages.)  We won't cover all of these tools here; rather, we'll mention just a few of the more common procedures that repository administrators might need.

First, remember that Berkeley DB has genuine transactions.  Every attempt to change the DB is first logged.  If anything ever goes wrong, the DB can back itself up to a previous `checkpoint' and replay transactions to get the data back into a sane state.

In our experience, we have seen situations where a bug in Subversion (which causes a crash) can sometimes have a side-effect of leaving the DB environment in a `locked' state.  Any further attempts to read or write to the repository just sit there, waiting on the lock.

To `unwedge' the repository:

 1. Shut down the Subversion server, to make sure nobody is accessing the repository's Berkeley DB files.

 2. Switch to the user who owns and manages the database.

 3. Run the command db_recover -v -h REPOS/db, where REPOS is the repository's directory name.  You should see output like this:

          db_recover: Finding last valid log LSN: file: 40 offset 4080873
          db_recover: Checkpoint at: [40][4080333]
          db_recover: Checkpoint LSN: [40][4080333]
          db_recover: Previous checkpoint: [40][4079793]
          db_recover: Checkpoint at: [40][4079793]
          db_recover: Checkpoint LSN: [40][4079793]
          db_recover: Previous checkpoint: [40][4078761]
          db_recover: Recovery complete at Sun Jul 14 07:15:42 2002
          db_recover: Maximum transaction id 80000000 Recovery checkpoint [40][4080333]

     Make sure that the db_recover program you invoke is the one distributed with the same version of Berkeley DB you're using in your Subversion server.

 4. Restart the Subversion server.

Make sure you run this command as the user that owns and manages the database --- typically your Apache process --- and not as root. Running db_recover as root leaves files owned by root in the db directory, which the non-root user that manages the database cannot open.  If you do this, you'll get ``permission denied'' error messages when you try to access the repository.

Second, a repository administrator may need to manage the growth of logfiles.  At any given time, the DB environment is using at least one logfile to log transactions; when the `current' logfile grows to 10 megabytes, a new logfile is started, and the old one continues to exist.

Thus, after a while, you may see a whole group of 1MB logfiles lying around the environment.  At this point, you can make a choice: if you leave every single logfile behind, it's guaranteed that db_recover will always be able to replay every single DB transaction, all the way back to the first commit.  (This is the `safe', or perhaps paranoid, route.)  On the other hand, you can ask Berkeley DB to tell you which logfiles are no longer being actively written to:

     $ db_archive -a -h repos/db
     log.0000000023
     log.0000000024
     log.0000000029

Subversion's own repository uses a post-commit hook script, which, after performing a `hot-backup' of the repository, removes these excess logfiles.  (In the Subversion source tree, see tools/backup/hot-backup.py)

This script also illustrates the safe way to perform a backup of the repository while it's still up and running: recursively copy the entire repository directory, then re-copy the logfiles listed by db_archive -l.

To start using a repository backup that you've restored, be sure to run db_recover -v command in the db area first. This guarantees that any unfinished log transactions are fully played before the repository goes live again.  (The hot-backup.py script does that for you during backup, so you can skip this step if you decide to use it.)

Finally, note that Berkeley DB has a whole locking subsystem; in extremely intensive svn operations, we have seen situations where the DB environment runs out of locks.  The maximum number of locks can be adjusted by changing the values in the repos/db/DB_CONFIG file.  Don't change the default values unless you know what you're doing; be sure to read http://www.sleepycat.com/docs/ref/lock/max.html first.

Tweaking with svnadmin
----------------------

The svnadmin tool has some subcommands that are specifically useful to repository administrators.  Be careful with svnadmin!  Unlike svnlook, which is read-only, svnadmin has the ability to modify the repository.

The most-used feature is probably svnadmin setlog.  A commit's log message is an unversioned property directly attached to the revision object; there's only one log message per revision. Sometimes a user screws up the message, and it needs to be replaced:

     $ echo "Here is the new, correct log message" > newlog.txt
     $ svnadmin setlog myrepos 388 newlog.txt

There's a nice CGI script in tools/cgi/ that allows people (with commit-access passwords) to tweak existing log messages via web browser.

Another common use of svnadmin is to inspect and clean up old, dead transactions.  Commits and updates both create transaction trees, but occasionally a bug or crash can leave them lying around. By inspecting the datestamp on a transaction, an administrator can make a judgment call and remove it:

     $ svnadmin lstxns myrepos
     319
     321
     $ svnadmin lstxns --long myrepos
     Transaction 319
     Created: 2002-07-14T12:57:22.748388Z
     ...
     $ svnadmin rmtxns myrepos 319 321

Another useful subcommand: svnadmin undeltify.  Remember that the latest version of each file is stored as fulltext in the repository, but that earlier revisions of files are stored as ``deltas'' against each next-most-recent revisions.  When a user attempts to access an earlier revision, the repository must apply a sequence of backwards-deltas to the newest fulltexts in order to derive the older data.

If a particular revision tree is extremely popular, the administrator can speed up the access time to this tree by ``undeltifying'' any path within the revision -- that is, by converting every file to fulltext:

     $ svnadmin undeltify myrepos 230 /project/tags/release-1.3
     Undeltifying `/project/tags/release-1.3' in revision 230...done.

Networking a repository
=======================

Okay, so now you have a repository, and you want to make it available over a network.

Subversion's primary network server is Apache httpd speaking WebDAV/deltaV protocol, which is a set of extension methods to http. (For more information on DAV, see http://www.webdav.org/.)

To network your repository, you'll need to

  * get Apache httpd 2.0 up and running with the mod_dav module

  * install the mod_dav_svn plugin to mod_dav, which uses Subversion's libraries to access the repository

  * configure your httpd.conf file to export the repository

You can accomplish the first two items by either building httpd and Subversion from source code, or by installing a binary packages on your system.  The second appendix of this document contains more detailed instructions on doing this. (see Compiling and installing.)  Instructions are also available in the INSTALL file in Subversion's source tree.

In this section, we focus on configuring your httpd.conf.

Somewhere near the bottom of your configuration file, define a new Location block:

     <Location /repos/myrepo>
        DAV svn
        SVNPath /absolute/path/to/myrepo
     </Location>

This now makes your myrepo repository available at the URL http://hostname/repos/myrepo.

Alternately, you can use the SVNParentPath directive to indicate a ``parent'' directory whose immediate subdirectories are are assumed to be independent repositories:

     <Location /repos>
        DAV svn
        SVNParentPath /absolute/path/to/parent/dir
     </Location>

If you were to run svnadmin create foorepo within this parent directory, then the url http://hostname/repos/foorepo would automatically be accessible without having to change httpd.conf or restart httpd.

Note that this simple <Location> setup starts life with no access restrictions at all:

  * Anyone can use their svn client to checkout either a working copy of a repository URL, or of any URL that corresponds to a subdirectory of a repository.

  * By pointing an ordinary web browser at a repository URL, anyone can interactively browse the repository's latest revision.

  * Anyone can commit to a repository.

If you want to restrict either read or write access to a repository as a whole, you can use Apache's built-in access control features.

First, create an empty file that will hold httpd usernames and passwords.   Place names and crypted passwords into this file like so:

     joe:Msr3lKOsYMkpc
     frank:Ety6rZX6P.Cqo
     mary:kV4/mQbu0iq82

You can generate the crypted passwords by using the standard crypt(3) command, or using the htpasswd tool supplied in Apache's bin directory:

     $ /usr/local/apache2/bin/htpasswd -n sussman
     New password:
     Re-type new password:
     sussman:kUqncD/TBbdC6

Next, add lines within your <Location> block that point to the user file:

     AuthType Basic
     AuthName "Subversion repository"
     AuthUserFile /path/to/users/file

If you want to restrict all access to the repository, add one more line:

     Require valid-user

This line make Apache require user authentication for every single type of http request to your repository.

To restrict write-access only, you need to require a valid user for all request methods except those that are read-only:

     <LimitExcept GET PROPFIND OPTIONS REPORT>
        Require valid-user
     </LimitExcept>

Or, if you want to get fancy, you can create two separate user files, one for readers, and one for writers:

     AuthGroupFile /my/svn/group/file

     <LimitExcept GET PROPFIND OPTIONS REPORT>
        Require group svn_committers
     </LimitExcept>

     <Limit GET PROPFIND OPTIONS REPORT>
        Require group svn_committers
        Require group svn_readers
     </Limit>

These are only a few simple examples.  For a complete tutorial on Apache access control, please consider taking a look at the ``Security'' tutorials found at http://httpd.apache.org/docs-2.0/misc/tutorials.html.

Another note: in order for svn cp to work (which is actually implemented as a DAV COPY request), mod_dav needs to be able to be able to determine the hostname of the server.  A standard way of doing this is to use Apache's ServerName directive to set the server's hostname.  Edit your httpd.conf to include:

     ServerName svn.myserver.org

If you are using virtual hosting through Apache's NameVirtualHost directive, you may need to use the ServerAlias directive to specify additional names that your server is known by.

(If you are unfamiliar with an Apache directive, or not exactly sure about what it does, don't hesitate to look it up in the documentation: http://httpd.apache.org/docs-2.0/mod/directives.html.)

You can test your exported repository by firing up httpd:

     $ /usr/local/apache2/bin/apachectl stop
     $ /usr/local/apache2/bin/apachectl start

Check /usr/local/apache2/logs/error_log to make sure it started up okay.  Try doing a network checkout from the repository:

     $ svn co http://localhost/repos wc

The most common reason this might fail is permission problems reading the repository db files.  Make sure that the user ``nobody'' (or whatever UID the httpd process runs as) has permission to read and write the Berkeley DB files!  This is a very common problem.

You can see all of mod_dav_svn's complaints in the Apache error logfile, /usr/local/apache2/logs/error_log, or wherever you installed Apache.  For more information about tracing problems, see "Debugging the server" in the HACKING file.

Migrating a repository
======================

Sometimes special situations arise where you need to move all of your filesystem data from one repository to another.  Perhaps the internal fs database schema has changed in some way in a new release of Subversion, or perhaps you'd like to start using a different database ``back end''.

Either way, your data needs to be migrated to a new repository.  To do this, we have the svnadmin dump and svnadmin load commands.

svnadmin dump writes a stream of your repository's data to stdout:

     $ svnadmin dump myrepos > dumpfile
     * Dumped revision 0.
     * Dumped revision 1.
     * Dumped revision 2.
     ...

This stream describes every revision in your repository as a list of changes to nodes.  It's mostly human-readable text; but when a file's contents change, the entire fulltext is dumped into the stream.  If you have binary files or binary property-values in your repository, those parts of the stream may be unfriendly to human readers.

After dumping your data, you would then move the file to a different system (or somehow alter the environment to use a different version of svnadmin and/or libsvn_fs.so), and create a ``new''-style repository that has a new schema or DB back-end:

     $ svnadmin create newrepos

The svnadmin load command attempts to read a dumpstream from stdin, and effectively replays each commit:

     $ svnadmin load newrepos < dumpfile
     <<< Started new txn, based on original revision 1
          * adding path : A ... done.
          * adding path : A/B ... done.
     ...
     ------- Committed new rev 1 (loaded from original rev 1) >>>

     <<< Started new txn, based on original revision 2
          * editing path : A/mu ... done.
          * editing path : A/D/G/rho ... done.

     ------- Committed new rev 2 (loaded from original rev 2) >>>

Voila, your revisions have been recommitted into the new repository.

And because svnadmin uses standand input and output streams for the repository dump and load process, people who are feeling saucy with Unix can try things like this:

     $ svnadmin create newrepos
     $ svnadmin dump myrepos | svnadmin load newrepos

Partial dump/load
-----------------

You can also create a dumpfile that represents a specific range of revisions.  svnadmin dump takes optional starting and ending revisions to accomplish just that task.

     $ svnadmin dump myrepos 23 > rev-23.dumpfile
     $ svnadmin dump myrepos 100 200 > revs-100-200.dumpfile

Now, regardless of the range of revisions used when dumping the repository, the default behavior is for the first revision dumped to always be compared against revision 0, which is just the empty root directory /.  This means that the first revision in any dumpfile will always look like a gigantic list of ``added'' nodes.  We do this so that a file like revs-100-200.dumpfile can be directly loaded into an empty repository.

However, if you add the --incremental option when you dump your repository, this tells svnadmin to compare the first dumped revision against the previous revision in the repository, the same way it treats every other revision that gets dumped.  The benefit of this is that you can create several small dumpfiles that can be loaded in succession, instead of one large one, like so:

     $ svnadmin dump myrepos 0 1000 > dumpfile1
     $ svnadmin dump myrepos 1001 2000 --incremental > dumpfile2
     $ svnadmin dump myrepos 2001 3000 --incremental > dumpfile3

These dumpfiles could be loaded into a new repository with the following command sequence:

     $ svnadmin load newrepos < dumpfile1
     $ svnadmin load newrepos < dumpfile2
     $ svnadmin load newrepos < dumpfile3

Another neat trick you can perform with this --incremental option involves appending to an existing dumpfile a new range of revisions.  For example, you might have a post-commit hook that simply appends the repository dump of the single revision that triggered the hook.  Or you might have a script like the following that runs nightly to append dumpfile data for all the revisions that were added to the repository since the last time the script ran.

     #!/usr/bin/perl

     $repos_path  = '/path/to/repos';
     $dumpfile    = '/usr/backup/svn-dumpfile';
     $last_dumped = '/var/log/svn-last-dumped';

     # Figure out the starting revision (0 if we cannot read the last-dumped file,
     # else use the revision in that file incremented by 1).
     if (open LASTDUMPED, "$last_dumped")
     {
         $new_start = <LASTDUMPED>;
         chomp $new_start;
         $new_start++;
         close LASTDUMPED;
     }
     else
     {
         $new_start = 0;
     }

     # Query the youngest revision in the repos.
     $youngest = `svnadmin youngest $repos_path`;
     chomp $youngest;

     # Do the backup.
     `svnadmin dump $repos_path $new_start $youngest --incremental >> $dumpfile`;

     # Store a new last-dumped revision
     open LASTDUMPED, "> $last_dumped" or die;
     print LASTDUMPED "$youngest\n";
     close LASTDUMPED;

     # All done!

As you can see, the Subversion repository dumpfile format, and specifically svnadmin's use of that format, can be a valuable means by which to backup changes to your repository over time in case of a system crash or some other catastrophic event.

WebDAV
======

Subversion uses WebDAV (Distributed Authoring and Versioning) as its primary network protocol, and here we discuss what this means to you, both present and future.

WebDAV was designed to make the web into a read/write medium, instead of a read-only medium (as it mainly exists today.)  The theory is that directories and files can be shared over the web, using standardized extensions to HTTP.  RFC 2518 describes the WebDAV extensions to HTTP, and is available (along with a lot of other useful information) at http://www.webdav.org/.

Already, a number of operating system file-browsers are able to mount networked directories using WebDAV.  On Win32, the Windows Explorer can browse what it calls ``WebFolders'', just like any other share. Mac OS X also has this capability, as does the Nautilus browser for GNOME.

However, RFC 2518 doesn't fully implement the ``versioning'' aspect of WebDAV.  A separate committee has created RFC 3253, known as the DeltaV extensions to WebDAV, available at http://www.webdav.org/deltav/.   These extensions add version-control concepts to HTTP, and this is what Subversion uses.

It's important to understand that while Subversion uses DeltaV for communication, the Subversion client is not a general-purpose DeltaV client. In fact, it expects some custom features from the server. Further, the Subversion server is not a general-purpose DeltaV server. It implements a strict subset of the DeltaV specification. A WebDAV or DeltaV client may very well be able to interoperate with it, but only if that client operates within the narrow confines of those features the server has implemented. Future versions of Subversion will address more complete WebDAV interoperability.

At the moment, most DAV browsers and clients do not yet support DeltaV; this means that a Subversion repository can viewed or mounted only as a read-only resource.  (An HTTP ``PUT'' request is valid when sent to a WebDAV-only server, but a DeltaV server such as mod_dav_svn will not allow it.  The client must use special version-control methods to write to the server.)  And on the flip side, a Subversion client cannot checkout a working copy from a generic WebDAV server; it expects a specific subset of DeltaV features.

For a detailed description of Subversion's WebDAV implementation, see http://svn.collab.net/repos/svn-repos/trunk/www/webdav-usage.html.