The primary mission of the Subversion project is to "provide a compelling replacement for CVS." One of its secondary missions is to provide a user interface similar to CVS's, so that switching to Subversion will be painless for CVS users.
So, if you learn Subversion's new features, you're ready to start using it, right?
Almost. Although the interfaces are similar, there are some important differences. Subversion has some features that CVS either lacks or offers differently; plus, there's the need to unlearn some of the bad habits that CVS has instilled in you.
With that, I give you the top ten Subversion tips for CVS users. The first six tips address bad CVS habits; the last four address good Subversion habits.
status to find out your ... statusIn CVS, if you want to see what has changed in your working copy, odds
are that you run cvs update. This command shows you the status of
the files in your working copy, but it also updates your CVS working
copy to the latest revision of the repository*. This not only
requires a round-trip to the server, but also may change files in your
working copy. Finding out what you've changed locally is different
from finding out what has changed in the repository, but CVS mixes the
two.**
With Subversion, if you want to find out what you've modified, you run
svn status. This command compares the files in your working copy
with those in the Subversion administrative areas (those pesky
.svn directories), thus avoiding the necessity of a network
round-trip:
$ svn status
D fish.c
A shrimp.c
M anemone.c
Note that fish.c is scheduled for deletion, shrimp.c is scheduled for
addition, and anemone.c has been modified.
|
Related Reading Version Control with Subversion |
Now, by default, svn status shows only the files that are interesting
(like those that have been added, modified, or deleted). If you want
to see information about all the files in your working copy, pass the
--verbose switch:
$ svn status --verbose
44 23 sally README
44 30 sally INSTALL
44 35 harry trout.c
D 44 19 ira fish.c
A 0 ? ? shrimp.c
M 0 ? ? anemone.c
44 36 harry things/rocks.txt
The first column remains the same, but the second 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.
If you want to know which files will be updated the next time you run svn
update, use the --show-updates switch to svn status:
$ svn status --show-updates --verbose
* 44 23 sally README
44 30 sally INSTALL
* 44 35 harry trout.c
D 44 19 ira fish.c
A 0 ? ? shrimp.c
M * 44 32 sally anemone.c
44 36 harry things/rocks.txt
You can see that the files that will be updated are marked with a *.
* Unless you pass CVS the -n switch.
** CVS has a status command, but it's not very useful.
I've seen people spend hours in meetings working out the directory structure and file placement of a project they are preparing to create in their CVS repository--and anyone who's ever tried to move a directory or a file in CVS knows why: CVS doesn't allow you to move anything around in the repository!* With Subversion, you can move files and directories with wild abandon:
$ svn move foo.c bar.c
A bar.c
D foo.c
Now bar.c has been scheduled to be added and foo.c has been
scheduled for deletion. (This is how Subversion represents a move.
svn commit will send your changes to the server.)
You can even move files and directories on the server by using URLs:
$ svn move -m "Move a file" http://svn.red-bean.com/repos/foo.c \
http://svn.red-bean.com/repos/bar.c
That will immediately move foo.c to bar.c on the server.
* Unless, of course, you shell into your repository and start moving and copying things around by hand, but this totally hoses your repository history.
In CVS, you have cvs tag, cvs tag -b, cvs rtag, and cvs rtag
-b for creating tags and branches. In Subversion, everything is done
as a copy:
$ svn copy -m "Tag rc1 rel." http://svn.red-bean.com/repos/trunk \
http://svn.red-bean.com/repos/tags/1.0rc1
You've created a tag of your main line of development (referred to as
trunk in Subversion terms). If you want to create a branch instead,
copy the trunk line of development into the branches directory--it's
just that easy. And in Subversion, tagging and branching are fast
too.
In Subversion, tags and branches are just copied paths in the
repository tree. By convention, tags live under /tags and branches
live under /branches.
CVS has to modify each individual file that you tag in the repository; depending on the size of your repository, this could take a very long time. Subversion, on the other hand, needs only to copy a single directory node, which not only is really fast but also takes very little space in your repository--no matter how many files are involved in the branch or tag. The Subversion community calls 'em "cheap copies" for good reason!
You're not limited to tagging all files in the same revision in Subversion: If you need to make a "mixed-revision" tag or branch, you can always copy a working copy to a URL:
$ svn copy -m "Mixed branch." . http://svn.red-bean.com/repos/branch/1.2-mixed
See Branching and Merging for an extensive description of how to branch and tag.
If you've ever made changes to a file in your CVS working copy that you wanted to undo without committing, you probably did something like this to rectify the situation:
$ rm I-made-a-boo-boo.txt
$ cvs up I-made-a-boo-boo.txt
U I-made-a-boo-boo.txt
And that, aside from requiring two separate operations, required a trip
to the server to get the unblemished file (which, by the way, may not be the original file you were working on but rather a newer version).
Subversion, however, stores a pristine copy of each file in the
.svn directory, so you can just do this:
$ svn revert I-made-a-boo-boo.txt
Reverted 'I-made-a-boo-boo.txt'
That comes in especially handy if you don't have a Net connection at the time.
By default, CVS translates line endings (from CR [Unix] to CRLF [Windows] and back) and expands keywords (like $Id$) in your files. This is very handy until you commit a binary file to your CVS repository and CVS, in a fit of helpfulness, turns your file into tapioca pudding.
Subversion will never ever ever do anything to your data unless you ask it to.
Let's say that together now:
SUBVERSION WILL NEVER EVER EVER DO ANYTHING TO YOUR DATA UNLESS YOU ASK IT TO.
You can add any binary file to your Subversion repository and not have to do anything special to have Subversion not destroy your file. However, if you add a text file (a .java file or .c file, for example), you may want Subversion to automatically handle end-of-line translation for you. This is done using Subversion properties.
In this case, you will set the svn:eol-style property to native:
$ svn propset svn:eol-style native halibut.c
and then commit your change.
You can teach your Subversion client to add certain properties to your files automatically--see the section on Automatic Properties and their configuration for more information.
|
Subversion's log command is so much more powerful than CVS log
that it merits a mention.
Part of the reason Subversion's log command gives more useful and compact data is that its output is based on an atomic Subversion commit rather than a collection of files that may or may not be part of the same commit. (Keep in mind that CVS has no actual concept of a commit grouping.) So Subversion is able to show you a much more concise view of your repository's log data.
For example:
$ 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
Outline sandwich fixins.
------------------------------------------------------------------------
r1 | sally | Mon, 15 Jul 2002 17:40:08 -0500 | 1 line
Initial import
------------------------------------------------------------------------
Each log entry shows you the revision number of the entry, the
author, the date, the number of lines in the log entry (to aid in
parsing svn log's output), and then the log message itself. If you
wish to see the paths that changed in your log output, pass the
--verbose flag:
$ svn log --verbose
------------------------------------------------------------------------
r3 | sally | Mon, 15 Jul 2002 18:03:46 -0500 | 1 line
Changed paths:
M /trunk/sandwich.txt
Added include lines and corrected # of cheese slices.
------------------------------------------------------------------------
r2 | harry | Mon, 15 Jul 2002 17:47:57 -0500 | 1 line
Changed paths:
M /trunk/sandwich.txt
Outline sandwich fixins.
------------------------------------------------------------------------
r1 | sally | Mon, 15 Jul 2002 17:40:08 -0500 | 1 line
Changed paths:
A /trunk/sandwich.txt
Initial import
------------------------------------------------------------------------
In the above examples, you might have noticed that we're not passing
any specific files or directories (called targets) to the log
command. If you run svn log without specifying any targets,
Subversion assumes that you're referring to your current working
directory. Subversion then uses a starting revision of 1, and the
working revision of your current working directory as the ending
revision. (You can find out what this working revision is by using
svn status -v, as we mentioned earlier.)
And now on to a small gotcha: If you commit a change to a file and
immediately run svn log, you won't see the log message for your most
recent commit. This is because the "working revision" of your working
directory has not been updated (committing a file does not
automatically update your working directory or any other files). If
you run svn update and then svn log, you'll see the "missing" log
message.
See http://svnbook.red-bean.com/svnbook/ch03s06.html#svn-ch-3-sect-5.1
and http://svnbook.red-bean.com/svnbook/re15.html for more information
on using svn log.
Suppose you have a working copy of /trunk and discover that the
change you made in revision 303, which changed oyster.c, is completely
wrong--it never should have been committed. You can use svn merge to
"undo" the change in your working copy*, and then commit the local
modification to the repository. All you need to do is specify a
reverse difference using svn merge:
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U oyster.c
Use svn diff to verify that the change is correct, and then commit
that to the repository.
For more information, see Undoing Changes.
* That is, restore the latest revision of your repository to its previous state; Subversion will still have the "bad" commit in the repository. Being a version control system, Subversion's job is to remember everything you've ever committed to it.
If you delete a file from your Subversion repository and wish to
"resurrect" it into the latest revision of your repository, the
easiest way is to svn copy it from a revision before it was deleted
into your working copy. Use svn log -v to find the revision where
the file was deleted, and then do your copy:
$ svn copy --revision 807 \
http://svn.red-bean.com/repos/trunk/perch.c ./perch.c
For more details, see Resurrecting deleted items.
In CVS, if you have a working copy for your project and are ready to
begin work on a branch, you would pass the branch name as the revision to which you wished to update. Because Subversion treats tags and
branches as regular paths in the repository, you can't just svn
update your working copy to the branch name in question. Enter the
svn switch command.
svn switch updates your working copy to mirror a new tree in the
repository--say, a branch tree instead of the trunk tree. This is the
Subversion way to move a working copy to a new branch.
$ svn switch http://svn.red-bean.com/repos/branches/vendors-with-fix .
U myproj/foo.txt
U myproj/bar.txt
U myproj/baz.c
U myproj/qux.c
Updated to revision 31.
For more details, see Switching a working copy.
If your Subversion repository is being served up through the Apache
HTTP Server (that is, you access it via a URL beginning with http),
Subversion gives you a couple of extremely convenient freebies:
First, you can point any web browser to your Subversion repository and navigate your way through the latest revision of your repository.

Second, if you're using an operating system that knows how to talk to DAV shares, you can mount your Subversion repository (read-only) on your desktop:


While this is a convenient way to see the contents of your repository, it's also very useful for sharing files with non-Subversion users.
Copyright © 2004 Brian W. Fitzpatrick, Ben Collins-Sussman, C. Michael Pilato. This article is distributed under the Creative Commons Attribution License (v 2.0).
O'Reilly Media, Inc., recently released (June 2004) Version Control with Subversion.
Sample Chapter 2, "Basic Concepts," is available free online.
You can also look at the Table of Contents, the Index, and the Full Description of the book.
For more information, or to order the book, click here.
Return to ONLamp.com
Copyright © 2009 O'Reilly Media, Inc.