Client Cookbook
***************

How to make a lovely gumbo with your Subversion client, in 11 easy steps.

This chapter goes into more of the gritty details of client commands. For a first overview of the client's CVS-like ``copy-modify-merge'' model of development, see Basics.

Before reading on, here is the most important piece of information you'll ever need when using Subversion: svn help.  The Subversion command-line client tries to be self-documenting; at any time, a quick svn help <subcommand> will describe the syntax, switches, and behavior of subcommand.

This chapter by no means covers every option to every client subcommand.  Instead, it's a conversational introduction to the most common tasks you'll encounter.  When in doubt, run svn help.

Checkout
========

Most of the time, you will start using a Subversion repository by doing a checkout of your project.  ``Checking out'' will provide you with a local copy of the HEAD (latest revision) of the Subversion repository that you checked out.

     $ svn co http://svn.collab.net/repos/svn/trunk
     A  trunk/subversion.dsw
     A  trunk/svn_check.dsp
     A  trunk/COMMITTERS
     A  trunk/configure.in
     A  trunk/IDEAS
     ...
     Checked out revision 2499.

Although the above example checks out the trunk directory, you can just as easily checkout any deep subdirectory of a repository by specifying the subdirectory in the checkout URL:

     $ svn co http://svn.collab.net/repos/svn/trunk/doc/handbook
     A  handbook/svn-handbook.texi
     A  handbook/getting_started.texi
     A  handbook/outline.txt
     A  handbook/license.texi
     A  handbook/repos_admin.texi
     A  handbook/client.texi
     Checked out revision 2499.

Since Subversion uses a ``copy-modify-merge'' model instead of ``lock-modify-unlock,'' you're now ready to start making changes to the files that you've checked out, known collectively as your working copy. You can even delete the entire working copy and forget about it entirely -- there's no need to notify the Subversion server unless you're ready to check in changes, a new file, or even a directory.

Every directory in a working copy contains an administrative area, a subdirectory named .svn.  Normal ls commands won't show this subdirectory, but it's vital.  Whatever you do, don't delete or change anything in the administrative area!  Subversion depends on it to manage your working copy.

You can run svn help checkout for command line options to checkout, although one option is very common and worth mentioning: you can specify a directory after your repository url.  This places your working copy into a new directory that you name.  For example:

     $ svn co http://svn.collab.net/repos/svn/trunk subv
     A  subv/subversion.dsw
     A  subv/svn_check.dsp
     A  subv/COMMITTERS
     A  subv/configure.in
     A  subv/IDEAS
     ...
     Checked out revision 2499.

Basic Work Cycle
================

Subversion has numerous features, options, bells and whistles, but on a day-to-day basis, odds are that you will only use a few of them. In this section we'll run through the most common things that you might find yourself doing with Subversion in the course of a day's work.

The typical work cycle looks like this:

  * Update your working copy

  * Make changes

  * Examine your changes

  * Merge others' changes

  * Commit your changes

Update your working copy (svn up)
---------------------------------

When working on a project with a team, you'll want to update your working copy: that is, receive any changes from other developers on the project.  svn update brings your working copy in-sync with the latest revision in the repository.

     $ svn up
     U  ./foo.c
     U  ./bar.c
     Updated to revision 2.

In this case, someone else checked in modifications to both foo.c and bar.c since the last time you updated, and Subversion has updated your working copy to include those changes.

Let's examine the output of svn update a bit more.  When the server sends changes to your working copy, a letter code is displayed next to each item:

U  foo
     File foo was (U)pdated (received changes from the server.)

A  foo
     File or directory foo was (A)dded to your working copy.

D  foo
     File or directory foo was (D)eleted from your working copy.

R  foo
     File or directory foo was (R)eplaced in your working copy; that is, foo was deleted, and a new item with the same name was added.  While they may have the same name, the repository considers them to be distinct objects with distinct histories.

G  foo
     File foo received new changes, but also had changes of your own to begin with.  The changes did not intersect, however, so Subversion has mer(G)ed the repository's changes into the file without a problem.

C  foo
     File foo received (C)onflicting changes from the server.  The changes from the server directly overlap your own changes to the file. No need to panic, though.  This overlap needs to be resolved by a human (you); we discuss this situation further down.

Make changes (svn add, svn rm, svn cp, svn mv)
----------------------------------------------

Now you can to get to work and make changes in your working copy. It's usually most convenient to create a ``task'' for yourself, such as writing a new feature, fixing a bug, etc.

What kinds of changes can you make to your working copy tree?

File changes
     This is the simplest sort of change.  Unlike other revision control systems, you don't need to tell Subversion that you intend to change a file; just do it.  Later on, Subversion will be able to automatically detect which files have been changed.

Tree changes
     You can ask Subversion to ``mark'' files and directories for scheduled removal or addition.  Of course, no additions or removals will happen in the repository until you decide to commit.

To make file changes, just use your normal editor, word processor, or whatever.   A file needn't be in text-format; binary files work just fine.

There are at least four Subversion subcommands for making tree changes.  Detailed help can be found with svn help, but here is an overview:

svn add foo
     Schedule foo to be added to the repository.  When you next commit, foo will become a permanent child of its parent directory.  Note that if foo is a directory, only the directory itself will be scheduled for addition.  If you want to add its contents as well, pass the --recursive switch.

svn rm foo
     Schedule foo to be removed from the repository.  If foo is a file, it immediately vanishes from the working copy -- but it can be recovered with svn revert (see below).  If foo is a directory, it is merely scheduled for deletion.  After you commit, foo will no longer exist in the working copy or repository.

svn cp foo bar
     Create new item bar as a duplicate of foo.  bar is automatically scheduled for addition.  When bar is added to the repository on the next commit, it's copy-history is recorded (as having originally come from foo.)

svn mv foo bar
     This command is exactly the same as running svn cp foo bar; svn rm foo.  That is, bar is scheduled for addition as a copy of foo, and foo is scheduled for removal.

Let's ammend our original statement: there are some use-cases that immediately commit tree changes to the repository.  This usually happens when a subcommand is operating directly on a URL, rather than on a working-copy path. (In particular, specific uses of svn mkdir, svn cp, svn mv, and svn rm can work with URLs.  See svn help on these commands for more details.)

Examine your changes (svn status, svn diff, svn revert)
-------------------------------------------------------

So now you've finished your changes... or so you think.  But what exactly did you change?  How can you review them?

Subversion has been optimized to help you with this task, and is able to do many things without talking to the repository or network at all. In particular, your working copy contains a secret cached ``pristine'' copy of each file within the .svn area.  Because of this, it can quickly show you how your working files have changed, or even allow you to undo your changes.

The svn status command is your friend; become intimate with it.  You'll probably use svn status more than any other command.

If you run svn status at the top of your working copy with no arguments, it will detect all file and tree changes you've made.  This example is designed to show all the different status codes that svn status can return.  The text in [] is not printed by svn status.

     $ svn status
     _ L    ./abc.c               [svn has a lock in its .svn directory for abc.c]
     M      ./bar.c               [the content in bar.c has local modifications]
     _M     ./baz.c               [baz.c has property but no content modifications]
     ?      ./foo.o               [svn doesn't manage foo.o]
     !      ./foo.c               [svn knows foo.c but a non-svn program deleted it]
     ~      ./qux                 [versioned as dir, but is file, or vice versa]
     A  +   ./moved_dir           [added with history of where it came from]
     M  +   ./moved_dir/README    [added with history and has local modifications]
     D      ./stuff/fish.c        [this file is scheduled for deletion]
     A      ./stuff/things/bloo.h [this file is scheduled for addition]

In this output format svn status prints four columns of characters followed by several whitespace characters followed by a file or directory name.  The first column tells the status of a file or directory and/or its contents.  The codes printed here are

_      file_or_dir
     The file or directory has not been added or deleted, nor has file_or_dir's contents been modified if it is a file.

A      file_or_dir
     The file or directory file_or_dir has been scheduled for addition into the repository.

M      file
     The contents of file file have been modified.

D      file_or_dir
     The file or directory file_or_dir has been scheduled for deletion from the repository.

?      file_or_dir
     The file or directory file_or_dir indicates that this file or directory is not under revision control.  You can silence the question marks by either passing the --quiet (-q) option to svn status, or by setting the svn:ignore property on the parent directory, see Properties.

!      file_or_dir
     The file or directory file_or_dir is under revision control but the working copy is missing.  This happens if the file or directory is removed using a non-Subversion command.  A quick svn up or svn revert file_or_dir will restore the missing file from its cached pristine copy.

~      file_or_dir
     The file or directory file_or_dir is under revision control as one kind of object, but what's actually on disk is some other kind. For example, Subversion might be expecting a file, but the user has removed the file and created a directory in its place, without using the svn rm nor svn add commands.

The second column tells the status of a file's or directory's properties, see Properties.  If a M appears in the second column, then the properties have been modified, otherwise a whitespace will be printed.  If only the properties of a file or directory are modified, then you will get _M printed in the first and second columns.  The first _ is just printed to make it clear to the eye that the properties are modified and not the contents.

The third column will only show whitespace or a L which means that svn has locked item locked in the .svn working area.  You will see L if you run svn status in a directory you are currently running svn commit when you are editing the log message.  If there are no running svn's, then presumably svn was forcibly quit or died and the lock needs to be cleaned up by running svn cleanup.  Locks typically appear if a Subversion command is interrupted before completion.

The forth column will only show whitespace or a + which means that the file or directory is scheduled to be added or modified with additional attached history.  This typically happens when you svn mv or svn cp a file or directory.  If you see A   +, this means the item is scheduled for addition-with-history.  It could be a file, or the root of a copied directory.  _   + means the item is part of a subtree scheduled for addition-with-history, i.e. some parent got copied, and it's just coming along for the ride.  M + means the item is part of a subtree scheduled for addition-with-history, and it has local mods.  When you commit, first some parent will be added-with-history (copied), which means this file will automatically exist in the copy.  Then the local mods will be further uploaded into the copy.

By default, svn status ignores files matching the regular expressions *.o, *.lo, *.la, #*#, *.rej, *~, and .#*.  If you want additional files ignored, set the svn:ignore property on the parent directory.  If you want to see the status of all the files in the repository irrespective of svn status and svn:ignore's regular expressions, then use the --no-ignore command line option.

If a single path is passed to the command, it will tell you about it:

     $ svn status stuff/fish.c
     D      stuff/fish.c

This command also has a --verbose (-v) mode, which will show you the status of every item in your working copy:

     $ svn status -v
     M               44        23    joe       ./README
     _               44        30    frank     ./INSTALL
     M               44        20    frank     ./bar.c
     _               44        18    joe       ./stuff
     _               44        35    mary      ./stuff/trout.c
     D               44        19    frank     ./stuff/fish.c
     _               44        21    mary      ./stuff/things
     A                0         ?     ?        ./stuff/things/bloo.h
     _               44        36    joe       ./stuff/things/gloo.c

This is the ``long form'' output of svn status.  The first column is still the same.  The second column shows the working-revision of the item.  The third and fourth column show the revision in which the item last changed, and who changed it.

Finally, there is a --show-updates (-u) switch, which contacts the repository and adds information about things that are out-of-date:

     $ svn status -u -v
     M      *        44        23    joe       ./README
     M               44        20    frank     ./bar.c
     _      *        44        35    mary      ./stuff/trout.c
     D               44        19    frank     ./stuff/fish.c
     A                0         ?     ?        ./stuff/things/bloo.h

Notice the two asterisks: if you were to run svn up at this point, you would receive changes to README and trout.c. Hmmm, better be careful.  You'll need to absorb those server-changes on README before you commit, lest the repository reject your commit for being out-of-date.  (More on this subject below.)

Another way to examine your changes is with the svn diff command.  You can find out exactly how you've modified things by running svn diff with no arguments, which prints out file changes in unified diff format:

     $ svn diff
     Index: ./bar.c
     ===================================================================
     --- ./bar.c
     +++ ./bar.c	Mon Jul 15 17:58:18 2002
     @ -1,7 +1,12 @
     +#include <sys/types.h>
     +#include <sys/stat.h>
     +#include <unistd.h>
     +
     +#include <stdio.h>

      int main(void) {
     -  printf("Sixty-four slices of American Cheese...\n");
     +  printf("Sixty-five slices of American Cheese...\n");
        return 0;
      }

     Index: ./README
     ===================================================================
     --- ./README
     +++ ./README	Mon Jul 15 17:58:18 2002
     @ -193,3 +193,4 @
     +Note to self:  pick up laundry.

     Index: ./stuff/fish.c
     ===================================================================
     --- ./stuff/fish.c
     +++ ./stuff/fish.c  Mon Jul 15 17:58:18 2002
     -Welcome to the file known as 'fish'.
     -Information on fish will be here soon.

     Index: ./stuff/things/bloo.h
     ===================================================================
     --- ./stuff/things/bloo.h
     +++ ./stuff/things/bloo.h  Mon Jul 15 17:58:18 2002
     +Here is a new file to describe
     +things about bloo.

The svn diff command produces this output by comparing your working files against the cached ``pristine'' copies within the .svn area.  Files scheduled for addition are displayed as all added-text, and files scheduled for deletion are displayed as all deleted text.

Now suppose you see this output, and realize that your changes to README are a mistake; perhaps you accidentally typed that text into the wrong file in your editor.

The svn revert command is exactly for this purpose.  It throws away all changes to your file:

     $ svn revert README
     Reverted ./README

The file is reverted to its pre-modified state by overwriting it with the cached ``pristine'' copy.  But also note that svn revert can undo any scheduled operations -- in case you decide that you don't want to add a new file after all, or that you don't want to remove something.

A final reminder: all three of these commands (svn status, svn diff, svn revert) can be used without any network access (except for the -u switch to status).  This makes it easy to manage your changes-in-progress while traveling on an airplane, etc.

Merge others' changes (conflict resolution)
-------------------------------------------

We've already seen how svn status -u can predict conflicts. Suppose you run svn update and some interesting things occur:

     $ svn up
     U  ./INSTALL
     G  ./README
     C  ./bar.c

The U and G codes are nothing to sweat about; those files cleanly absorbed changes from the repository.  The G stands for mer(G)ed, which means that the file had local changes to begin with, but the repository changes didn't overlap in any way.

But the C stands for conflict.  This means that the server's changes overlapped with your own, and now you have to manually choose between them.

Whenever a conflict occurs:

  * A C is printed during the update, and Subversion remembers that the file is ``conflicted.''

  * Conflict markers are placed into the file, to visibly demonstrate the overlapping areas.

  * Three fulltext files are created; these files are the original three files that could not be merged together.  Given the a file named ORIG_NAME, the three new fulltext files have filenames of the form ORIG_NAME.*.mine, ORIG_NAME.*.rOLD_REV and ORIG_NAME.*.rNEW_REV.  Here * represents some random digits that SVN chooses, ORIG_NAME.*.mine is a copy of the file that existed in your local working copy before the merge and without any conflict markers, ORIG_NAME.*.rOLD_REV is the original version of ORIG_NAME at the revision that your working copy is based off of with OLD_REV replaced with the specific revision number, and ORIG_NAME.*.rNEW_REV is the original version of ORIG_NAME that the file is being merged to, again with NEW_REV replaced with the specific revision number.

At this point, Subversion will not allow you to commit the file until the three temporary files are removed.

If you get a conflict, you need to either (1) hand-merge the conflicted text (by examining and editing the conflict markers within the file), (2) copy one of the tmpfiles on top of your working file, or (3) run svn revert to toss all of your changes.

Once you've resolved the conflict, you need to let Subversion know by removing the three tmpfiles.  (The svn resolve command, by the way, is a shortcut that does nothing but automatically remove the three tmpfiles for you.)  When the tmpfiles are gone, Subversion no longer considers the file to be in a state of conflict anymore.

Commit your changes
-------------------

Finally!  Your edits are finished, you've merged all updates from the server, and you're ready to commit your changes.

The svn commit command sends all (or some) of your changes to the repository.  When you commit a change, you need to supply a log message, describing your change.  Your log message will be permanently attached to the new revision you create.

     $ svn commit -m "Added include lines and corrected # of cheese slices."
     Sending        bar.c
     Transmitting file data .
     Committed revision 3.
     $

Another way to specify a log message is to place it in a file, and pass the filename with the -F switch.  If you fail to specify either the -m or -F switch, then Subversion will automatically launch your favorite $EDITOR for composing a log message.

The repository doesn't know or care if your changes make any sense as a whole; it only checks to make sure that nobody else has changed any of the same files that you did when you weren't looking.  If somebody has done that, the entire commit will fail with a message informing that one or more of your files is out-of-date.  At this point, you need to run svn update again, deal with any merges or conflicts that result, and attempt your commit again.

That covers the most basic work cycle for using Subversion. Run svn help COMMANDNAME for help on any of the commands covered in this section.

History
=======

As we mentioned earlier, the repository is like a time machine.  It remembers every revision ever committed, and allows you to explore this history.

There are two commands that mine historical data from the repository. svn log shows you broad information: log messages attached to revisions, and which paths changed in each revision.  svn diff, on the other hand, can show you the specific details of how a file changed over time.

svn log
-------

To find out information about the history of a file or directory, you use the svn log command. svn log will tell you who made changes to a file and at what revision, the time and date of that revision, and the log message that accompanied the commit.

     $ svn log
     ------------------------------------------------------------------------
     rev 3:  fitz | Mon, 15 Jul 2002 18:03:46 -0500 | 1 line

     Added include lines and corrected # of cheese slices.
     ------------------------------------------------------------------------
     rev 2:  someguy | Mon, 15 Jul 2002 17:47:57 -0500 | 1 line

     Added main() methods.
     ------------------------------------------------------------------------
     rev 1:  fitz | Mon, 15 Jul 2002 17:40:08 -0500 | 2 lines

     Initial import
     ------------------------------------------------------------------------

Note that the log messages are printed in reverse chronological order by default.  If you wish to see a different range of revisions in a particular order, or just a single revision, pass the --revision (-r) switch:

     $ svn log -r 5:19
     ...  # shows logs 5 through 19 in chronological order
     $ svn log -r 19:5
     ...  # shows logs 5 through 19 in reverse order
     $ svn log -r 8
     ...

You can also examine the log history on a single file or directory. The commands

     $ svn log foo.c
     ...
     $ svn log http://foo.com/svn/trunk/code/foo.c
     ...

will display log messages only for those revisions in which the working file (or URL) changed.

And while we're on the subject, svn log also takes a --verbose (-v) option too; it includes a list of changed-paths in each revision:

     $ svn log -r 8 -v
     ------------------------------------------------------------------------
     rev 8:  jrandom | 2002-07-14 08:15:29 -0500 | 1 line
     Changed paths:
        U /trunk/code/foo.c
        U /trunk/code/bar.h
        A /trunk/code/doc/README

     Frozzled the sub-space winch.

     ------------------------------------------------------------------------

svn diff
--------

We've already seen svn diff in an previous section; it displays file differences in unified diff format.  Earlier, it was used to show the local modifications made to our working copy.

In fact, it turns out that there are three distinct uses of svn diff:

Examining local changes
.......................

Invoking svn diff with no switches will compare your working files to the cached ``pristine'' copies in the .svn area:

     $ svn diff foo
     Index: ./foo
     ===================================================================
     --- ./foo
     +++ ./foo	Tue Jul 16 15:19:53 2002
     @ -1 +1,2 @
      An early version of the file
     +...extra edits

Comparing working copy to repository
....................................

If a single --revision (-r) number is passed, then your working files are compared to a particular revision in the repository.

     $ svn diff -r 3 foo
     Index: ./foo
     ===================================================================
     --- ./foo
     +++ ./foo	Tue Jul 16 15:19:53 2002
     @ -1,2 +1,2 @
      An early version of the file
     -Second version of the file
     +...extra edits

Comparing repository to repository
..................................

If two revision numbers are passed via -r, then the two revisions are directly compared.

     $ svn diff -r 2:3 foo

     Index: ./foo
     ===================================================================
     --- ./foo
     +++ tmp.280.00001	Tue Jul 16 15:22:19 2002
     @ -1 +1,2 @
      An early version of the file
     +Second version of the file

If you read the help for svn diff, you'll discover that you can supply URLs instead of working copy paths as well.  This is especially useful if you wish to inspect changes when you have no working copy available:

     $ svn diff -r 23:24 http://foo.com/some/project
     ...

Branches and Tags
=================

Branches and tags are general concepts common to almost all revision control systems.  If you're not familiar with these ideas, you can find a good introductory explanation in Karl Fogel's free CVS book: http://cvsbook.red-bean.com/cvsbook.html#Branching_Basics

At this point, you should understand how each commit creates an entire new filesystem tree in the repository.  (If not, read about revisions, see Transactions and Revision Numbers, or see Revision numbers are different now.)

As you may have suspected, the filesystem doesn't grow 652 new inodes each time a new revision is created.  Instead, each new tree is mostly made of pointers to already-existing nodes; new nodes are created only for changed items, and all the rest of the revision tree is ``shared storage'' with other revision trees.  This technique demonstrates how the filesystem is able to make ``cheap copies'' of things.  These cheap copies are nothing more than directory entries that point to existing nodes.  And this is the basis of tags and branches.

Branching with svn cp
---------------------

Suppose we have a repository whose head tree is revision 82.  In this repository is a subdirectory mooIRC that contains a software project that is ready to be tagged.  How do we tag it?  Very simple: make a ``cheap'' copy of this directory.  In other words, create a new directory entry (somewhere else in the filesystem) that points to this specific node that represents directory mooIRC in revision 82.  Of course, you can name the new directory entry whatever you want -- probably a tag-name like mooIRC-beta.

The easiest way to make this copy is with svn cp, which, incidentally, can operate entirely on URLs, so that the copy happens only on the server-side:

     $ svn cp http://foo.com/repos/mooIRC \
              http://foo.com/repos/mooIRC-beta
     Committed revision 83.

Now, as long as you never touch the contents of the directory mooIRC-beta, that entry will forever point to a node that looks the way mooIRC did at a specific moment in time (however it looked in revision 82).  And that's exactly what a tag is.

But suppose mooIRC-beta isn't sacred, and instead you decide to start making commits to it.  And suppose you also continue to make commits in the original mooIRC directory.  Then you have two directories that started out looking identical -- their common ancestor was mooIRC in revision 82 -- but now have diverged their contents over time.  In other words, they represent different branches of the project.

It's very important to note that the Subversion filesystem is not aware of ``tags'' or ``branches.''  It's only aware of directories, and all directories are equal.  The tag and branch concepts are purely human meanings attached to particular directories.

For this reason, it's up to users (and the Subversion repository administrator) to choose sane policies that help elucidate these labels.  For example, here's a good way to lay out your repository:

        /
        /projectA
        /projectA/trunk/
        /projectA/branches/
        /projectA/tags/
        /projectB
        /projectB/trunk/
        /projectB/branches/
        /projectB/tags/

Each time /projectA/trunk reaches a taggable state, make a copy of the directory somewhere in /projectA/tags/, and set the copy to read-only.  Use the same procedure to create a branch in /projectA/branches/.

An alternate way to lay out a repository:

        /
        /trunk
        /trunk/projectA
        /trunk/projectB
        /branches
        /branches/projectA
        /branches/projectB
        /tags
        /tags/projectA
        /tags/projectB

Or, of course, you could just place each project into a dedicated repository.  It's up to you.  For examples on how to create a repository with one of these structures, see Creating a repository.

Switching to a branch with svn switch
-------------------------------------

The svn switch command allows you to ``move'' some or all of your working copy to a branch or tag.  For example, suppose I have a working copy of mooIRC, and I'd like to work on some subsystem as it appears in a subdirectory of mooIRC-beta.  At the same time, I want the rest my working copy to remain on the original mooIRC branch.  To do this, I switch the appropriate subdir to the new branch location:

     $ svn switch http://foo.com/repos/mooIRC-beta/subsystems/renderer \
                  mooIRC/subsystems/renderer

     U  mooIRC/subsystems/renderer/foo.c
     U  mooIRC/subsystems/renderer/bar.h
     U  mooIRC/subsystems/renderer/baz.c

Now my working copy of the renderer subdirectory represents a different location on the server.

Really, svn switch is just a fancier version of svn update.  Whereas svn update has the ability to move your working copy through time (either by updating to the latest revision, or by updating to a specific revision given with -r), svn switch is able to move your working copy through time and space.

If your working copy contains a number of ``switched'' subtrees from different repository locations, it continues to function as normal. When you update, you'll receive patches to each subtree as appropriate.  When you commit, your local changes will still be applied as a single, atomic change to the repository.

Moving changes with svn merge
-----------------------------

Suppose a team of programmers working on the mooIRC-beta branch have fixed a critical bug, and the team working on the original mooIRC branch would like to apply that change as well.

The svn merge command is the answer.  You can think of svn merge as a special kind of svn diff; only instead of displaying unified diffs to the screen, it applies the differences to your working copy as if they were local changes.

For example, suppose the bug fix happened in a commit to the mooIRC-beta branch in revision 102.

     $ svn diff -r 101:102 http://foo.com/repos/mooIRC-beta

     ...   # diffs sent to screen

     $ svn merge -r 101:102 http://foo.com/repos/mooIRC-beta mooIRC
     U   mooIRC/glorb.c
     U   mooIRC/src/floo.h

While the output of svn merge looks similar to svn update or svn switch, it is in fact only applying temporary changes to the working files.  Once the differences are applied as local changes, you can examine them as usual with svn diff, svn status, or undo them with svn revert as usual.  If the changes are acceptable, you can commit them.

Rolling back a change with svn merge
------------------------------------

Another common use for svn merge is for rolling back a change that has been committed.  Say you commit some changes in revision 10, and later decide that they were a mistake.  You can easily revert the tree to the state it was in at revision 9 with an svn merge command.

     $ svn commit -m "change some stuff"
     Sending        bar.c
     Sending        foo.c
     Transmitting file data ..
     Committed revision 10.
     $

     ... # developer continues on and realizes he made a mistake

     $ svn merge -r 10:9 .
     U ./bar.c
     U ./foo.c
     $ svn commit -m "oops, reverting revision 10"
     Sending        bar.c
     Sending        foo.c
     Transmitting file data ..
     Committed revision 11.

If you aren't rolling back the changes to your current directory (say you want to roll back one specific file, or all the files in one specific subdirectory), then the syntax is slightly different, as you have to tell svn merge where it should merge the changes into.

     $ svn merge -r 10:9 baz/ baz/
     U ./baz/bar.c
     U ./baz/foo.c
     $ svn commit -m "reverting revision 10's changes in baz/"
     Sending        baz/bar.c
     Sending        baz/foo.c
     Transmitting file data ..
     Committed revision 12.
     $

     ... # developer continues on and later makes another mistake

     $ svn merge -r 13:12 baz/foo.c baz/foo.c
     U ./baz/foo.c
     $ svn commit -m "reverting revision 12's change to foo.c"
     Sending        baz/foo.c
     Transmitting file data .
     Committed revision 15.

Keep in mind that rolling back a change like this is just like any other svn merge operation, so you should use svn status and svn diff to confirm that your work is in the state you want it to be in, and then use svn commit to send the final version to the repository.

Vendor branches
---------------

Sometimes you want to manage modified third-party source code inside your Subversion repository, while still tracking upstream releases.  In CVS this would have been called a ``vendor branch''.  Subversion doesn't have a formal ``vendor branch'', but it is sufficiently flexible that you can still do much the same thing.

The general procedure goes like this.  You create a top level directory (we'll use /vendor) to hold the vendor branches.  Then you import the third party code into a subdirectory of /vendor, and copy it into /trunk where you make your local changes.  With each new release of the code you are tracking you bring it into the vendor branch and merge the changes into /trunk, resolving whatever conflicts occur between your local changes and the upstream changes.

Let's try and make this a bit clearer with an example.

First, the initial import.

     $ svn mkdir http://svnhost/repos/vendor/foobar
     $ svn import http://svnhost/repos/vendor/foobar ~/foobar-1.0 current

Now we've got the current version of the foobar project in /vendor/foobar/current.  We make another copy of it so we can always refer to that version, and then copy it into the trunk so you can work on it.

     $ svn copy http://svnhost/repos/vendor/foobar/current    \
                http://svnhost/repos/vendor/foobar/foobar-1.0 \
                -m `tagging foobar-1.0'
     $ svn copy http://svnhost/repos/vendor/foobar/foobar-1.0 \
                http://svnhost/repos/trunk/foobar             \
                -m `bringing foobar-1.0 into trunk'

Now you just check out a copy of /trunk/foobar and get to work!

Later on, the developers at FooBar Widgets, Inc release a new version of their code, so you want to update the version of the code you're using. First, you check out the /vendor/foobar/current directory, then copy the new release over that working copy, handle any renames, additions or removals manually, and then commit.

     $ svn co http://svnhost/repos/vendor/foobar/current ~/current
     $ cd ~/foobar-1.1
     $ tar -cf - . | (cd ~/current ; tar -xf -)
     $ cd ~/current
     $ mv foobar.c main.c
     $ svn mv main.c foobar.c
     $ svn rm dead.c
     $ svn add doc
     $ svn add doc/*
     $ svn commit -m `importing foobar 1.1 on vendor branch'

Whoa, that was complicated. Don't worry, most cases are far simpler.

What happened? foobar 1.0 had a file called main.c.  This file was renamed to foobar.c in 1.1.  So your working-copy had the old main.c which svn knew about, and the new foobar.c which svn did not know about.  You rename foobar.c to main.c and svn mv it back to the new name.  This way, svn will know that foobar.c is a descendant of main.c.  dead.c has vanished in 1.1, and they have finally written some documentation, so you add that.

Next you copy /vendor/foobar/current to /vendor/foobar/foobar-1.1 so you can always refer back to version 1.1, like this.

     $ svn copy http://svnhost/repos/vendor/foobar/current    \
                http://svnhost/repos/vendor/foobar/foobar-1.1 \
                -m `tagging foobar-1.1'

Now that you have a pristine copy of foobar 1.1 in /vendor, you just have to merge their changes into /trunk and you're done. That looks like this.

     $ svn co http://svnhost/repos/trunk/foobar ~/foobar
     $ cd ~/foobar
     $ svn merge http://svnhost/repos/vendor/foobar/foobar-1.0 \
                 http://svnhost/repos/vendor/foobar/foobar-1.1
     $
     ... # resolve all the conflicts between their changes and your changes
     $ svn commit -m `merging foobar 1.1 into trunk'

There, you're done.  You now have a copy of foobar 1.1 with all your local changes merged into it in your tree.

Vendor branches that have more than several deletes, additions and moves can use the svn_load_dirs.pl script that comes with the Subversion distribution.  This script automates the above importing steps to make sure that mistakes are minimized.  You still need to use the merge commands to merge the new versions of foobar into your own local copy containing your local modifications.

This script has the following enhancements over svn import:

  * Can be run at any point in time to bring an existing directory in the repository to exactly match an external directory.  This scripts run all the svn add, svn rm and optionally any svn mv commands as necessary.

  * Optionally tag the newly imported directory.

  * Optionally add arbitrary properties to files and directories that match a regular expression.

This script takes care of complications where Subversion requires a commit before renaming a file or directory twice, such as if you had a vendor branch that renamed foobar-1.1/docs/doc.ps to foobar-1.2/documents/doc-1.2.ps.  Here, you would rename docs to documents, perform a commit, then rename doc.ps to doc-1.2.ps.  You could not do the two renames without the commit, because doc.ps was already moved once from docs/doc.ps to documents/doc.ps.

This script always compares the directory being imported to what currently exists in the Subversion repository and takes the necessary steps to add, delete and rename files and directories to make the subversion repository match the imported directory.  As such, it can be used on an empty subversion directory for the first import or for any following imports to upgrade a vendor branch.

For the first foobar-1.0 release located in ~/foobar-1.0:

     $ svn_load_dirs.pl -t foobar-1.0                      \
                        http://svnhost/repos/vendor/foobar \
                        current                            \
                        ~/foobar-1.0

svn_load_dirs.pl takes three mandatory arguments.  The first argument, http://svnhost/repos/vendor/foobar, is the URL to the base Subversion directory to work in.  In this case, we're working in the vendor/foobar part of the Subversion repository.  The next argument, current, is relative to the first and is the directory where the current import will take place, in this case http://svnhost/repos/vendor/foobar/current.  The last argument, ~/foobar-1.0, is the directory to import.  Finally, the optional -t command line option is also relative to http://svnhost/repos/vendor/foobar and tells svn_load_dirs.pl to create a tag of the imported directory in http://svnhost/repos/vendor/foobar/foobar-1.0.

The import of foobar-1.1 would be taken care of in the same way:

     $ svn_load_dirs.pl -t foobar-1.1                      \
                        http://svnhost/repos/vendor/foobar \
                        current                            \
                        ~/foobar-1.1

The script looks in your current http://svnhost/repos/vendor/foobar/current directory and sees what changes need to take place for it to match ~/foobar-1.1. The script is kind enough to notice that there are files and directories that exist in 1.0 and not in 1.1 and asks if you want to perform any renames.  At this point, you can indicate that main.c was renamed to foobar.c and then indicate that no further renames have taken place.

The script will then delete dead.c and add doc and doc/* to the Subversion repository and finally create a tag foobar-1.1 in http://svnhost/repos/vendor/foobar/foobar-1.1.

The script also accepts a separate configuration file for applying properties to specific files and directories matching a regular expression that are added to the repository.  This script will not modify properties of already existing files or directories in the repository.  This configuration file is specified to svn_load_dirs.pl using the -p command line option. The format of the file is either two or four columns.

regular_expression  control  property_name  property_value

The regular_expression is a Perl style regular expression.  The control column must either be set to break or cont. It is used to tell svn_load_dirs.pl if the following lines in the configuration file should be examined for a match or if all matching should stop.  If control is set to break, then no more lines from the configuration file will be matched.  If control is set to cont, which is short for continue, then more comparisons will be made.  Multiple properties can be set for one file or directory this way.  The last two columns, property_name and property_value are optional and are applied to matching files and directories.

If you have whitespace in any of the regular_expression, property_name or property_value columns, you must surround the value with either a single or double quote.  You can protect single or double quotes with a \ character.  The \ character is removed by this script only for whitespace or quote characters, so you do not need to protect any other characters, beyond what you would normally protect for the regular expression.

This sample configuration file was used to load on a Unix box a number of Zip files containing Windows files with CRLF end of lines.

        \.doc$              break   svn:mime-type   application/msword
        \.ds(p|w)$          break   svn:eol-style   CRLF
        \.ilk$              break   svn:eol-style   CRLF
        \.ncb$              break   svn:eol-style   CRLF
        \.opt$              break   svn:eol-style   CRLF
        \.exe$              break   svn:mime-type   application/octet-stream
        dos2unix-eol\.sh$   break
        .*                  break   svn:eol-style   native

In this example, all the files should be converted to the native end of line style, which the last line of the configuration handles.  The exception is dos2unix-eol.sh, which contains embedded CR's used to find and replace Windows CRLF end of line characters with Unix's LF characters.  Since svn and svn_load_dirs.pl convert all CR, CRLF and LF's to the native end of line style when svn:eol-style is set to native, this file should be left untouched.  Hence, the break with no property settings.

The Windows Visual C++ and Visual Studio files (*.dsp, *.dsw, etc.) should retain their CRLF line endings on any operating system and any *.doc files are always treated as binary files, hence the svn:mime-type setting of application/msword.

Removing a branch or tag with svn rm
------------------------------------

The svn rm command can operate on URLs.  A file or directory can be ``remotely'' deleted from the repository, with no working copy present:

     $ svn rm http://foo.com/repos/tags/mooIRC-bad-tag -m "deleting bad tag"
     Committed revision 1023.

Of course, this is still a form of immediate commit, so some kind of log message is still required.

Enough said!

Properties
==========

Subversion allows you to attach arbitrary ``metadata'' to files and directories.  We refer to this data as properties, and they can be thought of as collections of name/value pairs (hash-tables) attached to each item in your working copy.

To set or get a property on a file or directory, use the svn propset and svn propget commands.  To list all properties attached to an item, use svn proplist.  To delete a property, use svn propdel.

     $ svn propset color green foo.c
     property `color' set on 'foo.c'

     $ svn propget color foo.c
     green

     $ svn propset height "5 feet" foo.c
     property `height' set on 'foo.c'

     $ svn proplist foo.c
     Properties on 'foo.c':
       height
       color

     $ svn proplist foo.c --verbose
     Properties on 'foo.c':
       height : 5 feet
       color : green

     $ svn propdel color foo.c
     property `color' deleted from 'foo.c'

Properties are versioned, just like file contents.  This means that new properties can be merged into your working files, and can sometimes come into conflict too.  Property values need not be text, either.  For example, you could attach a binary property-value by using the -F switch:

     $ svn propset x-face -F joeface.jpg foo.c
     property `x-face' set on 'foo.c'

Subversion also provides a great convenience method for editing existing properties: svn propedit. When you invoke it, Subversion will open the value of the property in question in your favorite editor (or at least the editor that you've defined as $EDITOR in your shell), and you can edit the value just as you would edit any text file. This is exceptionally convenient for properties that are a newline-separated array of values. (See below.)

Property changes are still considered ``local modifications'', and aren't permanent until you commit.  Like textual changes, property changes can be seen by svn diff, svn status, and reverted altogether with svn revert:

     $ svn diff
     Property changes on: foo.c
     ___________________________________________________________________
     Name: color
        + green

     $ svn status
     _M   foo.c

Notice that a 2nd column has appeared in the status output; the leading underscore indicates that you've not made any textual changes, but the M means you've modified the properties.  svn status tries to hide the 2nd ``property'' column when an item has no properties at all; this was a design choice, to ease new users into the concept.  When properties are created, edited, or updated on an item, that 2nd column appears forever after.

Also: don't worry about the non-standard way that Subversion currently displays property differences.  You can still run svn diff and redirect the output to create a usable patch file.  The patch program will ignore property patches; as a rule, it ignores any noise it can't understand.  (In future versions of Subversion, though, we may start using a new patch format that describes property changes and file copies/renames.)

Special properties
------------------

Subversion has no particular policy regarding properties; they can be used for any purpose.  The only restriction is that Subversion has reserved the svn: name prefix for itself.  A number of special ``magic'' properties begin with this prefix.  We'll cover these features here.

svn:executable
..............

This is a file-only property, and can be set to any value.  Its mere existence causes a file's permissions to be executable.

svn:mime-type
.............

At the present time, Subversion examines the svn:mime-type property to decide if a file is text or binary.  If the file has no svn:mime-type property, or if the property's value matches text/*, then Subversion assumes it is a text file.  If the file has the svn:mime-type property set to anything other than text/*, it assumes the file is binary.

If Subversion believes that the file is binary, it will not attempt to perform contextual merges during updates.  Instead, Subversion creates two files side-by-side in your working copy; the one containing your local modifications is renamed with an .orig extension.

Subversion also helps users by running a binary-detection algorithm in the svn import and svn add subcommands.  These subcommands try to make a good guess at a file's binary-ness, and then (possibly) set a svn:mime-type property of application/octet-stream on the file being added.  (If Subversion guesses wrong, you can always remove or hand-edit the property.)

Finally, if the svn:mime-type property is set, then mod_dav_svn will use it to fill in the Content-type: header when responding to an http GET request.  This makes files display more nicely when perusing a repository with a web browser.

svn:ignore
..........

If you attach this property to a directory, it causes certain file patterns within the directory to be ignored by svn status. For example, suppose I don't want to see object files or backup files in my status listing:

     $ svn status
     M  ./foo.c
     ?  ./foo.o
     ?  ./foo.c~

Using svn propedit, I would set the value of svn:ignore to a newline-delimited list of patterns:

     $ svn propget svn:ignore .
     *.o
     *~

svn:keywords
............

Subversion has the ability to substitute useful strings into special ``keywords'' within text files.  For example, if I placed this text into a file:

     Here is the latest report from the front lines.
     $LastChangedDate$
     Cumulus clouds are appearing more frequently as summer approaches.

Subversion is able substitute the $LastChangedDate$ string with the actual date in which this file last changed.  The keyword string is not removed in the replacement, just the specific information is placed after the keyword string:

     Here is the latest report from the front lines.
     $LastChangedDate: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $
     Cumulus clouds are appearing more frequently as summer approaches.

Subversion substitutes five keywords:

LastChangedDate
     The last time this file changed.  Can also be abbreviated as Date. The keyword substitution of $LastChangedDate$ will look something like $LastChangedDate: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $.

LastChangedRevision
     The last revision in which this file changed.  Can be abbreviated as Rev.  The keyword substitution of $LastChangedRevision will look something like $LastChangedRevision: 144 $.

LastChangedBy
     The last user to change this file.  Can be abbreviated as Author.  The keyword substitution of $LastChangedBy$ will look something like $LastChangedBy: joe $.

HeadURL
     A full URL to the latest version of the file in the repository.  Can be abbreviated as URL.  The keyword substitution of $HeadURL$ will look something like $HeadURL: http://svn.collab.net/repos/trunk/README $.

Id
     A compressed summary of the other keywords, for example: $Id: bar 148 2002-07-28 21:30:43 epg $.  This means the file bar was last changed in revision 148 by committer epg, at 2002-07-28 21:30:43.

To activate a keyword, or set of keywords, you merely need to set the svn:keywords property to a list of keywords you want replaced. Keywords not listed in svn:keywords will not be replaced.

     $ svn propset svn:keywords "Date Author" foo.c
     property `svn:keywords' set on 'foo.c'

And when you commit this property change, you'll discover that all occurrences of $Date$, $LastChangedDate$, $Author$, and $LastChangedBy$ will have substituted values within foo.c.

svn:eol-style
.............

By default, Subversion doesn't pay any attention to line endings.  If a text file has either LF, CR, or CRLF endings, then those are the line endings that will exist on the file in both the repository and working copy.

But if developers are working on different platforms, line endings can sometimes become troublesome.  For example, if a Win32 developer and Unix developer took turns modifying a file, its line endings might flip-flop back and forth from revision to revision in the repository. This makes examining or merging differences very difficult, as every line appears to be changed in each version of the file.

The solution here is to set the svn:eol-style property to ``native''.  This makes the file always appear with the ``native'' line endings of each developer's operating system.  Note, however, that the file will always contain LF endings in the repository.  This prevents the line-ending ``churn'' from revision to revision.

Alternately, you can force files to always retain a fixed, specific line ending: set a file's svn:eol-style property to one of LF, CR or CRLF.  A Win32 .dsp file, for example, which is used by Microsoft development tools, should always have CRLF endings.

svn:externals
.............

See Modules.

Modules
=======

Sometimes it's useful to construct a working copy that is made out of a number of different checkouts.  For example, you may want different sub-directories to come from different locations in a repository.

On the one hand, you could begin by checking out a working copy, and then run svn switch on various subdirectories.  But this is a bit of work.  Wouldn't it be nice to define -- in a single place -- exactly how you want the final working copy to be?

This is known as a module.  You can define a module by attaching another special ``magic'' svn: property to a directory: the svn:externals property.

The value of this property is a list of subdirectories and their corresponding URLs:

     $ svn propget svn:externals projectdir
     subdir1/foo       http://url.for.external.source/foo
     subdir1/bar       http://blah.blah.blah/repositories/theirproj
     subdir1/bar/baz   http://blorg.blorg.blorg/basement/code

Assuming that this property is attached to the directory projectdir, then when we check it out, we'll get everything else defined by the property.

     $ svn checkout http://foo.com/repos/projectdir
     A  projectdir/blah.c
     A  projectdir/gloo.c
     A  projectdir/trout.h
     Checked out revision 128.

     Fetching external item into projectdir/subdir1/foo
     A  projectdir/subdir1/foo/rho.txt
     A  projectdir/subdir1/foo/pi.txt
     A  projectdir/subdir1/foo/tau.doc
     Checked out revision 128.
     ...

By tweaking the value of the svn:externals property, the definition of the module can change over time, and subsequent calls to svn update will update working copies appropriately.

Revisions
=========

As you may have noticed, many Subversion commands are able to process the -r switch.  Here we describe some special ways to specify revisions.

The Subversion client understands a number of revision keywords. These keywords can be used instead of integer arguments to the -r switch, and are resolved into specific revision numbers:

HEAD
     The latest revision in the repository.

BASE
     The ``pristine'' revision of an item in a working copy.

COMMITTED
     The last revision in which an item changed.

PREV
     The revision just before the last revision in which an item changed.  (Technically, COMMITTED - 1).

Here are some examples of revision keywords in action:

     $ svn diff -r PREV:COMMITTED foo.c
     # shows the last change committed to foo.c

     $ svn log -r HEAD
     # shows log message for the latest repository commit

     $ svn diff -r HEAD
     # compares your working file (with local mods) to the latest version
     # in the repository.

     $ svn diff -r BASE:HEAD foo.c
     # compares your "pristine" foo.c (no local mods) with the latest version
     # in the repository

     $ svn log -r BASE:HEAD
     # shows all commit logs since you last updated

     $ svn update -r PREV foo.c
     # rewinds the last change on foo.c.
     # (foo.c's working revision is decreased.)

Other Commands
==============

svn cleanup
-----------

When Subversion modifies your working copy (or any information within .svn), it tries to do so as safely as possible.  Before changing anything, it writes its intentions to a logfile, then executes the commands in the logfile.  It's similar in design to a journaled filesystem; if the user hits Control-C or if the machine crashes, the logfiles are left lying around.  By re-executing the logfiles, the work can complete, and your working copy can get itself back into a consistent state.

And this is exactly what svn cleanup does: it searches your working copy and re-runs any leftover logs, removing locks in the process.  Use this command if Subversion ever tells you that some part of your working copy is ``locked''.  Also, svn status will display an L next to locked items:

     $ svn st
       L    ./somedir
     M      ./somedir/foo.c

     $ svn cleanup
     $ svn st
     M      ./somedir/foo.c

svn info
--------

In general, we try to discourage users from directly reading the .svn/entries file used to track items.  Instead, curiosity can be quelled by using the svn info to display most of the tracked information:

     $ svn info client.texi
     Path: client.texi
     Name: client.texi
     Url: http://svn.collab.net/repos/svn/trunk/doc/handbook/client.texi
     Revision: 2548
     Node Kind: file
     Schedule: normal
     Last Changed Author: fitz
     Last Changed Rev: 2545
     Last Changed Date: 2002-07-15 23:03:54 -0500 (Mon, 15 Jul 2002)
     Text Last Updated: 2002-07-16 08:48:04 -0500 (Tue, 16 Jul 2002)
     Properties Last Updated: 2002-07-16 08:48:03 -0500 (Tue, 16 Jul 2002)
     Checksum: 8sfaU+5dqyOgkhuSdyxGrQ==

svn import
----------

The import command is a quick way to move an unversioned tree of files into a repository.

There are two ways to use this command:

     $ svnadmin create /usr/local/svn/newrepos
     $ svn import file:///usr/local/svn/newrepos mytree
     Adding  mytree/foo.c
     Adding  mytree/bar.c
     Adding  mytree/subdir
     Adding  mytree/subdir/quux.h
     Transmitting file data....
     Committed revision 1.

The above example places the contents of directory mytree directly into the root of the repository:

     /foo.c
     /bar.c
     /subdir
     /subdir/quux.h

If you give svn import a third argument, it will use the argument as the name of a new subdirectory to create within the URL.

     $ svnadmin create /usr/local/svn/newrepos
     $ svn import file:///usr/local/svn/newrepos mytree fooproject
     Adding  mytree/foo.c
     Adding  mytree/bar.c
     Adding  mytree/subdir
     Adding  mytree/subdir/quux.h
     Transmitting file data....
     Committed revision 1.

The repository would now look like

     /fooproject/foo.c
     /fooproject/bar.c
     /fooproject/subdir
     /fooproject/subdir/quux.h

svn export
----------

The export command is a quick way to create an unversioned tree of files from a repository directory.

     $ svn export file:///usr/local/svn/newrepos/fooproject
     A  fooproject/foo.c
     A  fooproject/bar.c
     A  fooproject/subdir
     A  fooproject/subdir/quux.h
     Checked out revision 3.

The resulting directory will not contain any .svn administrative areas, and all property metadata will be lost.  (Hint: don't use this tecnique for backing up; it's probably better for rolling source distributions.)

svn ls
------

The ls command lets you find what files are in a repository directory.

     $ svn ls http://svn.collab.net/repos/svn
     README
     branches/
     clients/
     tags/
     trunk/

If you want a more detailed listing, pass the -v flag and you will get output like this.

     $ svn ls -v http://svn.collab.net/repos/svn
     _    2755   kfogel     1331 Jul 28 02:07 README
     _    2773  sussman        0 Jul 29 15:07 branches/
     _    2769 cmpilato        0 Jul 29 12:07 clients/
     _    2698   rooneg        0 Jul 24 18:07 tags/
     _    2785    brane        0 Jul 29 19:07 trunk/

The columns tell you if there file has any properties (``P'' if it does, ``_'' if it doesn't), the revision it was last updated at, the user who last updated it, it's size, the date it was last updated, and the filename.

svn mkdir
---------

This is another convenience command, and it has two uses.

First, it can be used to simultaneously create a new working copy directory and schedule it for addition:

     $ svn mkdir new-dir
     A     new-dir

Or, it can be used to instantly create a directory in a repository (no working copy needed):

     $ svn mkdir file:///usr/local/svn/newrepos/branches -m "made new dir"
     Committed revision 1123.

Again, this is a form of immediate commit, so some sort of log message is required.

Run-time Configuration
======================

When you first run the svn command-line client, it creates a per-user configuration area.  On Unix-like systems, a .subversion/ directory is created in the user's home directory.  On Win32 systems, a Subversion folder is created wherever it's appropriate to do so (typically somewhere within Documents and Settings\username, although it depends on the system.)

Proxies
-------

At the time of writing, the configuration area only contains one item: a proxies file.  By setting values in this file, your Subversion client can operate through an http proxy.  (Read the file itself for details; it should be self-documenting.)

Config
------

Soon -- very soon -- a config file will exist in this area for defining general user preferences.  For example, the preferred $EDITOR to use, options to pass through to svn diff, preferences for date/time formats, and so on.  See issue #668 for details (http://subversion.tigris.org/issues/show_bug.cgi?id=668).

Multiple config areas
---------------------

On Unix, an administrator can create``global'' Subversion preferences by creating and populating an /etc/subversion/ area.  The per-user ~/.subversion/ configuration will still override these defaults, however.

On Win32, an administrator has the option of creating three other locations: a global Subversion folder in the ``All Users'' area, a collection of global registry settings, or a collection of per-user registry settings.  The registry settings are set in:

     HKCU\Software\Tigris.org\Subversion\Proxies
     HKCU\Software\Tigris.org\Subversion\Config
     etc.

To clarify, here is the order Subversion searches for run-time settings on Win32.  Each subsequent location overrides the previous one:

  * global registry

  * global Subversion folder

  * user registry

  * user Subversion folder