<appendix id="svn-ap-a">
  <title>Subversion for CVS Users</title>

  <simplesect>

    <para>This appendix is a guide for CVS users new to Subversion.
      It's essentially a list of differences between the two systems
      as <quote>viewed from 10,000 feet</quote>. For each section, we
      provide backreferences to relevant chapters when
      possible.</para>

    <para>Although the goal of Subversion is to take over the current
      and future CVS user base, some new features and design changes
      were required to fix certain <quote>broken</quote> behaviors
      that CVS had.  This means that, as a CVS user, you may need to
      break habits&mdash;ones that you forgot were odd to begin
      with.</para>

  </simplesect>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 1 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-1">
    <title>Revision Numbers Are Different Now</title>

    <para>In CVS, revision numbers are per-file.  This is because CVS
      uses RCS as a backend; each file has a corresponding RCS file in
      the repository, and the repository is roughly laid out according
      to the structure of your project tree.</para>

    <para>In Subversion, the repository looks like a single
      filesystem.  Each commit results in an entirely new filesystem
      tree; in essence, the repository is an array of trees.  Each of
      these trees is labeled with a single revision number.  When
      someone talks about <quote>revision 54</quote>, they're talking
      about a particular tree (and indirectly, the way the filesystem
      looked after the 54th commit).</para>

    <para>Technically, it's not valid to talk about <quote>revision 5
      of <filename>foo.c</filename></quote>.  Instead, one would say
      <quote><filename>foo.c</filename> as it appears in revision
      5</quote>. Also, be careful when making assumptions about the
      evolution of a file.  In CVS, revisions 5 and 6 of
      <filename>foo.c</filename> are always different.  In Subversion,
      it's most likely that <filename>foo.c</filename> did
      <emphasis>not</emphasis> change between revisions 5 and
      6.</para>

    <para>For more details on this topic, see <xref
    linkend="svn-ch-2-sect-3.2" />.</para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 2 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-2">
    <title>Directory Versions</title>
    
    <para>Subversion tracks tree structures, not just file contents.
      It's one of the biggest reasons Subversion was written to
      replace CVS.</para>

    <para>Here's what this means to you, as a former CVS user:</para>

    <itemizedlist>
      <listitem>
        <para>The <command>svn add</command> and <command>svn
          delete</command> commands work on directories now, just as
          they work on files.  So do <command>svn copy</command> and
          <command>svn move</command>.  However, these commands do
          <emphasis>not</emphasis> cause any kind of immediate change
          in the repository.  Instead, the working items are simply
          <quote>scheduled</quote> for addition or deletion.  No
          repository changes happen until you run <command>svn
          commit</command>.</para>
      </listitem>
      <listitem>
        <para>Directories aren't dumb containers anymore; they have
          revision numbers like files.  (Or more properly, it's
          correct to talk about <quote>directory
          <filename>foo/</filename> in revision 5</quote>.)</para>
      </listitem>
    </itemizedlist>

    <para>Let's talk more about that last point.  Directory versioning
      is a hard problem; because we want to allow mixed-revision
      working copies, there are some limitations on how far we can
      abuse this model.</para>

    <para>From a theoretical point of view, we define <quote>revision
      5 of directory <filename>foo</filename></quote> to mean a
      specific collection of directory-entries and properties.  Now
      suppose we start adding and removing files from
      <filename>foo</filename>, and then commit.  It would be a lie
      to say that we still have revision 5 of
      <filename>foo</filename>.  However, if we bumped
      <filename>foo</filename>'s revision number after the commit,
      that would be a lie too; there may be other changes to
      <filename>foo</filename> we haven't yet received, because we
      haven't updated yet.</para>
    
    <para>Subversion deals with this problem by quietly tracking
      committed adds and deletes in the <filename>.svn</filename>
      area.  When you eventually run <command>svn update</command>,
      all accounts are settled with the repository, and the
      directory's new revision number is set correctly.
      <emphasis>Therefore, only after an update is it truly safe to
      say that you have a <quote>perfect</quote> revision of a
      directory.</emphasis> Most of the time, your working copy will
      contain <quote>imperfect</quote> directory revisions.</para>
    
    <para>Similarly, a problem arises if you attempt to commit
      property changes on a directory.  Normally, the commit would
      bump the working directory's local revision number.  But again,
      that would be a lie, because there may be adds or deletes that
      the directory doesn't yet have, because no update has happened.
      <emphasis>Therefore, you are not allowed to commit
      property-changes on a directory unless the directory is
      up-to-date.</emphasis></para>

    <para>For more discussion about the limitations of directory
      versioning, see <xref linkend="svn-ch-2-sect-3.4"/>.</para>

  </sect1>


  <!-- ================================================================= -->
  <!-- ======================== SECTION 3 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-3">
    <title>More Disconnected Operations</title>

    <para>In recent years, disk space has become outrageously cheap
      and abundant, but network bandwidth has not.  Therefore, the
      Subversion working copy has been optimized around the scarcer
      resource.</para>

    <para>The <filename>.svn</filename> administrative directory
      serves the same purpose as the <filename>CVS</filename>
      directory, except that it also stores read-only,
      <quote>pristine</quote> copies of your files.  This allows you
      to do many things off-line:</para>
    
    <variablelist>
      
      <varlistentry>
        <term><command>svn status</command></term>
        <listitem>
          <para>Shows you any local changes you've made (see <xref
              linkend="svn-ch-3-sect-4.3.1"/>)</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><command>svn diff</command></term>
        <listitem>
          <para>Shows you the details of your changes (see <xref
              linkend="svn-ch-3-sect-4.3.2"/>)</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><command>svn revert</command></term>
        <listitem>
          <para>Removes your local changes (see <xref
              linkend="svn-ch-3-sect-4.3.3"/>)</para>
        </listitem>
      </varlistentry>

    </variablelist>

    <para>Also, the cached pristine files allow the Subversion client
      to send differences when committing, which CVS cannot do.</para>

    <para>The last subcommand in the list is new; it will not only
      remove local mods, but it will un-schedule operations such as
      adds and deletes.  It's the preferred way to revert a file;
      running <command>rm file; svn update</command> will still work, but
      it blurs the purpose of updating.  And, while we're on this
      subject&hellip;

    </para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 4 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-4">
    <title>Distinction Between Status and Update</title>

    <para>In Subversion, we've tried to erase a lot of the confusion
      between the <command>cvs status</command> and
      <command>cvs update</command> commands.</para>

    <para>The <command>cvs status</command> command has two purposes:
      first, to show the user any local modifications in the working
      copy, and second, to show the user which files are out-of-date.
      Unfortunately, because of CVS's hard-to-read status output, many
      CVS users don't take advantage of this command at all.  Instead,
      they've developed a habit of running <command>cvs update</command>
      or <command>cvs update -n</command> to quickly see their mods.  If
      users forget to use the <option>-n</option> option, this has the
      side effect of merging repository changes they may not be ready
      to deal with.</para>

    <para>With Subversion, we've tried to remove this muddle by making
      the output of <command>svn status</command> easy to read for
      both humans and parsers.  Also, <command>svn update</command>
      only prints information about files that are updated,
      <emphasis>not</emphasis> local modifications.</para>

    <para><command>svn status</command> prints all files that have
      local modifications.  By default, the repository is not
      contacted.  While this subcommand accepts a fair number of
      options, the following are the most commonly used ones:</para>

    <variablelist>
      <varlistentry>
        <term><option>-u</option></term>
        <listitem>
          <para>Contact the repository to determine, and then display,
            out-of-dateness information.</para>
        </listitem>
      </varlistentry>
      
      <varlistentry>
        <term><option>-v</option></term>
        <listitem>
          <para>Show <emphasis>all</emphasis> entries under
            version control.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><option>-N</option></term>
        <listitem>
          <para>Run non-recursively (do not descend into
            subdirectories).</para>
        </listitem>
      </varlistentry>
    </variablelist>

    <para>The <command>status</command> command has two output
      formats.  In the default <quote>short</quote> format, local
      modifications look like this:</para>

    <screen>
% svn status
M     ./foo.c
M     ./bar/baz.c
</screen>

    <para>If you specify the <option>--show-updates</option>
      (<option>-u</option>) switch, a longer output format is
      used:</para>

    <screen>
% svn status -u
M             1047    ./foo.c
       *      1045    ./faces.html
       *         -    ./bloo.png
M             1050    ./bar/baz.c
Status against revision:   1066
</screen>

    <para>In this case, two new columns appear.  The second column
      contains an asterisk if the file or directory is out-of-date.
      The third column shows the working-copy's revision number of the
      item.  In the example above, the asterisk indicates that
      <filename>faces.html</filename> would be patched if we updated,
      and that <filename>bloo.png</filename> is a newly added file in
      the repository.  (The <command>-</command> next to
      <filename>bloo.png</filename> means that it doesn't yet exist in
      the working copy.)</para>

    <!-- ###TODO describe -u here as well as -uv. -u and -v use
         different <quote>long</quote> formats and need to be
         documented separately. Moreover, as you can combine -u and
         -v, it needs to be explained what each of them does. As -u is
         much more important than -v, and the example following that
         paragraph *is* about -u, not -v, my patch concentrated on
         that. -->

    <para>Lastly, here's a quick summary of the most common status codes that
      you may see:</para>

    <screen>
A    Resource is scheduled for Addition
D    Resource is scheduled for Deletion
M    Resource has local modifications
C    Resource has conflicts (changes have not been completely merged
       between the repository and working copy version)
X    Resource is external to this working copy (comes from another
       repository.  See <xref linkend="svn-ch-7-sect-2.3.6" />)
?    Resource is not under version control
!    Resource is missing or incomplete (removed by another tool than
       Subversion)
</screen>

    <!-- ###TODO:  This paragraph should be moved elsewhere.  We are
                   talking about status codes here, and not update.
                   Although CVS uses update as a form of status... -->
    <para>Subversion has combined the CVS <command>P</command> and
      <command>U</command> codes into just <command>U</command>.  When
      a merge or conflict occurs, Subversion simply prints
      <command>G</command> or <command>C</command>, rather than a
      whole sentence about it.</para>

    <para>For a more detailed discussion of <command>svn
    status</command>, see <xref linkend="svn-ch-3-sect-4.3.1" />.</para>


  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 5 ============================= -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-5">
    <title>Branches and Tags</title>

    <para>Subversion doesn't distinguish between filesystem space and
      <quote>branch</quote> space; branches and tags are ordinary
      directories within the filesystem.  This is probably the single
      biggest mental hurdle a CVS user will need to climb.  Read all
      about it in <xref linkend="svn-ch-4"/>.</para>


    <warning>
      <para>Since Subversion treats branches and tags as ordinary
      directories, always remember to check out the
      <literal>trunk</literal>
      (<literal>http://svn.example.com/repos/calc/trunk/</literal>) of
      your project, and not the project itself
      (<literal>http://svn.example.com/repos/calc/</literal>).  If you
      make the mistake of checking out the project itself, you'll wind
      up with a working copy that contains a copy of your project for
      every branch and tag you have.<footnote><para>That is, providing
      you don't run out of disk space before your checkout
      finishes.</para> </footnote></para>
    </warning>

  </sect1>


  <!-- ================================================================= -->
  <!-- ======================== SECTION 6 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-6">
    <title>Metadata Properties</title>

    <para>A new feature of Subversion is that you can attach arbitrary
      metadata (or <quote>properties</quote>) to files and
      directories.  Properties are arbitrary name/value pairs
      associated with files and directories in your working
      copy.</para>
    
    <para>To set or get a property name, use the <command>svn
      propset</command> and <command>svn propget</command>
      subcommands.  To list all properties on an object, use
      <command>svn proplist</command>.</para>

    <para>For more information, see <xref linkend="svn-ch-7-sect-2"/>.</para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 7 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-7">
    <title>Conflict Resolution</title>

    <para>CVS marks conflicts with in-line <quote>conflict
      markers</quote>, and prints a <command>C</command> during an
      update.  Historically, this has caused problems, because CVS
      isn't doing enough.  Many users forget about (or don't see) the
      <command>C</command> after it whizzes by on their terminal.
      They often forget that the conflict-markers are even present,
      and then accidentally commit files containing
      conflict-markers.</para>

    <para>Subversion solves this problem by making conflicts more
      tangible.  It remembers that a file is in a state of conflict,
      and won't allow you to commit your changes until you run
      <command>svn resolved</command>.  See <xref
      linkend="svn-ch-3-sect-4.4"/> for more details.</para>
  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 8 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-8">
    <title>Binary Files and Translation</title>

    <para>In the most general sense, Subversion handles binary files
      more gracefully than CVS does.  Because CVS uses RCS, it can
      only store successive full copies of a changing binary file.
      But internally, Subversion expresses differences between files
      using a binary-differencing algorithm, regardless of whether they
      contain textual or binary data.  That means that all files are
      stored differentially (compressed) in the repository, and small
      differences are always sent over the network.</para>
    
    <para>CVS users have to mark binary files with
      <option>-kb</option> flags, to prevent data from being garbled
      (due to keyword expansion and line-ending translations).  They
      sometimes forget to do this.</para>

    <para>Subversion takes the more paranoid route: first, it never
      performs any kind of keyword or line-ending translation unless
      you explicitly ask it do so (see <xref
      linkend="svn-ch-7-sect-2.3.4"/> and <xref
      linkend="svn-ch-7-sect-2.3.5"/> for more details).  By default,
      Subversion treats all file data as literal byte strings, and
      files are always stored in the repository in an untranslated
      state.</para>

    <para>Second, Subversion maintains an internal notion of whether a
      file is <quote>text</quote> or <quote>binary</quote> data, but
      this notion is <emphasis>only</emphasis> extant in the working
      copy.  During an <command>svn update</command>, Subversion will
      perform contextual merges on locally modified text files, but
      will not attempt to do so for binary files.</para>

    <para>To determine whether a contextual merge is possible,
      Subversion examines the <literal>svn:mime-type</literal>
      property.  If the file has no <literal>svn:mime-type</literal>
      property, or has a mime-type that is textual (e.g.
      <literal>text/*</literal>),
      Subversion assumes it is text.  Otherwise, Subversion assumes
      the file is binary.  Subversion also helps users by running a
      binary-detection algorithm in the <command>svn import</command>
      and <command>svn add</command> commands.  These commands will
      make a good guess and then (possibly) set a binary
      <literal>svn:mime-type</literal> property on the file being
      added.  (If Subversion guesses wrong, the user can always remove
      or hand-edit the property.)</para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 9 ============================== -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-9">

    <title>Versioned Modules</title>

    <para>Unlike CVS, a Subversion working copy is aware that it has
      checked out a module.  That means that if somebody changes the
      definition of a module (e.g. adds or removes components), then a
      call to <command>svn update</command> will update the working
      copy appropriately, adding and removing components.</para>

    <para>Subversion defines modules as a list of directories within a
      directory property:  see <xref linkend="svn-ch-7-sect-3"/>.</para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 10 ============================= -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-10">

    <title>Authentication</title>

    <para>With CVS's pserver, you are required to <quote>login</quote>
      to the server before any read or write operation&mdash;you even
      have to login for anonymous operations.  With a Subversion
      repository using Apache <command>httpd</command> or
      <command>svnserve</command> as the server, you don't provide
      any authentication credentials at the outset&mdash;if an
      operation that you perform requires authentication, the server
      will challenge you for your credentials (whether those
      credentials are username and password, a client certificate, or
      even both).  So if your repository is world-readable, you will
      not be required to authenticate at all for read
      operations.</para>

    <para>As with CVS, Subversion still caches your credentials on
      disk (in your <filename>~/.subversion/auth/</filename>
      directory) unless you tell it not to by using the
      <option>--no-auth-cache</option> switch.</para>

    <para>The exception to this behaviors, however, is in the case of
      accessing an <command>svnserve</command> server over an ssh
      tunnel, using the <literal>svn+ssh://</literal> URL schema.  In
      that case, the <command>ssh</command> program unconditionally
      demands authentication just to start the tunnel.</para>

  </sect1>

  <!-- ================================================================= -->
  <!-- ======================== SECTION 11 ============================= -->
  <!-- ================================================================= -->
  <sect1 id="svn-ap-a-sect-11">

    <title>Converting a Repository from CVS to Subversion</title>

    <para>Perhaps the most important way to familiarize CVS users with
      Subversion is to let them continue to work on their projects
      using the new system.  And while that can be somewhat
      accomplished using a flat import into a Subversion repository of
      an exported CVS repository, the more thorough solution involves
      transferring not just the latest snapshot of their data, but all
      the history behind it as well, from one system to another.  This
      is an extremely difficult problem to solve that involves
      deducing changesets in the absence of atomicity, and translating
      between the systems' completely orthogonal branching policies,
      among other complications.  Still, there are a handful of tools
      claiming to at least partially support the ability to convert
      existing CVS repositories into Subversion ones.</para>

    <para>One such tool is cvs2svn (<systemitem
      class="url">http://cvs2svn.tigris.org/</systemitem>), a Python
      script originally created by members of Subversion's own
      development community.  Others include Chia-liang Kao's
      Subversion converter plugin to the VCP tool (<systemitem
      class="url">http://svn.clkao.org/revml/branches/svn-perl/</systemitem>)
      and Lev Serebryakov's RefineCVS (<systemitem
      class="url">http://lev.serebryakov.spb.ru/refinecvs/</systemitem>).
      These tools have various levels of completeness, and may make
      entirely different decisions about how to handle your CVS
      repository history.  Whichever tool you decide to use, be sure
      to perform as much verification as you can stand on the
      conversion results&mdash;after all, you've worked hard to build
      that history!</para>

    <para>For an updated collection of links to known converter tools,
      visit the Links page of the Subversion website (<systemitem
      class="url">http://subversion.tigris.org/project_links.html</systemitem>).</para>

  </sect1>

</appendix>

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