# Guided Tour

Now we will go into the details of using Subversion. By the time you reach the end of this chapter, you will be able to perform almost all the tasks you need to use Subversion in a normal day's work. You'll start with an initial checkout of your code, and walk through making changes and examining those changes. You'll also see how to bring changes made by others into your working copy, examine them, and work through any conflicts that might arise.

Note that this chapter is not meant to be an exhaustive list of all Subversion's commands—rather, it's a conversational introduction to the most common Subversion tasks you'll encounter. This chapter assumes that you've read and understood and are familiar with the general model of Subversion. For a complete reference of all commands, see .

## Help!

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

## Import

You use `svn import` to import a new project into a Subversion repository. While this is most likely the very first thing you will do when you set up your Subversion server, it's not something that happens very often. For a detailed description of import, see later in this chapter.

## Revisions: Numbers, Keywords, and Dates, Oh My!

Before we go on, you should know a bit about how to identify a particular revision in your repository. As you learned in , a revision is a snapshot of the repository at a particular moment in time. As you continue to commit and grow your repository, you need a mechanism for identifying these snapshots.

You specify these revisions by using the `--revision` (`-r`) switch plus the revision you want (`svn --revision REV`) or you can specify a range by separating two revisions with a colon (`svn --revision REV1:REV2`). And Subversion lets you refer to these revisions by number, keyword, or date.

### Revision Numbers

When you create a new Subversion repository, it begins its life at revision zero and each successive commit increases the revision number by one. After your commit completes, the Subversion client informs you of the new revision number:

    $ svn commit --message "Corrected number of cheese slices."
    Sending        sandwich.txt
    Transmitting file data .
    Committed revision 3.

If at any point in the future you want to refer to that revision (we'll see how and why we might want to do that later in this chapter), you can refer to it as 3.

### Revision Keywords

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

Each directory in your working copy contains an administrative subdirectory called `.svn`. For every file in a directory, Subversion keeps a copy of each file in the administrative area. This copy is an unmodified (no keyword expansion, no end-of-line translation, no nothing) copy of the file as it existed in the last revision (called the BASE revision) that you updated it to in your working copy. We refer to this file as the pristine copy or text-base version of your file, and it's always an exact byte-for-byte copy of the file as it exists in the repository.

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 before (or at) `BASE`.

PREV

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

`PREV`, `BASE`, and `COMMITTED` can be used to refer to local paths, but not to URLs.

Here are some examples of revision keywords in action. Don't worry if the commands don't make sense yet; we'll be explaining these commands as we go through the chapter:

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

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

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

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

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

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

These keywords allow you to perform many common (and helpful) operations without having to look up specific revision numbers or remember the exact revision of your working copy.

### Revision Dates

Anywhere that you specify a revision number or revision keyword, you can also specify a date by specifying the date inside curly braces {}. You can even access a range of changes in the repository using both dates and revisions together!

Here are examples of the date formats that Subversion accepts. Remember to use quotes around any date that contains spaces.

    $ svn checkout --revision {2002-02-17}
    $ svn checkout --revision {15:30}
    $ svn checkout --revision {15:30:00.200000}
    $ svn checkout --revision {"2002-02-17 15:30"}
    $ svn checkout --revision {"2002-02-17 15:30 +0230"}
    $ svn checkout --revision {2002-02-17T15:30}
    $ svn checkout --revision {2002-02-17T15:30Z}
    $ svn checkout --revision {2002-02-17T15:30-04:00}
    $ svn checkout --revision {20020217T1530}
    $ svn checkout --revision {20020217T1530Z}
    $ svn checkout --revision {20020217T1530-0500}
    …

When you specify a date as a revision, Subversion finds the most recent revision of the repository as of that date:

    $ svn log --revision {2002-11-28}
    ------------------------------------------------------------------------
    r12 | ira | 2002-11-27 12:31:51 -0600 (Wed, 27 Nov 2002) | 6 lines
    …

#### Is Subversion a Day Early?

If you specify a single date as a revision without specifying a time of day (for example `2002-11-27`), you may think that Subversion should give you the last revision that took place on the 27th of November. Instead, you'll get back a revision from the 26th, or even earlier. Remember that Subversion will find the most recent revision of the repository as of the date you give. If you give a date without a timestamp, like `2002-11-27`, Subversion assumes a time of 00:00:00, so looking for the most recent revision won't return anything on the day of the 27th.

If you want to include the 27th in your search, you can either specify the 27th with the time (`{"2002-11-27 23:59"}`), or just specify the next day (`{2002-11-28}`).

You can also use a range of dates. Subversion will find all revisions between both dates, inclusive:

    $ svn log --revision {2002-11-20}:{2002-11-29}
    …

As we pointed out, you can also mix dates and revisions:

    $ svn log --revision {2002-11-20}:4040

Users should be aware of a subtlety that can become quite a stumblingblock when dealing with dates in Subversion. Since the timestamp of a revision is stored as a property of the revision—an unversioned, modifiable property—revision timestamps can be changed to represent complete falsifications of true chronology, or even removed altogether. This will wreak havoc on the internal date-to-revision conversion that Subversion performs.

## Initial Checkout

Most of the time, you will start using a Subversion repository by doing a checkout of your project. Checking out a repository creates a copy of it on your local machine. This copy contains the `HEAD` (latest revision) of the Subversion repository that you specify on the command line:

    $ svn checkout 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.

### Repository Layout

If you're wondering what `trunk` is all about in the above URL, it's part of the way we recommend you lay out your Subversion repository which we'll talk a lot more about in .

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

    $ svn checkout http://svn.collab.net/repos/svn/trunk/doc/book/tools
    A  tools/readme-dblite.html
    A  tools/fo-stylesheet.xsl
    A  tools/svnbook.el
    A  tools/dtd
    A  tools/dtd/dblite.dtd
    …
    Checked out revision 2499.

Since Subversion uses a copy-modify-merge model instead of lock-modify-unlock (see ), you're already able to start making changes to the files and directories in your working copy. Your working copy is just like any other collection of files and directories on your system. You can edit and change them, move them around, you can even delete the entire working copy and forget about it.

While your working copy is just like any other collection of files and directories on your system, you need to let Subversion know if you're going to be rearranging anything inside of your working copy. If you want to copy or move an item in a working copy, you should use `svn copy` or `svn move` instead of the copy and move commands provided by your operating system. We'll talk more about them later in this chapter.

Unless you're ready to commit a new file or directory, or changes to existing ones, there's no need to further notify the Subversion server that you've done anything.

### What's with the `.svn` directory?

Every directory in a working copy contains an administrative area, a subdirectory named `.svn`. Usually, directory listing commands won't show this subdirectory, but it is nevertheless an important directory. Whatever you do, don't delete or change anything in the administrative area! Subversion depends on it to manage your working copy.

While you can certainly check out a working copy with the URL of the repository as the only argument, you can also specify a directory after your repository URL. This places your working copy into the new directory that you name. For example:

    $ svn checkout 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.

That will place your working copy in a directory named `subv` instead of a directory named `trunk` as we did previously.

## 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

  - `svn update`

- Make changes

  - `svn add`

  - `svn delete`

  - `svn copy`

  - `svn move`

- Examine your changes

  - `svn status`

  - `svn diff`

  - `svn revert`

- Merge others' changes

  - `svn merge`

  - `svn resolved`

- Commit your changes

  - `svn commit`

### Update Your Working Copy

When working on a project with a team, you'll want to update your working copy to receive any changes made since your last update by other developers on the project. Use `svn update` to bring your working copy into sync with the latest revision in the repository.

    $ svn update
    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 to let you know what actions Subversion performed to bring your working copy up-to-date:

`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 from the repository, but your local copy of the file had your modifications. Either the changes did not intersect, or the changes were exactly the same as your local modifications, so Subversion has successfully 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 later in this chapter.

### Make Changes to Your Working Copy

Now you can get to work and make changes in your working copy. It's usually most convenient to decide on a particular change (or set of changes) to make, such as writing a new feature, fixing a bug, etc. The Subversion commands that you will use here are `svn add`, `svn delete`, `svn copy`, and `svn move`. However, if you are merely editing files that are already in Subversion, you may not need to use any of these commands until you commit. Changes you can make to your working copy:

File changes

  This is the simplest sort of change. You don't need to tell Subversion that you intend to change a file; just make your changes. 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, addition, copying, or moving. While these changes may take place immediately in your working copy, no additions or removals will happen in the repository until you commit them.

To make file changes, use your text editor, word processor, graphics program, or whatever tool you would normally use. Subversion handles binary files just as easily as it handles text files—and just as efficiently too.

Here is an overview of the four Subversion subcommands that you'll use most often to make tree changes (we'll cover `svn import` and `svn mkdir` later).

`svn add foo`

  Schedule `foo` to be added to the repository. When you next commit, `foo` will become a child of its parent directory. Note that if `foo` is a directory, everything underneath `foo` will be scheduled for addition. If you only want to schedule `foo` itself, pass the `--non-recursive` (`-N`) switch.

`svn delete foo`

  Schedule `foo` to be deleted from the repository. If `foo` is a file, it is immediately deleted from your working copy. If `foo` is a directory, it is not deleted, but Subversion schedules it for deletion. When you commit your changes, `foo` will be removed from your working copy and the repository. Of course, nothing is ever totally deleted from the repository—just from the `HEAD` of the repository. You can get back anything you delete by checking out (or updating your working copy) a revision earlier than the one in which you deleted it.

`svn copy foo bar`

  Create a 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, its copy history is recorded (as having originally come from `foo`). `svn copy` does not create intermediate directories.

`svn move foo bar`

  This command is exactly the same as running `svn copy foo bar; svn delete foo`. That is, `bar` is scheduled for addition as a copy of `foo`, and `foo` is scheduled for removal. `svn move` does not create intermediate directories.

#### Changing the Repository Without a Working Copy

Earlier in this chapter, we said that you have to commit any changes that you make in order for the repository to reflect these changes. That's not entirely true—there are some use-cases that immediately commit tree changes to the repository. This only 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 copy`, `svn move`, and `svn delete` can work with URLs.

URL operations behave in this manner because commands that operate on a working copy can use the working copy as a sort of staging area to set up your changes before committing them to the repository. Commands that operate on URLs don't have this luxury, so when you operate directly on a URL, any of the above actions represent an immediate commit.

### Examine Your Changes

Once you've finished making changes, you need to commit them to the repository, but before you do so, it's usually a good idea to take a look at exactly what you've changed. By examining your changes before you commit, you can make a more accurate log message. You may also discover that you've inadvertently changed a file, and this gives you a chance to revert those changes before committing. Additionally, this is a good opportunity to review and scrutinize changes before publishing them. You can see exactly what changes you've made by using `svn status`, `svn diff`, and `svn revert`. You will usually use the first two commands to find out what files have changed in your working copy, and then perhaps the third to revert some (or all) of those changes.

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

#### `svn status`

You'll probably use the `svn status` command more than any other Subversion command.

##### CVS Users: Hold That Update!

You're probably used to using `cvs update` to see what changes you've made to your working copy. `svn status` will give you all the information you need regarding what has changed in your working copy—without accessing the repository or potentially incorporating new changes published by other users.

In Subversion, `update` does just that—it updates your working copy with any changes committed to the repository since the last time you've updated your working copy. You'll have to break the habit of using the `update` command to see what local modifications you've made.

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. (Note that the text following `#` in the following example is not actually 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
    X      3rd_party           # this dir is part of an externals definition
    ?      foo.o               # svn doesn't manage foo.o
    !      some_dir            # svn manages this, but it's either missing or incomplete
    ~      qux                 # versioned as dir, but is file, or vice versa
    I      .screenrc           # this file is ignored
    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/loot/bloo.h   # this file is scheduled for addition
    C      stuff/loot/lump.c   # this file has conflicts from an update
        S  stuff/squawk        # this file or dir has been switched to a branch
    …

In this output format `svn status` prints five 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:

`A file_or_dir`

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

`C file`

  The file `file` is in a state of conflict. That is, changes received from the server during an update overlap with local changes that you have in your working copy. You must resolve this conflict before committing your changes to the repository.

`D file_or_dir`

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

`M file`

  The contents of the file `file` have been modified.

`X dir`

  The directory `dir` is unversioned, but is related to a Subversion externals definition. To find out more about externals definitions, see .

`? file_or_dir`

  The file or directory `file_or_dir` is not under version control. You can silence the question marks by either passing the `--quiet` (`-q`) switch to `svn status`, or by setting the `svn:ignore` property on the parent directory. For more information on ignored files, see .

`! file_or_dir`

  The file or directory `file_or_dir` is under version control but is missing or somehow incomplete. The item can be missing if it's removed using a non-Subversion command. In the case of a directory, it can be incomplete if you happened to interrupt a checkout or update. A quick `svn update` will refetch the file or directory from the repository, or `svn revert file` will restore a missing file.

`~ file_or_dir`

  The file or directory `file_or_dir` is in the repository as one kind of object, but what's actually in your working copy is some other kind. For example, Subversion might have a file in the repository, but you removed the file and created a directory in its place, without using the `svn delete` or `svn add` commands.

`I file_or_dir`

  Subversion is ignoring the file or directory `file_or_dir`, probably because you told it to. For more information on ignored files, see . Note that this symbol only shows up if you pass the `--no-ignore` option to `svn status`.

The second column tells the status of a file or directory's properties (see for more information on properties). If an `M` appears in the second column, then the properties have been modified, otherwise a whitespace will be printed.

The third column will only show whitespace or an `L` which means that Subversion has locked the item in the `.svn` working area. You will see an `L` if you run `svn status` in a directory where an `svn commit` is in progress—perhaps when you are editing the log message. If Subversion is not running, then presumably Subversion was interrupted and the lock needs to be cleaned up by running `svn cleanup` (more about that later in this chapter).

The fourth 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 move` or `svn copy` 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 modifications. When you commit, first the parent will be added-with-history (copied), which means this file will automatically exist in the copy. Then the local modifications will be uploaded into the copy.

The fifth column will only show whitespace or an `S`. This signifies that the file or directory has been switched from the path of the rest of the working copy (using `svn switch`) to a branch.

If you pass a specific path to `svn status`, it gives you information about that item alone:

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

`svn status` also has a `--verbose` (`-v`) switch, which will show you the status of every item in your working copy, even if it has not been changed:

    $ svn status --verbose
    M               44        23    sally     README
                    44        30    sally     INSTALL
    M               44        20    harry     bar.c
                    44        18    ira       stuff
                    44        35    harry     stuff/trout.c
    D               44        19    ira       stuff/fish.c
                    44        21    sally     stuff/things
    A                0         ?     ?        stuff/things/bloo.h
                    44        36    harry     stuff/things/gloo.c

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

None of the above invocations to `svn status` contact the repository, they work only locally by comparing the metadata in the `.svn` directory with the working copy. Finally, there is the `--show-updates` (`-u`) switch, which contacts the repository and adds information about things that are out-of-date:

    $ svn status --show-updates --verbose
    M      *        44        23    sally     README
    M               44        20    harry     bar.c
           *        44        35    harry     stuff/trout.c
    D               44        19    ira       stuff/fish.c
    A                0         ?     ?        stuff/things/bloo.h
    Status against revision:   46

Notice the two asterisks: if you were to run `svn update` at this point, you would receive changes to `README` and `trout.c`. This tells you some very useful information—you'll need to update and get the server changes on `README` before you commit, or the repository will reject your commit for being out-of-date. (More on this subject later.)

#### `svn diff`

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: Subversion uses its internal diff engine, which produces unified diff format, by default. If you want diff output in a different format, specify an external diff program using `--diff-cmd` and pass any flags you'd like to it using the `--extensions` switch. For example, to see local differences in file `foo.c` in context output format while ignoring whitespace changes, you might run `svn diff --diff-cmd /usr/bin/diff --extensions '-bc' foo.c`.

    $ svn diff
    Index: bar.c
    ===================================================================
    --- bar.c	(revision 3)
    +++ bar.c	(working copy)
    @@ -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	(revision 3)
    +++ README	(working copy)
    @@ -193,3 +193,4 @@
    +Note to self:  pick up laundry.

    Index: stuff/fish.c
    ===================================================================
    --- stuff/fish.c	(revision 1)
    +++ stuff/fish.c	(working copy)
    -Welcome to the file known as 'fish'.
    -Information on fish will be here soon.

    Index: stuff/things/bloo.h
    ===================================================================
    --- stuff/things/bloo.h	(revision 8)
    +++ stuff/things/bloo.h	(working copy)
    +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.

Output is displayed in unified diff format. That is, removed lines are prefaced with a `-` and added lines are prefaced with a `+`. `svn diff` also prints filename and offset information useful to the `patch` program, so you can generate patches by redirecting the diff output to a file:

    $ svn diff > patchfile

You could, for example, email the patchfile to another developer for review or testing prior to commit.

#### `svn revert`

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

This is a perfect opportunity to use `svn revert`.

    $ svn revert README
    Reverted 'README'

Subversion reverts the file to its pre-modified state by overwriting it with the cached pristine copy from the `.svn` area. But also note that `svn revert` can undo any scheduled operations—for example, you might decide that you don't want to add a new file after all:

    $ svn status foo
    ?      foo

    $ svn add foo
    A         foo

    $ svn revert foo
    Reverted 'foo'

    $ svn status foo
    ?      foo

`svn revert` ITEM has exactly the same effect as deleting ITEM from your working copy and then running `svn update -r BASE` ITEM. However, if you're reverting a file, `svn revert` has one very noticeable difference—it doesn't have to communicate with the repository to restore your file.

Or perhaps you mistakenly removed a file from version control:

    $ svn status README
           README

    $ svn delete README
    D         README

    $ svn revert README
    Reverted 'README'

    $ svn status README
           README

#### Look Ma! No Network!

All three of these commands (`svn status`, `svn diff`, and `svn revert`) can be used without any network access. This makes it easy to manage your changes-in-progress when you are somewhere without a network connection, such as traveling on an airplane, riding a commuter train or hacking on the beach.

Subversion does this by keeping private caches of pristine versions of each versioned file inside of the `.svn` administrative areas. This allows Subversion to report—and revert—local modifications to those files without network access. This cache (called the text-base) also allows Subversion to send the user's local modifications during a commit to the server as a compressed delta (or difference) against the pristine version. Having this cache is a tremendous benefit—even if you have a fast net connection, it's much faster to send only a file's changes rather than the whole file to the server. At first glance, this might not seem that important, but imagine the repercussions if you try to commit a one line change to a 400MB file and have to send the whole file to the server!

### Resolve Conflicts (Merging Others' Changes)

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

    $ svn update
    U  INSTALL
    G  README
    C  bar.c
    Updated to revision 46.

The `U` and `G` codes are no cause for concern; those files cleanly absorbed changes from the repository. The files marked with `U` contained no local changes but were `U`pdated with changes from the repository. The `G` stands for mer`G`ed, which means that the file had local changes to begin with, but the changes coming from the repository didn't overlap in any way.

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

Whenever a conflict occurs, three things occur to assist you in noticing and resolving that conflict:

- Subversion prints a `C` during the update, and remembers that the file is in a state of conflict.

- Subversion places conflict markers—special strings of text which delimit the sides of the conflict—into the file to visibly demonstrate the overlapping areas.

- For every conflicted file, Subversion places three extra files in your working copy:

  `filename.mine`

    This is your file as it existed in your working copy before you updated your working copy—that is, without conflict markers. This file has your latest changes in it and nothing else.

  `filename.rOLDREV`

    This is the file that was the `BASE` revision before you updated your working copy. That is, the file that you checked out before you made your latest edits.

  `filename.rNEWREV`

    This is the file that your Subversion client just received from the server when you updated your working copy. This file corresponds to the `HEAD` revision of the repository.

  Here `OLDREV` is the revision number of the file in your `.svn` directory and `NEWREV` is the revision number of the repository `HEAD`.

For example, Sally makes changes to the file `sandwich.txt` in the repository. Harry has just changed the file in his working copy and checked it in. Sally updates her working copy before checking in and she gets a conflict:

    $ svn update
    C  sandwich.txt
    Updated to revision 2.
    $ ls -1
    sandwich.txt
    sandwich.txt.mine
    sandwich.txt.r1
    sandwich.txt.r2

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

    $ svn commit --message "Add a few more things"
    svn: Commit failed (details follow):
    svn: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict

If you get a conflict, you need to do one of three things:

- Merge the conflicted text by hand (by examining and editing the conflict markers within the file).

- Copy one of the temporary files on top of your working file.

- Run `svn revert <filename>` to throw away all of your local changes.

Once you've resolved the conflict, you need to let Subversion know by running `svn resolved`. This removes the three temporary files and Subversion no longer considers the file to be in a state of conflict. You can always remove the temporary files yourself, but would you really want to do that when Subversion can do it for you? We didn't think so.

    $ svn resolved sandwich.txt
    Resolved conflicted state of 'sandwich.txt'

#### Merging Conflicts by Hand

Merging conflicts by hand can be quite intimidating the first time you attempt it, but with a little practice, it can become as easy as falling off a bike.

Here's an example. Due to a miscommunication, you and Sally, your collaborator, both edit the file `sandwich.txt` at the same time. Sally commits her changes, and when you go to update your working copy, you get a conflict and we're going to have to edit `sandwich.txt` to resolve the conflicts. First, let's take a look at the file:

    $ cat sandwich.txt
    Top piece of bread
    Mayonnaise
    Lettuce
    Tomato
    Provolone
    <<<<<<< .mine
    Salami
    Mortadella
    Prosciutto
    =======
    Sauerkraut
    Grilled Chicken
    >>>>>>> .r2
    Creole Mustard
    Bottom piece of bread

The strings of less-than signs, equal signs, and greater-than signs are conflict markers, and are not part of the actual data in conflict. You generally want to ensure that those are removed from the file before your next commit. The text between the first two sets of markers is composed of the changes you made in the conflicting area:

    <<<<<<< .mine
    Salami
    Mortadella
    Prosciutto
    =======

The text between the second and third sets of conflict markers is the text from Sally's commit:

    =======
    Sauerkraut
    Grilled Chicken
    >>>>>>> .r2

Usually you won't want to just delete the conflict markers and Sally's changes—she's going to be awfully surprised when the sandwich arrives and it's not what she wanted. So this is where you pick up the phone or walk across the office and explain to Sally that you can't get sauerkraut from an Italian deli. And if you ask them for it, they may very well ride you out of town on a rail. Once you've agreed on the changes you will check in, edit your file and remove the conflict markers.

    Top piece of bread
    Mayonnaise
    Lettuce
    Tomato
    Provolone
    Salami
    Mortadella
    Prosciutto
    Creole Mustard
    Bottom piece of bread

Now run `svn resolved`, and you're ready to commit your changes:

    $ svn resolved sandwich.txt
    $ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."

Remember, if you ever get confused while editing the conflicted file, you can always consult the three files that Subversion creates for you in your working copy—including your file as it was before you updated. You can even use a third-party interactive merging tool to examine those three files.

#### Copying a File Onto Your Working File

If you get a conflict and decide that you want to throw out your changes, you can merely copy one of the temporary files created by Subversion over the file in your working copy:

    $ svn update
    C  sandwich.txt
    Updated to revision 2.
    $ ls sandwich.*
    sandwich.txt  sandwich.txt.mine  sandwich.txt.r2  sandwich.txt.r1
    $ cp sandwich.txt.r2 sandwich.txt
    $ svn resolved sandwich.txt

#### Punting: Using `svn revert`

If you get a conflict, and upon examination decide that you want to throw out your changes and start your edits again, just revert your changes:

    $ svn revert sandwich.txt
    Reverted 'sandwich.txt'
    $ ls sandwich.*
    sandwich.txt

Note that when you revert a conflicted file, you don't have to run `svn resolved`.

Now you're ready to check in your changes. Note that `svn resolved`, unlike most of the other commands we've dealt with in this chapter, requires an argument. In any case, you want to be careful and only run `svn resolved` when you're certain that you've fixed the conflict in your file—once the temporary files are removed, Subversion will let you commit the file even if it still contains conflict markers.

### Commit Your Changes

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

The `svn commit` command sends all 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 attached to the new revision you create. If your log message is brief, you may wish to supply it on the command line using the `--message` (or `-m`) option:

    $ svn commit --message "Corrected number of cheese slices."
    Sending        sandwich.txt
    Transmitting file data .
    Committed revision 3.

However, if you've been composing your log message as you work, you may want to tell Subversion to get the message from a file by passing the filename with the `--file` switch:

    $ svn commit --file logmsg
    Sending        sandwich
    Transmitting file data .
    Committed revision 4.

If you fail to specify either the `--message` or `--file` switch, then Subversion will automatically launch your favorite editor (as defined in the environment variable `$EDITOR`) for composing a log message.

If you're in your editor writing a commit message and decide that you want to cancel your commit, you can just quit your editor without saving changes. If you've already saved your commit message, simply delete the text and save again.

    $ svn commit
    Waiting for Emacs...Done

    Log message unchanged or not specified
    a)bort, c)ontinue, e)dit
    a
    $

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 you that one or more of your files is out-of-date:

    $ svn commit --message "Add another rule"
    Sending        rules.txt
    svn: Commit failed (details follow):
    svn: Out of date: 'rules.txt' in transaction 'g'

At this point, you need to run `svn update`, deal with any merges or conflicts that result, and attempt your commit again.

That covers the basic work cycle for using Subversion. There are many other features in Subversion that you can use to manage your repository and working copy, but you can get by quite easily using only the commands that we've discussed so far in this chapter.

## Examining History

As we mentioned earlier, the repository is like a time machine. It keeps a record of every change ever committed, and allows you to explore this history by examining previous versions of files and directories as well as the metadata that accompanies them. With a single Subversion command, you can check out the repository (or restore an existing working copy) exactly as it was at any date or revision number in the past. However, sometimes you just want to peer into the past instead of going into the past.

There are several commands that can provide you with 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`

  Shows you the specific details of how a file changed over time.

`svn cat`

  This is used to retrieve any file as it existed in a particular revision number and display it on your screen.

`svn list`

  Displays the files in a directory for any given revision.

### `svn log`

To find out information about the history of a file or directory, use the `svn log` command. `svn log` will provide you with a record of who made changes to a file or directory, at what revision it changed, the time and date of that revision, and, if it was provided, the log message that accompanied the commit.

    $ svn log
    ------------------------------------------------------------------------
    r3 | sally | Mon, 15 Jul 2002 18:03:46 -0500 | 1 line

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

    Added main() methods.
    ------------------------------------------------------------------------
    r1 | sally | Mon, 15 Jul 2002 17:40:08 -0500 | 1 line

    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 --revision 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               # shows log for revision 8

You can also examine the log history of a single file or directory. For example:

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

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

If you want even more information about a file or directory, `svn log` also takes a `--verbose` (`-v`) switch. Because Subversion allows you to move and copy files and directories, it is important to be able to track path changes in the filesystem, so in verbose mode, `svn log` will include a list of changed paths in a revision in its output:

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

    Frozzled the sub-space winch.

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

#### Why Does `svn log` Give Me an Empty Response?

After working with Subversion for a bit, most users will come across something like this:

    $ svn log -r 2
    ------------------------------------------------------------------------
    $

At first glance, this seems like an error. But recall that while revisions are repository-wide, `svn log` operates on a path in the repository. If you supply no path, Subversion uses the current working directory as the default target. As a result, if you're operating in a subdirectory of your working copy and attempt to log a revision in which neither that directory nor any of its children was changed, Subversion will give you an empty log. If you want to see what changed in that revision, try pointing `svn log` directly at the top-most URL of your repository, as in `svn log -r 2 http://svn.collab.net/repos/svn`.

### svn diff

We've already seen `svn diff` before—it displays file differences in unified diff format; it was used to show the local modifications made to our working copy before committing to the repository.

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

- Examine local changes

- Compare your working copy to the repository

- Compare repository to repository

#### Examining Local Changes

As we've seen, invoking `svn diff` with no switches will compare your working files to the cached pristine copies in the `.svn` area:

    $ svn diff
    Index: rules.txt
    ===================================================================
    --- rules.txt	(revision 3)
    +++ rules.txt	(working copy)
    @@ -1,4 +1,5 @@
     Be kind to others
     Freedom = Responsibility
     Everything in moderation
    -Chew with your mouth open
    +Chew with your mouth closed
    +Listen when others are speaking
    $

#### Comparing Working Copy to Repository

If a single `--revision` (`-r`) number is passed, then your working copy is compared to the specified revision in the repository.

    $ svn diff --revision 3 rules.txt
    Index: rules.txt
    ===================================================================
    --- rules.txt	(revision 3)
    +++ rules.txt	(working copy)
    @@ -1,4 +1,5 @@
     Be kind to others
     Freedom = Responsibility
     Everything in moderation
    -Chew with your mouth open
    +Chew with your mouth closed
    +Listen when others are speaking
    $

#### Comparing Repository to Repository

If two revision numbers, separated by a colon, are passed via `--revision` (`-r`), then the two revisions are directly compared.

    $ svn diff --revision 2:3 rules.txt
    Index: rules.txt
    ===================================================================
    --- rules.txt	(revision 2)
    +++ rules.txt	(revision 3)
    @@ -1,4 +1,4 @@
     Be kind to others
    -Freedom = Chocolate Ice Cream
    +Freedom = Responsibility
     Everything in moderation
     Chew with your mouth closed
    $

Not only can you use `svn diff` to compare files in your working copy to the repository, but if you supply a URL argument, you can examine the differences between items in the repository without even having a working copy. This is especially useful if you wish to inspect changes in a file when you don't have a working copy on your local machine:

    $ svn diff --revision 4:5 http://svn.red-bean.com/repos/example/trunk/text/rules.txt
    …
    $

### `svn cat`

If you want to examine an earlier version of a file and not necessarily the differences between two files, you can use `svn cat`:

    $ svn cat --revision 2 rules.txt
    Be kind to others
    Freedom = Chocolate Ice Cream
    Everything in moderation
    Chew with your mouth closed
    $

You can also redirect the output directly into a file:

    $ svn cat --revision 2 rules.txt > rules.txt.v2
    $

You're probably wondering why we don't just use `svn update --revision` to update the file to the older revision. There are a few reasons why we might prefer to use `svn cat`.

First, you may want to see the differences between two revisions of a file using an external diff program (perhaps a graphical one, or perhaps your file is in such a format that the output of unified diff is nonsensical). In this case, you'll need to grab a copy of the old revision, redirect it to a file, and pass both that and the file in your working copy to your external diff program.

Sometimes it's easier to look at an older version of a file in its entirety as opposed to just the differences between it and another revision.

### `svn list`

The `svn list` command shows you what files are in a repository directory without actually downloading the files to your local machine:

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

If you want a more detailed listing, pass the `--verbose` (`-v`) flag to get output like this.

    $ svn list --verbose http://svn.collab.net/repos/svn
       2755 harry          1331 Jul 28 02:07 README
       2773 sally               Jul 29 15:07 branches/
       2769 sally               Jul 29 12:07 clients/
       2698 harry               Jul 24 18:07 tags/
       2785 sally               Jul 29 19:07 trunk/

The columns tell you the revision at which the file or directory was last modified, the user who modified it, the size if it is a file, the date it was last modified, and the item's name.

### A Final Word on History

In addition to all of the above commands, you can use `svn update` and `svn checkout` with the `--revision` switch to take an entire working copy back in time See? We told you that Subversion was a time machine.:

    $ svn checkout --revision 1729 # Checks out a new working copy at r1729
    …
    $ svn update --revision 1729 # Updates an existing working copy to r1729
    …

## Other Useful Commands

While not as frequently used as the commands previously discussed in this chapter, you will occasionally need these 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 log file, executes the commands in the log file, then removes the log file (this is similar in design to a journaled filesystem). If a Subversion operation is interrupted (if the process is killed, or if the machine crashes, for example), the log files remain on disk. By re-executing the log files, Subversion can complete the previously started operation, 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 runs any leftover logs, removing locks in the process. If Subversion ever tells you that some part of your working copy is locked, then this is the command that you should run. Also, `svn status` will display an `L` next to locked items:

    $ svn status
      L    somedir
    M      somedir/foo.c

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

### `svn import`

The `svn import` command is a quick way to copy an unversioned tree of files into a repository, creating intermediate directories as necessary.

    $ svnadmin create /usr/local/svn/newrepos
    $ svn import mytree file:///usr/local/svn/newrepos/some/project
    Adding         mytree/foo.c
    Adding         mytree/bar.c
    Adding         mytree/subdir
    Adding         mytree/subdir/quux.h

    Committed revision 1.

The previous example copied the contents of directory `mytree` under the directory `some/project` in the repository:

    $ svn ls file:///usr/local/svn/newrepos/some/project
    bar.c
    foo.c
    subdir/

Note that after the import is finished, the original tree is not converted into a working copy. To start working, you still need to `svn checkout` a fresh working copy of the tree.

## Summary

Now we've covered most of the Subversion client commands. Notable exceptions are those dealing with branching and merging (see ) and properties (see ). However, you may want to take a moment to skim through to get an idea of all the many different commands that Subversion has—and how you can use them to make your work easier.