<chapter id="svn-ch-3">
  <title>Guided Tour</title>

  <simplesect>

    <para>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.</para>

    <para>Note that this chapter is not meant to be an exhaustive list
      of all Subversion's commands&mdash;rather, it's a conversational
      introduction to the most common Subversion tasks you'll
      encounter.  This chapter assumes that you've read and understood
      <xref linkend="svn-ch-2"/> and are familiar with the general
      model of Subversion.  For a complete reference of all commands,
      see <xref linkend="svn-ch-9"/>.</para>

  </simplesect>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 1 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-1">
    <title>Help!</title>


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

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 2 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-2">
    <title>Import</title>

    <para>You use <command>svn import</command> 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 <xref
    linkend="svn-ch-3-sect-7.3"/> later in this chapter.
    </para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 3 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-3">
    <title>Revisions: Numbers, Keywords, and Dates, Oh My!</title>

    <para>Before we go on, you should know a bit about how to identify
      a particular revision in your repository.  As you learned in
      <xref linkend="svn-ch-2-sect-3.2"/>, a revision is a
      <quote>snapshot</quote> 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.</para>

    <para>You specify these revisions by using the
      <option>--revision</option> (<option>-r</option>) switch plus
      the revision you want (<command>svn --revision REV</command>) or
      you can specify a range by separating two revisions with a colon
      (<command>svn --revision REV1:REV2</command>).  And Subversion
      lets you refer to these revisions by number, keyword, or
      date.</para>
    
    <sect2 id="svn-ch-3-sect-3.1">
      <title>Revision Numbers</title>
      
      <para>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:</para>
      
      <screen>
$ svn commit --message "Corrected number of cheese slices."
Sending        sandwich.txt
Transmitting file data .
Committed revision 3.
</screen>

      <para>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
        <quote>3</quote>.</para>

    </sect2>
    
    <sect2 id="svn-ch-3-sect-3.2">
      <title>Revision Keywords</title>
      
      <para>The Subversion client understands a number of
        <firstterm>revision keywords</firstterm>.  These keywords
        can be used instead of integer arguments to the
        <option>--revision</option> switch, and are resolved into
        specific revision numbers by Subversion:</para>

      <note>
        <para>Each directory in your working copy contains an
          administrative subdirectory called
          <filename>.svn</filename>.  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 <quote>BASE</quote>
          revision) that you updated it to in your working copy.  We
          refer to this file as the <firstterm>pristine
          copy</firstterm> or <firstterm>text-base</firstterm> version
          of your file, and it's always an exact byte-for-byte copy of
          the file as it exists in the repository.</para> 
        </note>
      
      <variablelist>
        
        <varlistentry>
          <term>HEAD</term>
          <listitem>
            <para>The latest revision in the repository.</para>
          </listitem>
        </varlistentry>
        
        <varlistentry>
          <term>BASE</term>
          <listitem>
            <para>The <quote>pristine</quote> revision of an item in a
              working copy.</para>
          </listitem>
        </varlistentry>
        
        <varlistentry>
          <term>COMMITTED</term>
          <listitem>
            <para>The last revision in which an item changed before (or
              at) <literal>BASE</literal>.</para>
          </listitem>
        </varlistentry>
        
        <varlistentry>
          <term>PREV</term>
          <listitem>
            <para>The revision just <emphasis>before</emphasis> the last
              revision in which an item changed.  (Technically,
              <literal>COMMITTED</literal> - 1.)</para>
          </listitem>
        </varlistentry>
        
      </variablelist>

      <note>
        <para><literal>PREV</literal>, <literal>BASE</literal>, and
          <literal>COMMITTED</literal> can be used to refer to local
          paths, but not to URLs.</para>
      </note>
      
      <para>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:</para>
      
      <screen>
$ 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 <quote>pristine</quote> 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.)
</screen>
      
      <para>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.</para>
      
    </sect2>
    
    <sect2 id="svn-ch-3-sect-3.3">
      <title>Revision Dates</title>
      
      <para>Anywhere that you specify a revision number or revision
        keyword, you can also specify a date by specifying the date
        inside curly braces <quote>{}</quote>.  You can even access
        a range of changes in the repository using both dates and
        revisions together!</para>
      
      <para>Here are examples of the date formats that Subversion
        accepts.  Remember to use quotes around any date that contains
        spaces.</para>

      <screen>
$ 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}
&hellip;
</screen>
      
      <para>When you specify a date as a revision, Subversion finds
        the most recent revision of the repository as of that
        date:</para>
        
      <screen>
$ svn log --revision {2002-11-28}
------------------------------------------------------------------------
r12 | ira | 2002-11-27 12:31:51 -0600 (Wed, 27 Nov 2002) | 6 lines
&hellip;
</screen>
        
      <sidebar>
        <title>Is Subversion a Day Early?</title>
        
        <para>If you specify a single date as a revision without
          specifying a time of day (for example
          <literal>2002-11-27</literal>), 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 <emphasis>most recent revision of the
          repository</emphasis> as of the date you give.  If you give
          a date without a timestamp, like
          <literal>2002-11-27</literal>, 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.</para>

        <para>If you want to include the 27th in your search, you can
          either specify the 27th with the time (<literal>{"2002-11-27
          23:59"}</literal>), or just specify the next day
          (<literal>{2002-11-28}</literal>).</para>
        
      </sidebar>
      
      <para>You can also use a range of dates.  Subversion will find
        all revisions between both dates, inclusive:</para>
      
      <screen>
$ svn log --revision {2002-11-20}:{2002-11-29}
&hellip;
</screen>
        
      <para>As we pointed out, you can also mix dates and revisions:</para>
      
      <screen>
$ svn log --revision {2002-11-20}:4040
</screen>

      <para>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&mdash;an unversioned, modifiable
        property&mdash;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.</para>
        
    </sect2>
      
  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 4 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-4">
    <title>Initial Checkout</title>

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

    <screen>
$ 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
&hellip;
Checked out revision 2499.
</screen>
    
    <sidebar>
      <title>Repository Layout</title>

      <para>If you're wondering what <literal>trunk</literal> 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 <xref linkend="svn-ch-4"/>.</para>

    </sidebar>

    <para>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:</para>
    
    <screen>
$ 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
&hellip;
Checked out revision 2499.
</screen>
    
    <para>Since Subversion uses a <quote>copy-modify-merge</quote>
      model instead of <quote>lock-modify-unlock</quote> (see <xref
      linkend="svn-ch-2"/>), 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.</para>

      <note>
        <para>While your working copy is <quote>just like any other
          collection of files and directories on your system</quote>,
          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 <command>svn copy</command> or <command>svn
          move</command> instead of the copy and move commands
          provided by your operating system.  We'll talk more about
          them later in this chapter.</para>
      </note>

    <para>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.</para>

    <sidebar>
      <title>What's with the <filename>.svn</filename> directory?</title>

      <para>Every directory in a working copy contains an
        administrative area, a subdirectory named
        <filename>.svn</filename>.  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.</para>

    </sidebar>

    <para>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:</para>
    
    <screen>
$ 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
&hellip;
Checked out revision 2499.
</screen>
    
    <para>That will place your working copy in a directory named
      <literal>subv</literal> instead of a directory named
      <literal>trunk</literal> as we did previously.</para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 5 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-5">
    <title>Basic Work Cycle</title>

    <para>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.</para>
    
    <para>The typical work cycle looks like this:</para>

    <itemizedlist>
      <listitem>
        <para>Update your working copy</para>
        <itemizedlist>
          <listitem>
            <para><command>svn update</command></para>
          </listitem>
        </itemizedlist>
        
      </listitem>
      
      <listitem>
        <para>Make changes</para>
        <itemizedlist>
          <listitem>
            <para><command>svn add</command></para>
          </listitem>
          <listitem>
            <para><command>svn delete</command></para>
          </listitem>
          <listitem>
            <para><command>svn copy</command></para>
          </listitem>
          <listitem>
            <para><command>svn move</command></para>
          </listitem>
        </itemizedlist>
      </listitem>

      <listitem>
        <para>Examine your changes</para>
        <itemizedlist>
          <listitem>
            <para><command>svn status</command></para>
          </listitem>
          <listitem>
            <para><command>svn diff</command></para>
          </listitem>
          <listitem>
            <para><command>svn revert</command></para>
          </listitem>
        </itemizedlist>
      </listitem>

      <listitem>
        <para>Merge others' changes</para>
        <itemizedlist>
          <listitem>
            <para><command>svn merge</command></para>
          </listitem>
          <listitem>
            <para><command>svn resolved</command></para>
          </listitem>
        </itemizedlist>
      </listitem>

      <listitem>
        <para>Commit your changes</para>
        <itemizedlist>
          <listitem>
            <para><command>svn commit</command></para>
          </listitem>
        </itemizedlist>
      </listitem>
    </itemizedlist>

    <sect2 id="svn-ch-3-sect-4.1">
      <title>Update Your Working Copy</title>

      <para>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
        <command>svn update</command> to bring your working copy into
        sync with the latest revision in the repository.</para>
      
      <screen>
$ svn update
U  foo.c
U  bar.c
Updated to revision 2.
</screen>
      
      <para>In this case, someone else checked in modifications to
        both <filename>foo.c</filename> and <filename>bar.c</filename>
        since the last time you updated, and Subversion has updated
        your working copy to include those changes.</para>
      
      <para>Let's examine the output of <command>svn update</command>
        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:</para>

      <variablelist>

        <varlistentry>
          <term><computeroutput>U      foo</computeroutput></term>
          <listitem>
            <para>File <filename>foo</filename> was
              <computeroutput>U</computeroutput>pdated (received changes
              from the server).</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><computeroutput>A      foo</computeroutput></term>
          <listitem>
            <para>File or directory <filename>foo</filename> was
              <computeroutput>A</computeroutput>dded to your working
              copy.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><computeroutput>D      foo</computeroutput></term>
          <listitem>
            <para>File or directory <filename>foo</filename> was
              <computeroutput>D</computeroutput>eleted from your working
              copy.</para>
          </listitem>
        </varlistentry>
        
        <varlistentry>
          <term><computeroutput>R      foo</computeroutput></term>
          <listitem>
            <para>File or directory <filename>foo</filename> was
              <computeroutput>R</computeroutput>eplaced in your working
              copy; that is, <filename>foo</filename> 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.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><computeroutput>G      foo</computeroutput></term>
          <listitem>
            <para>File <filename>foo</filename> 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<computeroutput>G</computeroutput>ed the repository's
              changes into the file without a problem.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><computeroutput>C      foo</computeroutput></term>
          <listitem>
            <para>File <filename>foo</filename> received
              <computeroutput>C</computeroutput>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.</para>
          </listitem>
        </varlistentry>

      </variablelist>

    </sect2>

    <sect2 id="svn-ch-3-sect-4.2">
      <title>Make Changes to Your Working Copy</title>
      
      <para>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 <command>svn add</command>,
        <command>svn delete</command>, <command>svn copy</command>,
        and <command>svn move</command>.  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:</para>
      
      <variablelist>
        
        <varlistentry>
          <term>File changes</term>
          <listitem>
            <para>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.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>Tree changes</term>
          <listitem>
            <para>You can ask Subversion to <quote>mark</quote> 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.</para>
          </listitem>
        </varlistentry>

      </variablelist>
      
      <para>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&mdash;and just as efficiently
        too.</para>
      
      <para>Here is an overview of the four Subversion subcommands
        that you'll use most often to make tree changes (we'll cover
        <command>svn import</command> and <command>svn mkdir</command>
        later).</para>
      
      <variablelist>
        
        <varlistentry>
          <term><command>svn add foo</command></term>
          <listitem>
            <para>Schedule <filename>foo</filename> to be added to the
              repository.  When you next commit,
              <filename>foo</filename> will become a child of its
              parent directory.  Note that if <filename>foo</filename>
              is a directory, everything underneath <filename>foo</filename>
              will be scheduled for addition.  If you only want to
              schedule <filename>foo</filename> itself, pass the
              <option>--non-recursive</option> (<option>-N</option>)
              switch.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><command>svn delete foo</command></term>
          <listitem>
            <para>Schedule <filename>foo</filename> to be deleted from
              the repository.  If <filename>foo</filename> is a file,
              it is immediately deleted from your working copy.  If
              <filename>foo</filename> is a directory, it is not
              deleted, but Subversion schedules it for deletion.  When
              you commit your changes, <filename>foo</filename> will
              be removed from your working copy and the repository.
              <footnote><para>Of course, nothing is ever totally
              deleted from the repository&mdash;just from the
              <literal>HEAD</literal> 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.</para> </footnote></para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><command>svn copy foo bar</command></term>
          <listitem>
            <para>Create a new item <filename>bar</filename> as a
              duplicate of <filename>foo</filename>.
              <filename>bar</filename> is automatically scheduled for
              addition.  When <filename>bar</filename> is added to the
              repository on the next commit, its copy history is
              recorded (as having originally come from
              <filename>foo</filename>).  <command>svn copy</command>
              does not create intermediate directories.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><command>svn move foo bar</command></term>
          <listitem>
            <para>This command is exactly the same as running
              <command>svn copy foo bar; svn delete foo</command>.
              That is, <filename>bar</filename> is scheduled for
              addition as a copy of <filename>foo</filename>, and
              <filename>foo</filename> is scheduled for removal.
              <command>svn move</command> does not create intermediate
              directories.</para>
          </listitem>
        </varlistentry>

      </variablelist>

      <sidebar>
        <title>Changing the Repository Without a Working Copy</title>

        <!-- ### pll - Fri 07 Feb 2003 12:55:07                            -->
        <!-- I find this sidebar rather confusing here, since you really   -->
        <!-- haven't gone through explaining the svn command line syntax   -->
        <!-- anywhere.  Maybe a short section explaining that subversion   -->
        <!-- can be used both in networked and non-networked environments, -->
        <!-- and which types of commands need URLs, etc.  This should      -->
        <!-- probably be in chapter 2 (around the "Subversion in action"   -->
        <!-- though, so that this sidebar makes more sense.                -->
        
        <para>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&mdash;there
          <emphasis>are</emphasis> 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 <command>svn mkdir</command>, <command>svn
          copy</command>, <command>svn move</command>, and
          <command>svn delete</command> can work with URLs.</para>

        <para>URL operations behave in this manner because commands
          that operate on a working copy can use the working copy as a
          sort of <quote>staging area</quote> 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.</para>

      </sidebar>

    </sect2>

    <sect2 id="svn-ch-3-sect-4.3">
      <title>Examine Your Changes</title>
      
      <para>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 <command>svn
        status</command>, <command>svn diff</command>, and
        <command>svn revert</command>.  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.</para>
      
      <!-- pll - Fri 07 Feb 2003 12:55:07                                   -->
      <!-- I find this following paragraph a little unclear.  Mostly for    -->
      <!-- the same reasons as I found the sidebar above unclear.  There    -->
      <!-- hasn't been much discussion of the Subversion architecture, and  -->
      <!-- therefore, nothing has been clearly stated wrt the fact that the -->
      <!-- repository may not be local.                                     -->
      
      <para>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 <quote>pristine</quote> copy of each version
        controlled file within the <filename>.svn</filename> 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.</para>
      
      <sect3 id="svn-ch-3-sect-4.3.1">
        <title><command>svn status</command></title>
        
        <para>You'll probably use the <command>svn status</command>
          command more than any other Subversion command.</para>
        
        <sidebar>
          <title>CVS Users: Hold That Update!</title>
          
          <para>You're probably used to using <command>cvs
            update</command> to see what changes you've made to your
            working copy.  <command>svn status</command> will give you
            all the information you need regarding what has changed in
            your working copy&mdash;without accessing the repository
            or potentially incorporating new changes published by
            other users.</para>
        
          <para>In Subversion, <command>update</command> does just
            that&mdash;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 <command>update</command> command to see what
            local modifications you've made.</para>

        </sidebar>
        
        <para>If you run <command>svn status</command> 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 <command>svn
          status</command> can return.  (Note that the text following
          <literal>#</literal> in the following example is not
          actually printed by <command>svn status</command>.)</para>
      
        <screen>
$ 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
&hellip;
</screen>
      
        <para>In this output format <command>svn status</command>
          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:</para>


        <variablelist>

          <varlistentry>
            <term><computeroutput>A      file_or_dir</computeroutput></term>
            <listitem>
              <para>The file or directory
                <filename>file_or_dir</filename> has been scheduled for
                addition into the repository.
              </para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>C     file</computeroutput></term>
            <listitem>
              <para>The file <filename>file</filename> 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.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>D      file_or_dir</computeroutput></term>
            <listitem>
              <para>The file or directory
                <filename>file_or_dir</filename> has been scheduled for
                deletion from the repository.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>M      file</computeroutput></term>
            <listitem>
              <para>The contents of the file <filename>file</filename> have
                been modified.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>X      dir</computeroutput></term>
            <listitem>
              <para>The directory <filename>dir</filename> is
                unversioned, but is related to a Subversion externals
                definition.  To find out more about externals
                definitions, see <xref linkend="svn-ch-7-sect-3"/>.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>?      file_or_dir</computeroutput></term>
            <listitem>
              <para>The file or directory
                <filename>file_or_dir</filename> is not under version
                control.  You can silence the question marks by either
                passing the <option>--quiet</option>
                (<option>-q</option>) switch to <command>svn
                status</command>, or by setting the
                <literal>svn:ignore</literal> property on the parent
                directory.  For more information on ignored files, see
                <xref linkend="svn-ch-7-sect-2.3.3" />.</para>

            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>!      file_or_dir</computeroutput></term>
            <listitem>
              <para>The file or directory
                <filename>file_or_dir</filename> 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 <command>svn
                update</command> will refetch the file or directory
                from the repository, or <command>svn revert
                file</command> will restore a missing file.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>~     file_or_dir</computeroutput></term>
            <listitem>
              <para>The file or directory
                <filename>file_or_dir</filename> 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
                <command>svn delete</command> or <command>svn add</command>
                commands.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term><computeroutput>I      file_or_dir</computeroutput></term>
            <listitem>
              <para>Subversion is <quote>ignoring</quote> the file or
                directory <filename>file_or_dir</filename>, probably
                because you told it to.  For more information on ignored
                files, see <xref linkend="svn-ch-7-sect-2.3.3"/>.
                Note that this symbol only shows up if you pass the
                <option>--no-ignore</option> option to <command>svn
                status</command>.</para>
            </listitem>
          </varlistentry>

        </variablelist>

        <para>The second column tells the status of a file or
          directory's properties (see <xref
          linkend="svn-ch-7-sect-2"></xref> for more information on
          properties).  If an <computeroutput>M</computeroutput>
          appears in the second column, then the properties have been
          modified, otherwise a whitespace will be printed.</para>
        
        <para>The third column will only show whitespace or an
          <computeroutput>L</computeroutput> which means that
          Subversion has locked the item in
          the <filename>.svn</filename> working area.  You will see an
          <computeroutput>L</computeroutput> if you run <command>svn
          status</command> in a directory where an <command>svn
          commit</command> is in progress&mdash;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 <command>svn cleanup</command>
          (more about that later in this chapter).</para>
        
        <para>The fourth column will only show whitespace or a
          <computeroutput>+</computeroutput> which means that the file
          or directory is scheduled to be added or modified with
          additional attached history.  This typically happens when you
          <command>svn move</command> or <command>svn copy</command> a file
          or directory.  If you see
          <computeroutput>A&nbsp;&nbsp;+</computeroutput>, this means
          the item is scheduled for addition-with-history.  It could be
          a file, or the root of a copied directory.
          <computeroutput>+</computeroutput>
          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.
          <computeroutput>M&nbsp;&nbsp;+</computeroutput> means the item
          is part of a subtree scheduled for addition-with-history,
          <emphasis>and</emphasis> 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.</para>

        <para>The fifth column will only show whitespace or an
          <computeroutput>S</computeroutput>.  This signifies that the
          file or directory has been switched from the path of the
          rest of the working copy (using <command>svn
          switch</command>) to a branch.</para>
        
        <para>If you pass a specific path to <command>svn
          status</command>, it gives you information about that item
          alone:</para>
        
        <screen>
$ svn status stuff/fish.c
D      stuff/fish.c
</screen>
        
        <para><command>svn status</command> also has a
          <option>--verbose</option> (<option>-v</option>) switch,
          which will show you the status of <emphasis>every</emphasis>
          item in your working copy, even if it has not been
          changed:</para>
           
        <screen>
$ 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
</screen>
           
        <para>This is the <quote>long form</quote> output of
          <command>svn status</command>.  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.</para>

        <para>None of the above invocations to <command>svn
          status</command> contact the repository, they work only
          locally by comparing the metadata in the
          <filename>.svn</filename> directory with the working copy.
          Finally, there is the <option>--show-updates</option>
          (<option>-u</option>) switch, which contacts the repository
          and adds information about things that are
          out-of-date:</para>
      
        <screen>
$ 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
</screen>
           
        <para>Notice the two asterisks: if you were to run
          <command>svn update</command> at this point, you would
          receive changes to <filename>README</filename>
          and <filename>trout.c</filename>.  This tells you some very
          useful information&mdash;you'll need to update and get the
          server changes on <filename>README</filename> before you
          commit, or the repository will reject your commit for being
          out-of-date.  (More on this subject later.)</para>

      </sect3>

      <sect3 id="svn-ch-3-sect-4.3.2">
        <title><command>svn diff</command></title>
        
        <para>Another way to examine your changes is with the
          <command>svn diff</command> command.  You can find out
          <emphasis>exactly</emphasis> how you've modified things by
          running <command>svn diff</command> with no arguments, which
          prints out file changes in unified diff
          format:<footnote><para>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 <option>--diff-cmd</option> and
          pass any flags you'd like to it using the
          <option>--extensions</option> switch.  For example, to see
          local differences in file <filename>foo.c</filename> in
          context output format while ignoring whitespace changes, you
          might run <command>svn diff --diff-cmd /usr/bin/diff
          --extensions '-bc' foo.c</command>.</para>
          </footnote></para>
        
        <screen>
$ svn diff
Index: bar.c
===================================================================
--- bar.c	(revision 3)
+++ bar.c	(working copy)
@@ -1,7 +1,12 @@
+#include &lt;sys/types.h&gt;
+#include &lt;sys/stat.h&gt;
+#include &lt;unistd.h&gt;
+
+#include &lt;stdio.h&gt;

 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.
</screen>
        
        <para>The <command>svn diff</command> command produces this
          output by comparing your working files against the cached
          <quote>pristine</quote> copies within the
          <filename>.svn</filename> area.  Files scheduled for
          addition are displayed as all added-text, and files
          scheduled for deletion are displayed as all deleted
          text.</para>

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

        <screen>
$ svn diff &gt; patchfile
</screen>

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

      </sect3>

      <sect3 id="svn-ch-3-sect-4.3.3">
        <title><command>svn revert</command></title>

        <para>Now suppose you see the above diff output, and realize
          that your changes to <filename>README</filename> are a
          mistake; perhaps you accidentally typed that text into the
          wrong file in your editor.</para>
      
        <para>This is a perfect opportunity to use <command>svn
          revert</command>.</para>
           
        <screen>
$ svn revert README
Reverted 'README'
</screen>
        
        <para>Subversion reverts the file to its pre-modified state by
          overwriting it with the cached <quote>pristine</quote> copy
          from the <filename>.svn</filename> area.  But also note that
          <command>svn revert</command> can undo
          <emphasis>any</emphasis> scheduled operations&mdash;for
          example, you might decide that you don't want to add a new
          file after all:</para>

        <screen>
$ svn status foo
?      foo

$ svn add foo
A         foo

$ svn revert foo
Reverted 'foo'

$ svn status foo
?      foo
</screen>

        <note>
          <para><command>svn revert</command>
          <replaceable>ITEM</replaceable> has exactly the same effect as
          deleting <replaceable>ITEM</replaceable> from your working
          copy and then running <command>svn update -r BASE</command>
          <replaceable>ITEM</replaceable>.  However, if you're reverting
          a file, <command>svn revert</command> has one very noticeable
          difference&mdash;it doesn't have to communicate with the
          repository to restore your file.</para>
        </note>

        <para>Or perhaps you mistakenly removed a file from version
          control:</para>

        <screen>
$ svn status README 
       README

$ svn delete README 
D         README

$ svn revert README
Reverted 'README'

$ svn status README
       README
</screen>

      </sect3>

      <sidebar>
          <title>Look Ma! No Network!</title>

        <para>All three of these commands (<command>svn
          status</command>, <command>svn diff</command>, and
          <command>svn revert</command>) 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.</para>

        <para>Subversion does this by keeping private caches of
          pristine versions of each versioned file inside of the
          <filename>.svn</filename> administrative areas.  This allows
          Subversion to report&mdash;and revert&mdash;local
          modifications to those files <emphasis>without network
          access</emphasis>.  This cache (called the
          <quote>text-base</quote>) also allows Subversion to send the
          user's local modifications during a commit to the server as
          a compressed <firstterm>delta</firstterm> (or
          <quote>difference</quote>) against the pristine version.
          Having this cache is a tremendous benefit&mdash;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!</para>
    </sidebar>

    </sect2>

    <sect2 id="svn-ch-3-sect-4.4">
      <title>Resolve Conflicts (Merging Others' Changes)</title>
           
      <para>We've already seen how <command>svn status -u</command>
          can predict conflicts.  Suppose you run <command>svn
          update</command> and some interesting things occur:</para>
      
      <screen>
$ svn update
U  INSTALL
G  README
C  bar.c
Updated to revision 46.
</screen>
           
      <para>The <computeroutput>U</computeroutput> and
        <computeroutput>G</computeroutput> codes are no cause for
        concern; those files cleanly absorbed changes from the
        repository.  The files marked with
        <computeroutput>U</computeroutput> contained no local changes
        but were <computeroutput>U</computeroutput>pdated with changes
        from the repository.  The <computeroutput>G</computeroutput>
        stands for mer<computeroutput>G</computeroutput>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.</para>
           
      <para>But the <computeroutput>C</computeroutput> stands for
        conflict.  This means that the changes from the server overlapped
        with your own, and now you have to manually choose between
        them.</para>
           
      <para>Whenever a conflict occurs, three things occur to assist
        you in noticing and resolving that conflict:</para>
           
      <itemizedlist>

        <listitem>
          <para>Subversion prints a <computeroutput>C</computeroutput>
            during the update, and remembers that the file is in a
            state of conflict.</para>
        </listitem>

        <listitem>
          <para>Subversion places <firstterm>conflict
            markers</firstterm>&mdash;special strings of text which
            delimit the <quote>sides</quote> of the
            conflict&mdash;into the file to visibly demonstrate the
            overlapping areas.</para>
        </listitem>

        <listitem>
          <para>For every conflicted file, Subversion places three
            extra files in your working copy:</para>

          <variablelist>
            
            <varlistentry>
              <term><filename>filename.mine</filename></term>
              <listitem>
                <para> This is your file as it existed in your working
                  copy before you updated your working copy&mdash;that
                  is, without conflict markers.  This file has your
                  latest changes in it and nothing else.</para>
              </listitem>
            </varlistentry>
            
            <varlistentry>
              <term><filename>filename.rOLDREV</filename></term>
              <listitem>
                <para>This is the file that was the
                  <literal>BASE</literal> revision before you updated
                  your working copy.  That is, the file that you
                  checked out before you made your latest
                  edits.</para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><filename>filename.rNEWREV</filename></term>
              <listitem>
                <para>This is the file that your Subversion client
                  just received from the server when you updated your
                  working copy.  This file corresponds to the
                  <literal>HEAD</literal> revision of the
                  repository.</para>
              </listitem>
            </varlistentry>

          </variablelist>
          
          <para>Here <literal>OLDREV</literal> is the revision number
            of the file in your <filename>.svn</filename> directory
            and <literal>NEWREV</literal> is the revision number of
            the repository <literal>HEAD</literal>.
          </para>
        </listitem>
        
      </itemizedlist>
      
      <para>For example, Sally makes changes to the file
        <filename>sandwich.txt</filename> 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:</para>
      
      <screen>
$ svn update
C  sandwich.txt
Updated to revision 2.
$ ls -1
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2
</screen>
      <!-- ###TODO What happens if the revnum is gt 99999?-->
      
      <para>At this point, Subversion will <emphasis>not</emphasis>
        allow you to commit the file <filename>sandwich.txt</filename>
        until the three temporary files are removed.</para>

      <screen>
$ 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
</screen>

      <para>If you get a conflict, you need to do one of three
        things:</para>

        <itemizedlist>

          <listitem>
            <para>Merge the conflicted text <quote>by hand</quote> (by
              examining and editing the conflict markers within the
              file).
            </para>
          </listitem>

          <listitem>
            <para>Copy one of the temporary files on top of your
        working file.
            </para>
          </listitem>

          <listitem>
            <para>Run <command>svn revert &lt;filename&gt;</command>
              to throw away all of your local changes.</para>
          </listitem>

        </itemizedlist>

      <para>Once you've resolved the conflict, you need to let
        Subversion know by running <command>svn resolved</command>.
        This removes the three temporary files and Subversion no
        longer considers the file to be in a state of
        conflict.<footnote><para>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.</para>
        </footnote></para>

      <screen>
$ svn resolved sandwich.txt
Resolved conflicted state of 'sandwich.txt'
</screen>

      <sect3 id="svn-ch-3-sect-4.4.1">
        <title>Merging Conflicts by Hand</title>

        <para>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.</para>

        <para>Here's an example.  Due to a miscommunication, you and
          Sally, your collaborator, both edit the file
          <filename>sandwich.txt</filename> 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
          <filename>sandwich.txt</filename> to resolve the conflicts.
          First, let's take a look at the file:</para>

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

        <para>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:</para>

        <screen>
&lt;&lt;&lt;&lt;&lt;&lt;&lt; .mine
Salami
Mortadella
Prosciutto
=======
</screen>

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

        <screen>
=======
Sauerkraut
Grilled Chicken
&gt;&gt;&gt;&gt;&gt;&gt;&gt; .r2
</screen>

        <para>Usually you won't want to just delete the conflict
          markers and Sally's changes&mdash;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.<footnote><para>And if you
          ask them for it, they may very well ride you out of town on
          a rail.</para></footnote> Once you've agreed on the changes
          you will check in, edit your file and remove the conflict
          markers.</para>

        <screen>
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread
</screen>

        <para>Now run <command>svn resolved</command>, and you're
          ready to commit your changes:</para>

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

        <para>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&mdash;including your file as it was before you updated.
          You can even use a third-party interactive merging tool to
          examine those three files.</para>

      </sect3>

      <sect3 id="svn-ch-3-sect-4.4.2">
        <title>Copying a File Onto Your Working File</title>

        <para>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:</para>

        <screen>
$ 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
</screen>

      </sect3>

      <sect3 id="svn-ch-3-sect-4.4.3">
        <title>Punting: Using <command>svn revert</command></title>

        <para>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:</para>

        <screen>
$ svn revert sandwich.txt
Reverted 'sandwich.txt'
$ ls sandwich.*
sandwich.txt
</screen>

        <para>Note that when you revert a conflicted file, you don't
        have to run <command>svn resolved</command>.</para>

      </sect3>

      <para>Now you're ready to check in your changes.  Note that
        <command>svn resolved</command>, 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
        <command>svn resolved</command> when you're certain that you've
        fixed the conflict in your file&mdash;once the temporary files
        are removed, Subversion will let you commit the file even if
        it still contains conflict markers.</para>
      
    </sect2>
    
    <sect2 id="svn-ch-3-sect-4.5">
      <title>Commit Your Changes</title>
      
      <para>Finally!  Your edits are finished, you've merged all
        changes from the server, and you're ready to commit your
        changes to the repository.</para>
      
      <para>The <command>svn commit</command> command sends all of
           your changes to the repository.  When you commit a change,
           you need to supply a <firstterm>log message</firstterm>,
           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 <option>--message</option> (or
           <option>-m</option>) option:</para>
           
      <screen>
$ svn commit --message "Corrected number of cheese slices."
Sending        sandwich.txt
Transmitting file data .
Committed revision 3.
</screen>
           
      <para>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
        <option>--file</option> switch:</para>

      <screen>
$ svn commit --file logmsg 
Sending        sandwich
Transmitting file data .
Committed revision 4.
</screen>

      <para>If you fail to specify either the
        <option>--message</option> or <option>--file</option> switch,
        then Subversion will automatically launch your favorite editor
        (as defined in the environment variable
        <literal>$EDITOR</literal>) for composing a log
        message.</para>
        
        
      <tip>
        <para>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.</para>

        <screen>
$ svn commit
Waiting for Emacs...Done

Log message unchanged or not specified
a)bort, c)ontinue, e)dit
a
$
</screen>
      </tip>

      <para>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 <emphasis>has</emphasis> done
        that, the entire commit will fail with a message informing you
        that one or more of your files is out-of-date:</para>

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

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

           
      <para>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.</para>

    </sect2>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 6 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-6">
    <title>Examining History</title>

    <para>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 <emphasis>peer
      into</emphasis> the past instead of <emphasis>going
      into</emphasis> the past.</para>
           
    <para>There are several commands that can provide you with
      historical data from the repository:</para>

      <variablelist>

        <varlistentry>
          <term><command>svn log </command></term>
          <listitem>
            <para>Shows you broad information: log messages attached
              to revisions, and which paths changed in each
              revision.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><command>svn diff </command></term>
          <listitem>
            <para>Shows you the specific details of how a file changed
              over time.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><command>svn cat </command></term>
          <listitem>
            <para>This is used to retrieve any file as it existed in a
              particular revision number and display it on your
              screen.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term><command>svn list </command></term>
          <listitem>
            <para>Displays the files in a directory for any given
              revision.</para>
          </listitem>
        </varlistentry>

      </variablelist>


    <sect2 id="svn-ch-3-sect-5.1">
      <title><command>svn log</command></title>

      <para>To find out information about the history of a file or
        directory, use the <command>svn log</command>
        command. <command>svn log</command> 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.</para>
           
      <screen>
$ 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
------------------------------------------------------------------------
</screen>
           
      <para>Note that the log messages are printed in
        <emphasis>reverse chronological order</emphasis> by default.
        If you wish to see a different range of revisions in a
        particular order, or just a single revision, pass the
        <option>--revision</option> (<option>-r</option>)
        switch:</para>
           
      <screen>
$ 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
</screen>
        
      <para>You can also examine the log history of a single file or directory.
      For example:</para>
           
      <screen>
$ svn log foo.c
&hellip;
$ svn log http://foo.com/svn/trunk/code/foo.c
&hellip;
</screen>
           
      <para>These will display log messages <emphasis>only</emphasis>
        for those revisions in which the working file (or URL)
        changed.</para>
           
      <para>If you want even more information about a file or
        directory, <command>svn log</command> also takes a
        <option>--verbose</option> (<option>-v</option>) 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, <command>svn
        log</command> will include a list of changed paths in a
        revision in its output:</para>

      <screen>
$ 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.

------------------------------------------------------------------------
</screen>

      <sidebar>
        <title>Why Does <command>svn log</command> Give Me an Empty
          Response?</title>
        
        <para>After working with Subversion for a bit, most users will
          come across something like this:</para>

        <screen>
$ svn log -r 2
------------------------------------------------------------------------
$
</screen>

        <para>At first glance, this seems like an error.  But recall
          that while revisions are repository-wide, <command>svn
          log</command> 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 <command>svn log</command> directly at the top-most
          URL of your repository, as in <command>svn log -r 2
          http://svn.collab.net/repos/svn</command>.</para>

      </sidebar>
           
    </sect2>

    <sect2 id="svn-ch-3-sect-5.2">
      <title>svn diff</title>

      <para>We've already seen <command>svn diff</command>
        before&mdash;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.</para>
      
      <para>In fact, it turns out that there are
        <emphasis>three</emphasis> distinct uses of <command>svn
          diff</command>:</para>

      <itemizedlist>

        <listitem>
          <para>Examine local changes</para>
        </listitem>

        <listitem>
          <para>Compare your working copy to the repository</para>
        </listitem>

        <listitem>
          <para>Compare repository to repository</para>
        </listitem>

      </itemizedlist>
      
      <sect3 id="svn-ch-3-sect-5.2.1">
        <title>Examining Local Changes</title>

        <para>As we've seen, invoking <command>svn diff</command> with
          no switches will compare your working files to the cached
          <quote>pristine</quote> copies in
          the <filename>.svn</filename> area:</para>
        
        <screen>
$ 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
$
</screen>
        
      </sect3>

      <sect3 id="svn-ch-3-sect-5.2.2">
        <title>Comparing Working Copy to Repository</title>

        <para>If a single <option>--revision</option>
          (<option>-r</option>) number is passed, then your
          working copy is compared to the specified revision in the
          repository.</para>
          
        <screen>
$ 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
$
</screen>
          
      </sect3>

      <sect3 id="svn-ch-3-sect-5.2.3">
        <title>Comparing Repository to Repository</title>
        
        <para>If two revision numbers, separated by a colon, are
          passed via <option>--revision</option>
          (<option>-r</option>), then the two revisions are directly
          compared.</para>
          
        <screen>
$ 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 
$
</screen>
          
        <para>Not only can you use <command>svn diff</command> 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:</para>
           
        <screen>
$ svn diff --revision 4:5 http://svn.red-bean.com/repos/example/trunk/text/rules.txt
&hellip;
$
</screen>

      </sect3>

    </sect2>

    <sect2 id="svn-ch-3-sect-5.3">
       <title><command>svn cat</command></title>

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

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

      <para>You can also redirect the output directly into a
        file:</para>

      <screen>
$ svn cat --revision 2 rules.txt &gt; rules.txt.v2
$
</screen>

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

      <para>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.</para>

      <para>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.</para>

      </sect2>

    <sect2 id="svn-ch-3-sect-5.4">
      <title><command>svn list</command></title>
      
      <para>The <command>svn list</command> command shows you what
        files are in a repository directory without actually
        downloading the files to your local machine:</para>
      
      <screen>
$ svn list http://svn.collab.net/repos/svn
README
branches/
clients/
tags/
trunk/
</screen>

      <para>If you want a more detailed listing, pass the
        <option>--verbose</option> (<option>-v</option>) flag to get
        output like this.</para>

      <screen>
$ 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/
</screen>

      <para>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.</para>
 
    </sect2>

    <sect2 id="svn-ch-3-sect-5.5">
      <title>A Final Word on History</title>

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

      <screen>
$ svn checkout --revision 1729 # Checks out a new working copy at r1729
&hellip;
$ svn update --revision 1729 # Updates an existing working copy to r1729
&hellip;
</screen>

    </sect2>

  </sect1>


  <!-- ================================================================= -->
  <!-- ======================== SECTION 7 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-7">
    <title>Other Useful Commands</title>

      <para>While not as frequently used as the commands previously
      discussed in this chapter, you will occasionally need these
      commands.</para>

    <sect2 id="svn-ch-3-sect-7.1">
      <title><command>svn cleanup</command></title>

      <para>When Subversion modifies your working copy (or any
        information within <filename>.svn</filename>), 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.</para>

      <para>And this is exactly what <command>svn cleanup</command>
        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
        <quote>locked</quote>, then this is the command that you
        should run.  Also, <command>svn status</command> will display
        an <literal>L</literal> next to locked items:</para>

      <screen>
$ svn status
  L    somedir
M      somedir/foo.c 

$ svn cleanup
$ svn status
M      somedir/foo.c
</screen>

    </sect2>


    <sect2 id="svn-ch-3-sect-7.3">
      <title><command>svn import</command></title>

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

      <screen>
$ 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.
</screen>

      <para>The previous example copied the contents of directory
        <filename>mytree</filename> under the directory
        <filename>some/project</filename> in the repository:</para>

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

      <para>Note that after the import is finished, the original tree
        is <emphasis>not</emphasis> converted into a working copy.  To
        start working, you still need to <command>svn
        checkout</command> a fresh working copy of the tree.</para>

    </sect2>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 8 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ch-3-sect-8">
    <title>Summary</title>
        
      <para>Now we've covered most of the Subversion client
          commands.  Notable exceptions are those dealing with
          branching and merging (see <xref linkend="svn-ch-4"/>) and
          properties (see <xref linkend="svn-ch-7-sect-2"/>).
          However, you may want to take a moment to skim through <xref
          linkend="svn-ch-9"/> to get an idea of all the many
          different commands that Subversion has&mdash;and how you can
          use them to make your work easier.</para>

  </sect1>

</chapter>

<!--
local variables: 
sgml-parent-document: ("book.xml" "chapter")
end:
-->
