Introduction

Subversion fulfills two different functions :

It is a perpetual backup system
Subversion will store any number of old versions of your documents in a format that is lightweight, reliable and immutable. Every revision is quickly reachable, no matter how old -- Subversion is a time machine.
It is a cooperation coordinator
Teams wastes lots of time sending each other copies of their documents and wondering who has the latest version. Subversion keeps one authoritative version that everyone on the team can modify concurrently. More importantly, if two contributors, while working in parallel, accidentally edit the same section, Subversion will prevent the second's modifications from clobbering those of the first.

Software packages that combine these two functions are called version control systems. Compared to other version control systems, Subversion is reputed to be simple, dependable and fast. These qualities has made it a fixture of open-source software development and frequently used in the industry.

Why use Subversion? Because it will make you bolder. Facing a large refactoring is scary. What if your changes are worse than the original? What if I can't put things back the way they were? With subversion, do a commit (aka, make a backup), then proceed. The commit will only take 1 second of your time and 1 kb of your disk space (or some other small amounts). Then, if you paint yourself in a corner, reverting will take only 1 second as well. Similarly, Subversion lets you boldly remove dead code and dead prose. If you ever need to remind yourself how you solved a tricky problems in a previous version, Subversion's revision history will be there for you.

Subversion was developed with software development in mind. Nevertheless, it is a general tool, suitable for all kinds of projects, such as documentation projects or website development. Although some of its functionality works better on flat text files, and most usage examples on the web pertains to source code, Subversion is not limited to flat files. It will handle files of any format.


Fetching and Navigating Versions

Authors of open-source programs often distribute their source code through Subversion. For example, the following command copies the source code implementing the experimental programming language FrTime (by the research group PLT Scheme) into your current directory. To follow this tutorial, type on your command lines the lines that begin with a dollar sign (do not type the dollar sign.)

 $ svn checkout http://svn.plt-scheme.org/plt/trunk/collects/frtime/ 

FrTime's source code is hosted on a Web server, so the URL that specify where to fetch the source code from begins with http://. For your own Subversion repositories, using a Web server will be optional. You are likely to store them in a local directory, in which case the URL will begin with file:///. You may also encounter source code distributed over Subversion's own protocol, which are reachable using URLs that begin with svn+ssh://.

The command checkout operates like a file copy. In the previous command, the source of the copy was a directory called frtime, and the destination was your current directory (by default). Thus, you will find a subdirectory called frtime in your current directory.

 $ cd frtime/
 $ ls
 animation.ss  frp-snip.ss                 graphics-sig.ss   list.ss
 base-gm.ss    frtime-big.ss               graphics-unit.ss  lowered-
 [...]

This directory is called a working directory, because it remembers its source. You can see this with the info command.

 $ svn info
 Path: .
 URL: http://svn.plt-scheme.org/plt/trunk/collects/frtime
 Repository Root: http://svn.plt-scheme.org/plt
 Repository UUID: dd0f82c0-e3f7-0310-82dd-f13d63558e96
 Revision: 10393
 [...]

In Subversion parlance, the source is called a repository. The link between the working directory and the repository is implemented as a hidden subdirectory named .svn. You can see hidden directories with ls -lAd.

 $ ls -lAd .svn
 drwxr-xr-x+ 6 Admin None 0 Jun 20 21:20 .svn

If you were to delete .svn, the link would be lost and your working directory would revert to being a normal directory.

The info command also tells us that FrTime's repository contains 10393 revisions. When you real run the command, there will surely be more. Indeed, FrTime is a part of the large PLT Scheme project, whose developer community is so large they commit more than 10 new backups per day.

The update command can time-warp your working directory to any one of these revisions. For example, you can go back to the evening of July 21, 2005, when developer gcooper finished an important refactoring.

 $ svn update -r 420
 D    frtime.scrbl
 D    lowered-equivs.ss
 D    lang.ss
 [...]
 Updated to revision 420.

Each revision remembers (amongst other things) the name of its author, its date, and a short message by the author describing the changes. We can retrieve that information with the log command.

 $ svn log -r 420
 -----------------------------------------------------------------
 r420 | gcooper | 2005-07-21 23:36:23 +0530 (Thu, 21 Jul 2005) | 6 lines
 - new and improved model for conditionals based on "super-lift"
 - added quasiquote
 - made structures memory-efficient
 - removed "non-scheduled" dependencies
 - split into several modules
 -----------------------------------------------------------------

If we do not use the -r flag to specify a revision, the log command shows the messages of all revisions. The output might be long, so you will want to pipe to less.

 $ svn log|less
 [... lots of text]

And, without a revision argument, the update command brings the working directory back to the latest version.

 $ svn update
 U    info.ss
 UU   frp-snip.ss
 U    graphics.ss
 U    frtime-tool.ss
 [...]
 Updated to revision 10393.

Working directories are expendable. They are easy make and easy to delete. After all, the source code is safely kept by the repository; we can fetch it again if we need to. Once you're done navigating the history of the FrTime project, you may delete your working directory. As a precaution, before the deletion take a moment to confirm that everything in your working directory is indeed safeguarded in the repository.

 $ svn status
 [no output]

That's good. If there were some stragglers files, or modifications you needed to save, the status command would have highlighted them, like this:

 $ echo "Blue stragglers are stars of higher luminosity than the \
   turnoff point of normal main sequence stars" > stragglers.txt
 
 $ echo ";; this is a Scheme comment added at the bottom of an \
   important source file." >> main.ss
 
 $ svn status
 ?      stragglers.txt
 M      main.ss

The question mark indicates that stragglers.txt is not saved in the repository, and the letter M says that main.ss was modified but not committed. We will be happy to lose both of these ill-advised modifications to the FrTime source code, so we just remove the working directory.

 $ cd ..
 $ rm -rf frtime

Creating a Repository

A Subversion repository is a disk-based abstract data type (ADT) which represent a revision as a delta to the previous version. The invariant of the ADT guarantees that, once stored in Subversion, directories can be retrieved without any damage to their files' content, their names, or their permissions. In addition, the data structure has provisions for safe concurrent access.

The Subversion project created two different implementations of that ADT. The original implementation used the BerkeleyDB database in an unconventional way, which sometime resulted in corruption and on-disk memory leaks (disc leaks?). Recognizing this, the developers abandoned the BerkeleyDB for their second implementation, and the problems disappeared. (Programmers who are familiar with ADTs will applaud the Subversion team for coding to an interface. If they hadn't, the transition would have been much more difficult.)

When you create your repository, make sure you select the second implementation, called (oddly) the file-system file system. Using the svnadmin command, we can create three repositories for three different projects:

 $ cd ~
 $ mkdir svn-repositories; cd svn-repositories
 $ svnadmin create --fs-type fsfs website-repository
 $ svnadmin create --fs-type fsfs hello-world-repository
 $ svnadmin create --fs-type fsfs phd-thesis-repository

Note that, since svnadmin cannot access or create repositories remotely, it does not use the URL notation. It is important to create one repository per project, because repositories are monotonic and atomic.

Monotonic
Once something is stored in the repository it cannot be removed. This is both good and bad. It means your backups are safe from tampering, but it also means that private information stored by mistake can not be erased. Be careful; keep credit card numbers and foul language far away.
Atomic
If you want to backup a repository, you have to backup all of it. If you want to delete a repository, you have to delete it all.

By sticking to one project per repository, you can backup them independently, and delete them as they become obsolete.

The representation of repositories is opaque (in the ADT sense). Aside from making wholesale copies (for backups), you should only manipulate them via svn and svnadmin.

 $ ls website-repository/
 README.txt  conf  dav  db  format  hooks  locks
 
 $ cat website-repository/README.txt
 This is a Subversion repository; use the 'svnadmin' tool to examine
 it.  Do not add, delete, or modify files here unless you know how
 to avoid corrupting the repository.


Starting a New Working Directory

There are two ways to start working from your newly-created repository. The first way is when your project hasn't started yet. In this case you simply checkout an empty working directory.

 $ cd ~
 $ svn co file:///home/gm/svn-repositories/website-repository/ website
 Checked out revision 0.
 $ cd website
 $ ls
 [no output]
 $ ls -A
 .svn
 $ svn info
 Path: .
 URL: file:///home/gm/svn-repositories/website-repository
 [...]


Here, the command co is short form for checkout, and the website argument is a destination for the copy. Without the argument you would get a working directory named website-repository, which would be confusing. Since repository is on the local filesystem, not on a Web server or an SSH server, the URL begins with file:/// (yes, you need all three slashes). The URLs to subversion repositories tend to be awkward to type. Thankfully, you only have to enter them for the initial checkout. Working directories remember their source, so subsequent command will know where to look.

The second way to get your first working directory is useful when you created the repository after the project has started. In this case, you already have a directory containing your project's files, and you need to promote it to a working directories. Do it as follow.

Suppose you have been working on a website with a graphic banner, and that your file set happens to have a copy of the server log.

 $ mkdir existing-website
 $ cd existing-website/
 $ touch index.html banner.jpg server.log
 $ ls
 banner.jpg  index.html  server.log

You can turn the directory existing-website into a working directory with the following command:

 $ svn co file:///home/Admin/svn-repositories/website-repository/ .
 Checked out revision 0.

Note the dot as the destination argument. The dot indicates to Subversion that you want to checkout into the current directory, which effectively upgrades it to a working directory.

Adding, Modifying, and Committing Files

Even if a file is in a working directory, Subversion will not safeguard it unless you add it. In the existing-websites example, the three files in the working repository are not tracked, as indicated by the question marks in the output of the status command. We add the relevant files with the add command, leaving behind the server log.

 $ svn status
 ?      banner.jpg

 ?      index.html
 ?      server.log
 $ svn add banner.jpg index.html
 A         banner.jpg
 A         index.html

If we wanted to maintain backups of all files, including the server log, we would use svn add *.

Once the files are added, we create a revision with the commit command. The commit command is the principal way to create new revisions -- use it often.

 $ svn commit -m 'beginning of the project'
 Adding         banner.jpg
 Adding         index.html
 Transmitting file data ..
 Committed revision 1.

The -m flag specifies a message that will be attached to the revision (don't forget the quotes). Use empty double quotes to commit with an empty message. Note that adding the files did not create a revision on its own. It merely scheduled the files to be added during the next commit.

After the commit, the log shows that the revision is safely saved in the repository, and the status reminds us that the server log was not backed up, which is what we wanted.

 $ svn log index.html
 ------------------------------------------------------------------------
 r1 | gm | 2008-06-21 02:24:33 +0530 (Sat, 21 Jun 2008) | 1 line
 
 beginning of the project
 ------------------------------------------------------------------------
 
 $ svn status
 ?      server.log


From there on, any time you modify a file, status will indicate that you have uncommitted changes.

 $ echo '<!-- this is the end of index.html -->' >> index.html
 
 $ svn status

 ?      server.log
 M      index.html
 
 $ svn commit -m 'added a comment to the index'
 Sending        index.html
 Transmitting file data .
 Committed revision 2.
 
 $ svn log index.html
 ------------------------------------------------------------------------
 r2 | gm  | 2008-06-21 03:07:54 +0530 (Sat, 21 Jun 2008) | 1 line
 
 added a comment to the index
 ------------------------------------------------------------------------
 r1 | gm  | 2008-06-21 02:24:33 +0530 (Sat, 21 Jun 2008) | 1 line
 
 beginning of the project
 ------------------------------------------------------------------------

Reverting, Moving, and Removing Files

With Subversion, you can roll back to any revision stored in the repository. But most of the time you simply want to throw away the changes in your working directory and rollback to the latest commit. Subversion has a command just for this case.

 $ echo '<!-- I wonder how IE behaves with a open comment at \
         the end of the file?' >> index.html
 $ svn status
 ?      server.log
 M      index.html
 $ svn revert index.html
 Reverted 'index.html'  
 $ svn status
 ?      server.log

Equivalently, you can delete the file then ask for an up-to-date version.

 $ echo '<!-- How does IE behave with a open comment at \
         the end of the file?' >> index.html
 $ rm index.html
 $ svn update
 Restored 'index.html'
 At revision 2.

This behavior can be confusing when you are actually trying to remove the file from the project. In order to remove a file in such a way that update does not recover it, you must use Subversion's own rm command.

 $ svn rm index.html
 D         index.html
 $ svn commit -m 'index.html is obsolete. It will soon be a cgi'
 Deleting       index.html

It goes without saying that removing index.html in such a way does not remove the file from previous revisions. The content of index.html can be recovered by using update to time-warp your working directory to a revision when the file existed.

In addition to removing, other file manipulations must also be done via Subversion -- renaming, moving, and copying. If you rename (or move) a file without going through Subversion, update will insist to replace the file under its old name (or its old location). Worse, Subversion will ignore the file under its new name, and it will not be backed up. You can see this in the status: in the example below, big-banner.jpg is not being backed up, and banner.jpg is scheduled to reappear (as indicated by the exclamation-mark).

 $ mv banner.jpg big-banner.jpg
 $ svn status
 ?      big-banner.jpg
 ?      server.log
 !      banner.jpg
 $ svn up
 Restored 'banner.jpg'
 At revision 5.
 $ ls
 banner.jpg  big-banner.jpg  server.log
 $ svn status
 ?      big-banner.jpg
 ?      server.log
 $ rm big-banner.jpg

(Note that up is short for update.) To affect a real move, you must use the command svn mv.

 $ svn mv banner.jpg big-banner.jpg
 A         big-banner.jpg
 D         banner.jpg
 $ svn ci -m 'renamed'
 Deleting       banner.jpg
 Adding         big-banner.jpg
 
 Committed revision 4.

(Note that ci is short for commit). Subversion also has an equivalent of cp. While copying does not run into problems with updates, copying with svn cp lets Subversion share histories and deltas between the copies within the repository, which is more efficient than duplicating the bytes.

 $ svn cp banner.jpg big-banner.jpg
 A         big-banner.jpg
 $ svn ci -m 'copied'
 Adding         big-banner.jpg
 
 Committed revision 6.

Like adding, the commands for deleting, moving or copying to not create new revisions. Commit does.

Collaborating and Resolving Conflicts

References

Subversion Documentation

[back]