blob: f21b99eace4ed67ec85619848feb4314f7b0573c [file] [log] [blame]
<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-app-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-app-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
rm</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-app-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-app-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 up</command>
to quickly see their mods. Of course, this has the side effect
of merging repository changes that you 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>Here's a quick guide to <command>svn status</command>. We
encourage all new Subversion users to use it early and often:</para>
<variablelist>
<title><command>svn status</command> Prints All Files That Have
Local Modifications: The Network is not Accessed by
Default</title>
<varlistentry>
<term><option>-u</option> switch</term>
<listitem>
<para>Add out-of-dateness information from repository.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option> switch</term>
<listitem>
<para>Show <emphasis>all</emphasis> entries under
version control.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-N</option> switch</term>
<listitem>
<para>Nonrecursive.</para>
</listitem>
</varlistentry>
</variablelist>
<para>The status 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
Head 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 bloo.png
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 "long" 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-6-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-app-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>
</sect1>
<!-- ================================================================= -->
<!-- ======================== SECTION 6 ============================== -->
<!-- ================================================================= -->
<sect1 id="svn-app-a-sect-6">
<title>Meta-data Properties</title>
<para>A new feature of Subversion is that you can attach arbitrary
metadata to files and directories. We refer to this data as
<firstterm>properties</firstterm>, and they can be thought of as
collections of arbitrary name/value pairs attached to each item
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-6-sect-2"/>.</para>
</sect1>
<!-- ================================================================= -->
<!-- ======================== SECTION 7 ============================== -->
<!-- ================================================================= -->
<sect1 id="svn-app-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-app-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-6-sect-2.3.4"/> and <xref
linkend="svn-ch-6-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. text/*),
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-app-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, then a call to <command>svn update</command>
will update the working copy appropriately.</para>
<para>Subversion defines modules as a list of directories within a
directory property: see <xref linkend="svn-ch-6-sect-3"/>.</para>
</sect1>
</appendix>
<!--
local variables:
sgml-parent-document: ("book.xml" "appendix")
end:
-->