Version Control with SVK

This book is an incomplete draft. It is not yet the authoritative reference on svk. Be careful!

For SVK 1.04

(book compiled from Revision 120)

Michael L.H. Brouwer

Russell Brown

This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit http://creativecommons.org/licenses/by/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

(TBA)


Table of Contents

Foreword
Preface
Audience
How to Read this Book
Conventions Used in This Book
Typographic Conventions
Icons
Organization of This Book
This Book is Free
Acknowledgments
From Michael L.H. Brouwer
1. Introduction
What is SVK?
SVK's History
SVK's Features
SVK's Architecture
Installing SVK
SVK's Components
A Quick Start
2. Basic Concepts
The Depot
Versioning Models
The Problem of File-Sharing
The Lock-Modify-Unlock Solution
The Copy-Modify-Merge Solution
SVK in Action
Working Copies
Revisions
How Working Copies Track the Depot
Mixed Revision Working Copies
Updates and Commits are Separate
Mixed revisions are normal
Mixed revisions are useful
Mixed revisions have limitations
Summary
3. Guided Tour
Help!
Import
Mirror
Revisions: Numbers, Keywords, and Dates, Oh My!
Revision Numbers
Revision Keywords
Revision Dates
Initial Checkout
Basic Work Cycle
Update Your Working Copy
Make Changes to Your Working Copy
Examine Your Changes
svk status
svk diff
svk revert
Resolve Conflicts (Merging Others' Changes)
Merging Conflicts by Hand
Resolving the changes
Discarding Your Changes
Discarding Changes Coming From the Depot
Punting: Using svk revert
Commit Your Changes
Examining History
svk log
svk diff
Examining Local Changes
Comparing Working Copy to Repository
Comparing Repository to Repository
svk cat
svk list
A Final Word on History
Other Useful Commands
svk cleanup
svk import
Summary
4. Branching and Merging
What's a Branch?
Using Branches
Creating a Branch
Working with Your Branch
The Key Concepts Behind Branches
Copying Changes Between Branches
Copying Specific Changes
The Key Concept Behind Merging
Best Practices for Merging
Tracking Merges Manually
Previewing Merges
Merge Conflicts
Noticing or Ignoring Ancestry
Common Use-Cases
Merging a Whole Branch to Another
Undoing Changes
Resurrecting Deleted Items
Common Branching Patterns
Release Branches
Feature Branches
Switching a Working Copy
Tags
Creating a Simple Tag
Creating a Complex Tag
Branch Maintenance
Repository Layout
Data Lifetimes
Summary
5. Repository Administration
6. Server Configuration
7. Advanced Topics
8. Developer Information
9. SVK Complete Reference
The SVK Command Line Client: svk
svk Switches
svk Subcommands
svk add
svk admin
svk annotate
svk cat
svk checkout
svk cleanup
svk cmerge
svk commit
svk copy
svk delete
svk depotmap
svk describe
svk diff
svk help
svk import
svk info
svk list
svk log
svk merge
svk mirror
svk mkdir
svk move
svk patch
svk propdel
svk propedit
svk propget
svk proplist
svk propset
svk pull
svk push
svk resolved
svk revert
svk smerge
svk status
svk switch
svk sync
svk update
svk verify
svk admin
svk admin Switches
svk admin Subcommands
svk admin create
svk admin deltify
svk admin dump
svk admin help
svk admin hotcopy
svk admin list-dblogs
svk admin list-unused-dblogs
svk admin load
svk admin lslocks
svk admin lstxns
svk admin recover
svk admin rmlocks
svk admin rmtxns
svk admin setlog
svk admin verify
svk admin rmcache
10. Depot Management
What is the depot?
Multiple depots
The default depot
Named depots
Why use multiple depots?
Why not use multiple depots?
General depot manipulation
Listing depots
Detaching depots
Relocating depots
Advanced depot administration
A. SVK for CVS Users
B. WebDAV and Autoversioning
C. Repository Administration
D. Copyright

List of Figures

1.1. SVK's Architecture
2.1. The problem to avoid
2.2. The lock-modify-unlock solution
2.3. The copy-modify-merge solution
2.4. The copy-modify-merge solution (continued)
2.5. The depot's filesystem
2.6. The depot
4.1. Branches of development
4.2. Starting depot layout
4.3. Depot with new copy
4.4. The branching of one file's history

Foreword

After playing with Subversion and SVK for a long time, without really being able to use either for real work since our main repository was still using CVS, the author convinced his management to let him switch their SCM over to SVK directly instead of moving to Subversion which would have been at best a step sideways from CVS.

The transistion went smoothly and after the CVS repository was converted to Subversion using cvs2svn, we mirrored it to a SVK depot and setup a quick and easy bootstrap proccess for everyone to use. Almost all of the developers started using SVK immediately without any problems. A few of them asked the question:

Q: You expect me to use a piece of software without documentation for mission critical work?

A: It has documentation, look at the built in help or go to the svk wiki.

Of course I started to realize that without hanging out in the #svk irc channel, the help and the wiki were really not sufficient to help get someone going in using SVK. So I started writing a guide to using SVK day by day on our internal wiki.

After a few days of manually updating the wiki and keeping the table of contents in sync with the actual content, I started to realize that a wiki isn't the best way to write a book, which is what this guide was turning into. I also watched people coming to #svk on a daily basis asking very similar questions about SVK which should have been answered in a document somewhere.

After some encouragement from clkao in irc I decided to start with a copy of the Subversion book's docbook XML sources and write a book about SVK. The idea was to collect information from the wiki, FAQs, from #svk and things I was putting on our internal wiki that really applied to SVK in general into one place.

This book is that one place.

Michael L.H. Brouwer, San Jose, 30 August, 2005

Preface

##TODO witty open quote here” —##TODO Witty Quote Author

In the world of open-source software, the Concurrent Versions System (CVS) has long been the tool of choice for version control. And rightly so. CVS itself is free software, and its non-restrictive modus operandi and support for networked operation—which allow dozens of geographically dispersed programmers to share their work—fits the collaborative nature of the open-source world very well. CVS and its semi-chaotic development model have become cornerstones of open-source culture.

Like many tools that have lasted 25 years, CVS is starting to show its age. Subversion is a relatively new version control system designed to be the successor to CVS. The designers set out to win the hearts of CVS users in two ways: by creating an open-source system with a design (and “look and feel”) similar to CVS, and by attempting to fix most of CVS's noticeable flaws. While the result isn't necessarily the next great evolution in version control design, Subversion is very powerful, very usable, and very flexible.

For some people, a plain successor to CVS wasn't good enough. One of those people was Chia-liang Kao. He took a year off his regular work to sit down and write a version control system that would help raise his own productivity once he got back to doing paid work. The result of his labor, and more recently that of an entire community of users and developers is SVK. While Subversion set out take over CVS's user base, SVK attempts to provide an answer for many others - including people who had already defected to another version control system and users who had never before used version control. SVK is written in Perl and uses the underlying revision-tracking filesystem built by the Subversion project.

This book documents SVK version 1.04. We have made every attempt to be thorough in our coverage. However, SVK has a thriving and energetic development community — a number of features and improvements planned for future versions of SVK may change some of the commands and specific notes in this book.

Audience

This book is written for computer-literate folk who want to use SVK to manage their data. While SVK runs on a number of different operating systems, its primary user interface is command-line based. It is that command-line tool (svk) which is discussed and used in this book. For consistency, the examples in this book assume the reader is using a Unix-like operating system, and is relatively comfortable with Unix and command-line interfaces.

That said, the svk program also runs on non-Unix platforms like Microsoft Windows. With a few minor exceptions, such as the use of backward slashes (\) instead of forward slashes (/) for path separators, the input to and output from this tool when run on Windows are identical to its Unix counterpart. However, Windows users may find more success by running the examples inside the Cygwin Unix emulation environment.

Most readers are probably programmers or sysadmins who need to track changes to source code. This is the most common use for SVK, and therefore it is the scenario underlying all of the book's examples. But SVK can be used to manage changes to any sort of information: images, music, databases, documentation, and so on. To SVK, all data is just data.

While this book is written with the assumption that the reader has never used version control, we've also tried to make it easy for users of CVS or Subversion to make a painless leap into SVK. Special sidebars may discuss CVS or Subversion from time to time, and a special appendix summarizes most of the differences between CVS, Subversion and SVK.

How to Read this Book

This book aims to be useful to people of widely different backgrounds—from people with no previous experience in version control to experienced sysadmins. Depending on your own background, certain chapters may be more or less important to you. The following can be considered a “recommended reading list” for various types of readers:

Experienced sysadmins

The assumption here is that you've probably used CVS before, and are dying to get a Subversion server up and running ASAP. Chapters 5 and 6 will show you how to create your first repository and make it available over the network. After that's done, chapter 3 and appendix A are the fastest routes to learning the SVK client while drawing on your CVS or Subversion experience.

New users

Your administrator has probably set up Subversion already, and you need to learn how to use SVK as a client. If you've never used a version control system (like CVS or Subversion), then chapters 2 and 3 are a vital introduction. If you're already an old hand at CVS or Subversion, chapter 3 and appendix A are the best place to start.

Advanced users

Whether you're a user or administrator, eventually your project will grow larger. You're going to want to learn how to do more advanced things with SVK, such as how to use branches and perform merges (chapter 4), how to use SVK's property support, how to configure runtime options (chapter 7), and other things. Chapters 4 and 7 aren't vital at first, but be sure to read them once you're comfortable with the basics.

Developers

Presumably, you're already familiar with SVK, and now want to either extend it or add new tests or fixes to it. Chapter 8 is just for you.

The book ends with reference material—chapter 9 is a reference guide for all SVK commands, and the appendices cover a number of useful topics. These are the chapters you're mostly likely to come back to after you've finished the book.

Conventions Used in This Book

This section covers the various conventions used in this book.

Typographic Conventions

Constant width

Used for commands, command output, and switches

Constant width italic

Used for replaceable items in code and text

Italic

Used for file and directory names

Icons

Note

This icon designates a note relating to the surrounding text.

Tip

This icon designates a helpful tip relating to the surrounding text.

Warning

This icon designates a warning relating to the surrounding text.

Note that the source code examples are just that—examples. While they will compile with the proper compiler incantations, they are intended to illustrate the problem at hand, not necessarily serve as examples of good programming style.

» 

Organization of This Book

The chapters that follow and their contents are listed here:

Chapter 1, Introduction

Covers the history of SVK as well as its features, architecture, components, and install methods. Also includes a quick-start guide.

Chapter 2, Basic Concepts

Explains the basics of version control and different versioning models, along with SVK's depot, working copies and revisions.

Chapter 3, Guided Tour

Walks you through a day in the life of a SVK user. It demonstrates how to use SVK to obtain, modify, and commit data.

Chapter 4, Branching and Merging

Discusses branches, merges, and tagging, including best practices for branching and merging, common use cases, how to undo changes, and how to easily swing from one branch to the next.

Chapter 5, Depot Administration

Describes the basics of the SVK depot, how to create, configure and maintain a depot, how to setup a shared repository and the tool you can use to do all this.

Chapter 6, Server Configuration

Explains how to configure a Subversion server for use with SVK, and the three ways to access your repository: HTTP, the svn protocol, and local access. It also covers the details of authentication, authorization and anonymous access.

Chapter 7, Advanced Topics

Explores the SVK client environment variables, file and directory properties, how to ignore files in your working copy, and lastly how to handle vendor branches.

Chapter 8, Developer Information

Describes the internals of SVK, the $SVKROOT administrative areas from a programmer's point of view. Shows how to write new tests for SVK and most importantly, how to contribute to the development of SVK.

Chapter 9, SVK Complete Reference

Explains in great detail every subcommand of svk with plenty of examples for the whole family!

Appendix A, SVK for Subversion Users

Covers the similarities and differences between SVK and Subversion.

Appendix B, Troubleshooting

Addresses common problems and difficulties using and building SVK.

Appendix C, Third Party Tools

Discusses tools that support or use Subversion, including alternative client programs, repository browser tools, and so on.

This Book is Free

This book started out as a branch of the Version Control With Subversion book. Over time is was morphed into an SVK specific book by the authors. As such, it has always been under a free license. (See Appendix D, Copyright.) In fact, the book was written in the public eye, as a part of SVK. This means two things:

  • You will always find the latest version of this book in the book's own Subversion repository at svn://svn.clkao.org/svkbook/trunk.

  • You can distribute and make changes to this book however you wish—it's under a free license. Of course, rather than distribute your own private version of this book, we'd much rather you send feedback and patches to the SVK developer community. See the section called “” to learn about joining this community.

A relatively recent online version of this book can be found at http://svkbook.elixus.org.

Acknowledgments

This book would not be possible (nor very useful) if SVK did not exist. For that, the authors would like to thank Chia-liang Kao for having the vision of writing an Open Source version control system with the power, speed and interoperability that SVK has.

In addition this book wouldn't have existed, or at least would have taken much longer to write if it wasn't for the Subversion book written by Ben Collins-Sussman, Brian W. Fitzpatrick and C. Michael Pilato

The original book on which this book is based is titled Version Control With Subversion and is Copyright 2002, 2003, 2004, 2005 by Ben Collins-Sussman, Brian W. Fitzpatrick and C. Michael Pilato

We would also like to thank the countless people who contributed to the SVK book with reviews, suggestions and fixes: While this is undoubtedly not a complete list, this book would be incomplete and incorrect without the help of: Gary Hoo, Jesse Vincent, Michael Hendricks, Chris Russo and the entire SVK community.

Finally we would like to thank the countless people who contributed to the original subversion book with informal reviews, suggestions, and fixes: While this is undoubtedly not a complete list, this book would be incomplete and incorrect without the help of: Jani Averbach, Ryan Barrett, Francois Beausoleil, Jennifer Bevan, Matt Blais, Zack Brown, Martin Buchholz, Brane Cibej, John R. Daily, Peter Davis, Olivier Davy, Robert P. J. Day, Mo DeJong, Brian Denny, Joe Drew, Nick Duffek, Ben Elliston, Justin Erenkrantz, Shlomi Fish, Julian Foad, Chris Foote, Martin Furter, Dave Gilbert, Eric Gillespie, Matthew Gregan, Art Haas, Greg Hudson, Alexis Huxley, Jens B. Jorgensen, Tez Kamihira, David Kimdon, Mark Benedetto King, Andreas J. Koenig, Nuutti Kotivuori, Matt Kraai, Scott Lamb, Vincent Lefevre, Morten Ludvigsen, Paul Lussier, Bruce A. Mah, Philip Martin, Feliciano Matias, Patrick Mayweg, Gareth McCaughan, Jon Middleton, Tim Moloney, Mats Nilsson, Joe Orton, Amy Lyn Pilato, Kevin Pilch-Bisson, Dmitriy Popkov, Michael Price, Mark Proctor, Steffen Prohaska, Daniel Rall, Tobias Ringstrom, Garrett Rooney, Joel Rosdahl, Christian Sauer, Larry Shatzer, Russell Steicke, Sander Striker, Erik Sjoelund, Johan Sundstroem, John Szakmeister, Mason Thomas, Eric Wadsworth, Colin Watson, Alex Waugh, Chad Whitacre, Josef Wolf, Blair Zajac, and the entire Subversion community.

From Michael L.H. Brouwer

Thanks to my girlfriend Laura for putting up with me staying up until late at night and getting up at 6am and to work on the book.

Chapter 1. Introduction

Version control is the art of managing changes to information. It has long been a critical tool for programmers, who typically spend their time making small changes to software and then undoing those changes the next day. But the usefulness of version control software extends far beyond the bounds of the software development world. Anywhere you can find people using computers to manage information that changes often, there is room for version control. And that's where SVK comes into play.

This chapter contains a high-level introduction to SVK—what it is; what it does; how to get it.

What is SVK?

SVK is a free/open-source version control system. That is, SVK manages files and directories over time. A tree of files is placed into a depot on the user's machine. The depot remembers every change ever made to your files and directories, and also to other files and directories that you mirror from other places. This allows you to recover older versions of your data, or examine the history of how your data changed. In this regard, many people think of a version control system as a sort of “time machine”.

Also central to many uses of Version Control is the concept of a repository. A repository is like a filesystem that can either be hosted on a remote server or locally on the same machine as the user's depot. While SVK doesn't currently provide a repository server, it has been designed to be able to work with repositories created by other Version Control systems; in particular Subversion repositories.

SVK can access repositories across networks, which allows them to be used by people on different computers. This is convenient to those who like a centralized repository model, and SVK supports this fully. Others prefer to use other more detached or distributed models, and again SVK is at home in these environments too. Whichever model is used, because the work is versioned, can always track back through the changes that have been made, and undo them if required.

Some version control systems are also software configuration management (SCM) systems. These systems are specifically tailored to manage trees of source code, and have many features that are specific to software development—such as natively understanding programming languages, or supplying tools for building software. SVK, however, is not one of these systems. It is a general system that can be used to manage any collection of files. For you, those files might be source code—for others, anything from grocery shopping lists to digital video mix-downs and beyond.

SVK's History

The idea of source control management has been around for many years. Early on the centralized repository scheme became the standard for many developer teams. In more recent times, distributed source control has become part of the normal work flow process. CVS is a widely known and used standard for Source Control Management. Because of some shortcomings a team of developers decided to create an improved version of CVS called Subversion (svn). While Subversion, is still a centralized repository system, because it was a new design, it was developed to be more flexible than its predecessor. Because of this fact, developers are able to take key components and connect them together in ways that the original designers never dreamt of. SVK is one of those dreams.

This particular dream came from Chia-liang Kao, who took a year out from work to develop SVK.###TODO: Expand this some more.

SVK's Features

While Subversion aimed to take the basic Source Control model already provided by CVS and improve on its design and implementation, SVK aims to open up other Source Control techniques and features offered by other Source Control Systems and models.

Because some of these features are very different to those offered by fully-centralized systems such as CVS and Subversion, there may be a number of techniques or terms that are unfamiliar to you. These will be explained later.

Below is a list of some of the key features provided by SVK

SVK provides:

Disconnected Operation

If a repository is being used, all read-only operations are available without a connection to the repository.

Decentralized Operation

It is possible to use SVK without any connection to a repository whatsoever.

Merge Tracking

Merges between branches are tracked automatically, and therefore do not need manual lists of revision numbers to be specified.

High Performance and Scalability

SVK performs very well when compared with other version control systems.###TODO Need more here.

Support for multiple repository systems

SVK can mirror repositories created by a number of Source Control Systems other than Subversion. ###TODO: List some here

Consistent data handling

Subversion expresses file differences using a binary differencing algorithm, which works identically on both text (human-readable) and binary (human-unreadable) files. Both types of files are stored equally compressed in the repository, and differences are transmitted in both directions across the network.

SVK's Architecture

Figure 1.1, “SVK's Architecture” illustrates what one might call a “mile-high” view of SVK's design.

Figure 1.1. SVK's Architecture

SVK's Architecture

Because of the extremely flexible nature of SVK, it's very difficult to pin down one definitive way of describing its architecture; either in words or graphically. The way in which it all works depends largely on the source control model that you're currently using, and that gets even more complicated when you consider that you could be using more than one model with multiple projects in the same svk installation.

On one end is a Subversion repository that holds all of your versioned data. On the other end is your Subversion client program, which manages local reflections of portions of that versioned data (called “working copies”). Between these extremes are multiple routes through various Repository Access (RA) layers. Some of these routes go across computer networks and through network servers which then access the repository. Others bypass the network altogether and access the repository directly.

Installing SVK

SVK is a set of Perl 5 modules written on top of Subversion's Perl bindings. In order to run SVK you will need to install Subversion with Perl bindings. Subversion itself is built on a portability layer called APR (Apache Portable Runtime library). This means SVK should work on any operating system that supports Perl 5 and the Apache httpd server runs on: Windows, Linux, all flavors of BSD, Mac OS X, Netware, and others.

The easiest way to get SVK is to download a binary package built for your operating system. SVK's website (http://svk.elixus.org) often has these packages available for download, posted by volunteers. The site usually contains graphical installer packages for users of Apple and Microsoft operating systems. If you run a Unix-like operating system, you can use your system's native package distribution system (RPMs, DEBs, the ports tree, etc.) to get SVK.

Alternately, you can build SVK directly from source code. Below are instructions from the SVK wiki at http://svk.elixus.org/index.php?BuildingSvkInYourHomeDirectory, on how to build SVK in your home directory without root access:

#!/bin/sh

# Install Perl
curl -O http://www.cpan.org/src/stable.tar.gz
tar xzf stable.tar.gz
cd perl-5*
sh Configure -ders -Dprefix=$HOME/local
make
make test # I didn't really do this step :P
make install
cd ..
export PATH=$HOME/local/bin:$PATH

# Install CPAN Modules
rm -f $HOME/local/lib/perl5/5.8.6/CPAN/Config.pm
rm -fr .cpan
perl -e 'print "\n\n\n\n\n\n\n\nfollow\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n4\n1\n\nq\n"' > answers
perl -MCPAN -eshell < answers
rm answers
cpan Bundle::CPAN < /dev/null
cpan LWP < /dev/null
cpan ExtUtils::AutoInstall < /dev/null
cpan Module::Build < /dev/null
cpan Module::Install < /dev/null
cpan Module::Signature < /dev/null
cpan SVN::Simple::Edit < /dev/null
cpan version < /dev/null
cpan Sort::amic < /dev/null
cpan PerlIO::via::symlink < /dev/null
cpan IO::Digest < /dev/null
cpan Date::Parse < /dev/null
cpan File::Type < /dev/null
cpan PerlIO::eol < /dev/null
cpan Locale::Maketext::Simple < /dev/null
cpan Locale::Maketext::Lexicon < /dev/null
cpan FreezeThaw < /dev/null
cpan HTML::Element < /dev/null
cpan IPC::Run3 < /dev/null
cpan Pod::HTML_Elements < /dev/null
cpan Text::Diff < /dev/null
cpan XML::ValidWriter < /dev/null
cpan VCP::Dest::svk < /dev/null

# Install Apache 2.0
wget http://apache.mirrors.pair.com/httpd/httpd-2.0.52.tar.gz
tar xzf httpd-2.0.52.tar.gz 
./configure --prefix=$HOME/local/apache2 --enable-mods-shared='headers rewrite dav ssl'
make
make install
cd ..
# XXX Apache configuration/startup juju goes here...

# Install SWIG
wget http://optusnet.dl.sourceforge.net/sourceforge/swig/swig-1.3.19.tar.gz
tar xzf swig-1.3.24.tar.gz 
cd SWIG-1.3.24/
./configure --with-perl5=$HOME/local/bin/perl5.8.6 --prefix=$HOME/local
make
make install
cd ..

# Install Subversion
wget http://subversion.tigris.org/tarballs/subversion-1.2.1.tar.gz
tar xzf subversion-1.2.1.tar.gz 
cd subversion-1.2.1
./configure \
  SWIG=$HOME/local/bin/swig \
  PERL=$HOME/local/bin/perl5.8.6 \
  --prefix=$HOME/local \
  --with-apxs=$HOME/local/apache2/bin/apxs
make
make swig-pl
make check-swig-pl
make install
make install-swig-pl
cd ..

# Install SVN-Mirror
svn co svn://svn.clkao.org/member/clkao/modules/SVN-Mirror/ SVN-Mirror
cd SVN-Mirror
perl Makefile.PL
make
make test
make install
cd ..

# Install VCP
wget http://search.cpan.org/CPAN/authors/id/A/AU/AUTRIJUS/VCP-autrijus-snapshot-0.9-20050110.tar.gz
tar xzf VCP-autrijus-snapshot-0.9-20050110.tar.gz 
cd VCP-autrijus-snapshot-0.9-20050110
perl Makefile.PL
make
make test
make install
cd ..

# Install SVK
svn co svn://svn.clkao.org/svk/trunk svk
cd svk/
perl Makefile.PL
make
make test
make install
cd ..
rm -fr SVN-Mirror SWIG-1.3.24 perl-5.8.6 stable.tar.gz \
       subversion-1.2.1* svk swig-1.3.24.tar.gz 
svk help commands

# Done!

SVK's Components

SVK, once installed, has a number of different pieces. The following is a quick overview of what you get. Don't be alarmed if the brief descriptions leave you scratching your head—there are plenty more pages in this book devoted to alleviating that confusion.

svk

The command-line client program.

svnadmin

A tool for creating, tweaking or repairing a Subversion repository—this is technically part of subversion, however svk need it to be installed in order to create depots..

Assuming you have SVK installed correctly, you should be ready to start. The next two chapters will walk you through the use of svk, SVK's command-line client program.

A Quick Start

Some people have trouble absorbing a new technology by reading the sort of “top down” approach provided by this book. This section is a very short introduction to SVK, and is designed to give “bottom up” learners a fighting chance. If you're one of those folks who prefers to learn by experimentation, the following demonstration will get you up and running. Along the way, we give links to the relevant chapters of this book.

If you're new to the entire concept of version control or to the “copy-modify-merge” model used by both CVS, Subversion and SVK, then you should read Chapter 2, Basic Concepts before going any further.

Note

The following example assumes that you have svk, the SVK command-line client, and svnadmin, the administrative tool which is part of Subversion, ready to go. It also assumes you are using Subversion 1.2 or later (run svnadmin --version to check.) and SVK-1.00 or later (run svk --version to check.

SVK stores all versioned data in a depot. To begin, create the default depot (make sure to answer y<return> to the question svk asks you):

$ svk depotmap --init
Repository /Users/sally/.svk/local does not exist, create? (y/n)y
$ ls ~/.svk
cache   config  local

This command creates a new directory ~/.svk[1] which contains SVK's administrative files, and a Subversion repository called local.

SVK has no concept of a “project”. The depot is just a virtual versioned filesystem, a large tree that can hold anything you wish. Some people prefer to store only one project in a depot, and others prefer to store multiple projects in a depot by placing them into separate directories. The merits of each approach are discussed in the section called “”. Either way, the depot only manages files and directories, so it's up to humans to interpret particular directories as “projects”.

In this example, we assume that you already have some sort of project (a collection of files and directories) that you wish to import into your newly created SVK depot. Begin by organizing them into a single directory called myproject (or whatever you wish). For reasons that will be clear later on (see Chapter 4, Branching and Merging), your project's tree structure should contain three top-level directories named branches, tags, and trunk. The trunk directory should contain all of your data, while branches and tags directories are empty:

/tmp/myproject/branches/
/tmp/myproject/tags/
/tmp/myproject/trunk/
                    foo.c
                    bar.c
                    Makefile
                    …

Once you have your tree of data ready to go, import it into the repository with the svk import command (see the section called “svk import):

$ svk import --message "initial import" /tmp/myproject //myproject
Committed revision 1.
Import path //myproject initialized.
Committed revision 2.
Directory /tmp/myproject imported to depotpath //myproject as revision 2.

Now the depot contains this tree of data. As mentioned earlier, you won't see your files by directly peeking into the depot; they're all stored within a database. But the depot's imaginary filesystem now contains a top-level directory named myproject, which in turn contains your data.

Note that the original /tmp/myproject directory is unchanged; SVK is unaware of it. (In fact, you can even delete that directory if you wish.) In order to start manipulating repository data, you need to create a new “working copy” of the data, a sort of private workspace. Ask SVK to “check out” a working copy of the myproject/trunk directory in the depot:

$ svk checkout //myproject/trunk myproject
Syncing //myproject/trunk(/myproject/trunk) in /Users/sally/myproject to 2.
A   myproject/foo.c
A   myproject/bar.c
A   myproject/Makefile
…

Now you have a editable copy of part of the depot in a new directory named myproject. You can edit the files in your working copy and then commit those changes back into the depot.

  • Enter your working copy and edit a file's contents.

  • Run svk diff to see unified diff output of your changes.

  • Run svk commit to commit the new version of your file to the depot.

  • Run svk update to bring your working copy “up-to-date” with the depot.

For a full tour of all the things you can do with your working copy, read Chapter 3, Guided Tour.

At this point, you have the option of making your depot available to others over a network. See Chapter 6, Server Configuration to learn about the different sorts of server processes available and how to configure them.



[1] It's possible to change the location of ~/.svk by setting the $SVKROOT environment variable.

Chapter 2. Basic Concepts

This chapter is a short, casual introduction to SVK. If you're new to version control, this chapter is definitely for you. We begin with a discussion of general version control concepts, work our way into the specific ideas behind SVK, and show some simple examples of SVK in use.

Even though the examples in this chapter show people sharing collections of program source code, keep in mind that SVK can manage any sort of file collection—it's not limited to helping computer programmers.

The Depot

SVK is a system for tracking history. At its core is a depot[2], which is a central store of data. The depot stores information in the form of a filesystem tree—a typical hierarchy of files and directories.

So why is this interesting? So far, this sounds like the definition of a typical file system. And indeed, the depot is a kind of file system but it's not your usual breed. What makes the SVK depot special is that it remembers every change ever written to it: every change to every file, and even changes to the directory tree itself, such as the addition, deletion, and rearrangement of files and directories.

When SVK reads data from the depot, it normally sees only the latest version of the filesystem tree. But it also has the ability to view previous states of the filesystem. For example, you can ask SVK historical questions like, “What did this directory contain last Wednesday?” or “Who was the last person to change this file, and what changes did they make?” These are the sorts of questions that are at the heart of any version control system: systems that are designed to record and track changes to data over time.

Versioning Models

The core mission of a version control system is to enable collaborative editing and sharing of data. But different systems use different strategies to achieve this.

The Problem of File-Sharing

All version control systems have to solve the same fundamental problem: how will the system allow users to share information, but prevent them from accidentally stepping on each other's feet? It's all too easy for users to accidentally overwrite each other's changes in the depot.

Consider the scenario shown in Figure 2.1, “The problem to avoid”. Suppose we have two co-workers, Harry and Sally. They each decide to edit the same repository file at the same time. If Harry saves his changes to the repository first, then it's possible that (a few moments later) Sally could accidentally overwrite them with her own new version of the file. While Harry's version of the file won't be lost forever (because the system remembers every change), any changes Harry made won't be present in Sally's newer version of the file, because she never saw Harry's changes to begin with. Harry's work is still effectively lost—or at least missing from the latest version of the file—and probably by accident. This is definitely a situation we want to avoid!

Figure 2.1. The problem to avoid

The problem to avoid

The Lock-Modify-Unlock Solution

Many version control systems use a lock-modify-unlock model to address this problem. In such a system, the repository allows only one person to change a file at a time. First Harry must “lock” the file before he can begin making changes to it. Locking a file is a lot like borrowing a book from the library; if Harry has locked a file, then Sally cannot make any changes to it. If she tries to lock the file, the repository will deny the request. All she can do is read the file, and wait for Harry to finish his changes and release his lock. After Harry unlocks the file, his turn is over, and now Sally can take her turn by locking and editing. Figure 2.2, “The lock-modify-unlock solution” demonstrates this simple solution.

Figure 2.2. The lock-modify-unlock solution

The lock-modify-unlock solution

The problem with the lock-modify-unlock model is that it's a bit restrictive, and often becomes a roadblock for users:

  • Locking may cause administrative problems. Sometimes Harry will lock a file and then forget about it. Meanwhile, because Sally is still waiting to edit the file, her hands are tied. And then Harry goes on vacation. Now Sally has to get an administrator to release Harry's lock. The situation ends up causing a lot of unnecessary delay and wasted time.

  • Locking may cause unnecessary serialization. What if Harry is editing the beginning of a text file, and Sally simply wants to edit the end of the same file? These changes don't overlap at all. They could easily edit the file simultaneously, and no great harm would come, assuming the changes were properly merged together. There's no need for them to take turns in this situation.

  • Locking may create a false sense of security. Pretend that Harry locks and edits file A, while Sally simultaneously locks and edits file B. But suppose that A and B depend on one another, and the changes made to each are semantically incompatible. Suddenly A and B don't work together anymore. The locking system was powerless to prevent the problem—yet it somehow provided a false sense of security. It's easy for Harry and Sally to imagine that by locking files, each is beginning a safe, insulated task, and thus not bother discussing their incompatible changes early on.

The Copy-Modify-Merge Solution

SVK, Subversion, CVS, and other version control systems use a copy-modify-merge model as an alternative to locking. In this model, each user's client contacts the project repository and creates a personal working copy—a local reflection of the repository's files and directories. Users then work in parallel, modifying their private copies. Finally, the private copies are merged together into a new, final version. The version control system often assists with the merging, but ultimately a human being is responsible for making it happen correctly.

Here's an example. Say that Harry and Sally each create working copies of the same project, copied from the repository. They work concurrently, and make changes to the same file A within their copies. Sally saves her changes to the repository first. When Harry attempts to save his changes later, the repository informs him that his file A is out-of-date. In other words, that file A in the repository has somehow changed since he last copied it. So Harry asks his client to merge any new changes from the repository into his working copy of file A. Chances are that Sally's changes don't overlap with his own; so once he has both sets of changes integrated, he saves his working copy back to the repository. Figure 2.3, “The copy-modify-merge solution” and Figure 2.4, “The copy-modify-merge solution (continued)” show this process.

Figure 2.3. The copy-modify-merge solution

The copy-modify-merge solution

Figure 2.4. The copy-modify-merge solution (continued)

The copy-modify-merge solution (continued)

But what if Sally's changes do overlap with Harry's changes? What then? This situation is called a conflict, and it's usually not much of a problem. When Harry asks his client to merge the latest repository changes into his working copy, his copy of file A is somehow flagged as being in a state of conflict: he'll be able to see both sets of conflicting changes, and manually choose between them. Note that software can't automatically resolve conflicts; only humans are capable of understanding and making the necessary intelligent choices. Once Harry has manually resolved the overlapping changes—perhaps after a discussion with Sally—he can safely save the merged file back to the repository.

The copy-modify-merge model may sound a bit chaotic, but in practice, it runs extremely smoothly. Users can work in parallel, never waiting for one another. When they work on the same files, it turns out that most of their concurrent changes don't overlap at all; conflicts are infrequent. And the amount of time it takes to resolve conflicts is far less than the time lost by a locking system.

In the end, it all comes down to one critical factor: user communication. When users communicate poorly, both syntactic and semantic conflicts increase. No system can force users to communicate perfectly, and no system can detect semantic conflicts. So there's no point in being lulled into a false promise that a locking system will somehow prevent conflicts; in practice, locking seems to inhibit productivity more than anything else.

SVK in Action

It's time to move from the abstract to the concrete. In this section, we'll show real examples of SVK being used.

Working Copies

You've already read about working copies; now we'll demonstrate how the SVK client creates and uses them.

A SVK working copy is an ordinary directory tree on your local system, containing a collection of files. You can edit these files however you wish, and if they're source code files, you can compile your program from them in the usual way. Your working copy is your own private work area: SVK will never incorporate changes from the depot, nor publish your own changes to the depot, until you explicitly tell it to do so.

After you've made some changes to the files in your working copy and verified that they work properly, SVK provides you with commands to “publish” your changes to the depot. If the depot contained changes not yet in your working copy[3], SVK provides you with commands to merge those changes into your working directory (by reading from the depot).

A SVK working copy doesn't contain any extra files, unlike Subversion and CVS working copies. Instead SVK keeps track of the state of your working copy in a subdirectory of your home directory named .svk.

A typical SVK depot often holds the files (or source code) for several projects; usually, each project is a subdirectory in the depot's filesystem tree. In this arrangement, a user's working copy will usually correspond to a particular subtree of the depot.

For example, suppose you have two software projects, paint and calc, for which you wish to start keeping a history.

To add these 2 projects to your depot you would run the following commands:

$ svk import  --message "Initial import of calc." calc //calc
Repository /Users/sally/.svk/local does not exist, create? (y/n)y
Committed revision 1.
Import path //calc initialized.
Committed revision 2.
Directory /Users/sally/calc imported to depotpath //calc as revision 2.

Then repeat the same steps for the paint project. Now you have 2 projects in the depot. Each project lives in its own top-level subdirectory, as shown in Figure 2.5, “The depot's filesystem”.

Figure 2.5. The depot's filesystem

The depot's filesystem

Since the calc and paint projects have been imported into the depot, it's safe to remove the directories we imported from, so lets run:

$ rm -rf calc
$ rm -rf paint

Now in order to get a working copy, you must check out some subtree of the depot[4]. (The term “check out” may sound like it has something to do with locking or reserving resources, but it doesn't; it simply creates a private copy of the project for you.) For example, if you check out /calc, you will get a working copy like this:

$ svk checkout //calc
Syncing //calc(/calc) in /Users/sally/calc to 2.
A   calc/button.c
A   calc/Makefile
A   calc/integer.c
$ ls -A calc
Makefile        button.c        integer.c

The list of letter A's indicates that SVK is adding a number of items to your working copy. You now have a editable copy of the depot's /calc directory.

Suppose you make changes to button.c. Since SVK knows the revision that the file in your working copy was based on, SVK can tell that you've changed the file. However, SVK does not make your changes public until you explicitly tell it to. The act of publishing your changes is more commonly known as committing (or checking in) changes to the depot.

To publish your changes to others, you can use SVK's commit command:

$ svk commit button.c
Committed revision 57.

Now your changes to button.c have been committed to the depot; if another user checks out a working copy of /calc, they will see your changes in the latest version of the file.

Suppose you have a collaborator, Sally, who checked out a working copy of /calc at the same time you did. When you commit your change to button.c, Sally's working copy is left unchanged; SVK only modifies working copies at the user's request.

To bring her project up to date, Sally can ask SVK to update her working copy, by using the SVK update command. This will incorporate your changes into her working copy, as well as any others that have been committed since she checked it out.

$ pwd
/Users/sally/calc
$ ls -A 
Makefile integer.c button.c
$ svk update
U   button.c

The output from the svk update command indicates that SVK updated the contents of button.c. Note that Sally didn't need to specify which files to update; SVK uses the information about the working copy stored inside ~/.svk/config, and further information from the depot, to decide which files need to be brought up to date.

Revisions

A svk commit operation can publish changes to any number of files and directories as a single atomic transaction. In your working copy, you can change files' contents, create, delete, rename and copy files and directories, and then commit the complete set of changes as a unit.

In the depot, each commit is treated as an atomic transaction: either all the commit's changes take place, or none of them take place. SVK tries to retain this atomicity in the face of program crashes, system crashes, network problems, and other users' actions.

Each time the depot accepts a commit, this creates a new state of the filesystem tree, called a revision. Each revision is assigned a unique natural number, one greater than the number of the previous revision. The initial revision of a freshly created depot is numbered zero, and consists of nothing but an empty root directory.

Figure 2.6, “The depot” illustrates a nice way to visualize the depot. Imagine an array of revision numbers, starting at 0, stretching from left to right. Each revision number has a filesystem tree hanging below it, and each tree is a “snapshot” of the way the depot looked after a commit.

Figure 2.6. The depot

The depot

It's important to note that working copies do not always correspond to any single revision in the depot; they may contain files from several different revisions. For example, suppose you check out a working copy from a depot whose most recent revision is 4:

calc/Makefile:4
     integer.c:4
     button.c:4

At the moment, this working directory corresponds exactly to revision 4 in the repository. However, suppose you make a change to button.c, and commit that change. Assuming no other commits have taken place, your commit will create revision 5 of the depot, and your working copy will now look like this:

calc/Makefile:4
     integer.c:4
     button.c:5

Suppose that, at this point, Sally commits a change to integer.c, creating revision 6. If you use svk update to bring your working copy up to date, then it will look like this:

calc/Makefile:6
     integer.c:6
     button.c:6

Sally's change to integer.c will appear in your working copy, and your change will still be present in button.c. In this example, the text of Makefile is identical in revisions 4, 5, and 6, but SVK will mark your working copy of Makefile with revision 6 to indicate that it is still current. So, after you do a clean update at the top of your working copy, it will generally correspond to exactly one revision in the repository.

How Working Copies Track the Depot

For each working copy, SVK records three essential pieces of information in the hash: subsection of the checkout: section in the ~/.svk/config file:

  • An absolute path to the working copy, or a subdirectory thereof, and

  • what revision your working copy is based on (this is called the working copy's working revision), and

  • the encoding in which the filenames are stored by the filesystem.

Given this information, by consulting the depot, SVK can tell which of the following four states a working file is in:

Unchanged, and current

The file is unchanged in the working directory, and no changes to that file have been committed to the depot since its working revision. An svk commit of the file will do nothing, and an svk update of the file will do nothing.

Locally changed, and current

The file has been changed in the working directory, and no changes to that file have been committed to the depot since its base revision. There are local changes that have not been committed to the depot, thus an svk commit of the file will succeed in publishing your changes, and an svk update of the file will do nothing.

Unchanged, and out-of-date

The file has not been changed in the working directory, but it has been changed in the depot. The file should eventually be updated, to make it current with the depot revision. An svk commit of the file will do nothing, and an svk update of the file will fold the latest changes into your working copy.

Locally changed, and out-of-date

The file has been changed both in the working directory, and in the depot. An svk commit of the file will fail with an “out-of-date” error. The file should be updated first; an svk update command will attempt to merge the public changes with the local changes. If SVK can't complete the merge in a plausible way automatically, it will ask the user how to resolve the conflict.

This may sound like a lot to keep track of, but the svk status command will show you the state of any item in your working copy. For more information on that command, see the section called “svk status.

Mixed Revision Working Copies

As a general principle, Subversion tries to be as flexible as possible. One special kind of flexibility is the ability to have a working copy containing files and directories with a mix of different working revision numbers. Unfortunately, this flexibility tends to confuse a number of new users. If the earlier example showing mixed revisions perplexed you, here's a primer on both why the feature exists and how to make use of it.

Updates and Commits are Separate

One of the fundamental rules of Subversion is that a “push” action does not cause a “pull”, nor the other way around. Just because you're ready to submit new changes to the repository doesn't mean you're ready to receive changes from other people. And if you have new changes still in progress, then svn update should gracefully merge repository changes into your own, rather than forcing you to publish them.

The main side-effect of this rule is that it means a working copy has to do extra bookkeeping to track mixed revisions, and be tolerant of the mixture as well. It's made more complicated by the fact that directories themselves are versioned.

For example, suppose you have a working copy entirely at revision 10. You edit the file foo.html and then perform an svn commit, which creates revision 15 in the repository. After the commit succeeds, many new users would expect the working copy to be entirely at revision 15, but that's not the case! Any number of changes might have happened in the repository between revisions 10 and 15. It would be a lie to claim that we had a working copy of revision 15, the client simply doesn't know. If, on the other hand, svn commit were to automatically download the newest changes, then it would be possible to set the entire working copy to revision 15—but then we'd be breaking the fundamental rule of “push” and “pull” remaining separate actions. Therefore the only safe thing the Subversion client can do is mark the one file—foo.html—as being at revision 15. The rest of the working copy remains at revision 10. Only by running svn update can the latest changes be downloaded, and the whole working copy be marked as revision 15.

Mixed revisions are normal

The fact is, every time you run svn commit, your working copy ends up with some mixture of revisions. The things you just committed are marked as having larger working revisions than everything else. After several commits (with no updates in-between) your working copy will contain a whole mixture of revisions. Even if you're the only person using the repository, you will still see this phenomenon. To examine your mixture of working revisions, use the svn status --verbose command (see the section called “svk status for more information.)

Often, new users are completely unaware that their working copy contains mixed revisions. This can be confusing, because many client commands are sensitive to the working revision of the item they're examining. For example, the svn log command is used to display the history of changes to a file or directory (see the section called “svk log). When the user invokes this command on a working copy object, they expect to see the entire history of the object. But if the object's working revision is quite old (often because svn update hasn't been run in a long time), then the history of the older version of the object is shown.

Mixed revisions are useful

If your project is sufficiently complex, you'll discover that it's sometimes nice to forcibly “backdate” portions of your working copy to an earlier revision; you'll learn how to do that in Chapter 3, Guided Tour. Perhaps you'd like to test an earlier version of a sub-module contained in a subdirectory, or perhaps you'd like to figure out when a bug first came into existence in a specific file. This is the “time machine” aspect of a version control system — the feature which allows you to move any portion of your working copy forward and backward in history.

Mixed revisions have limitations

However you make use of mixed revisions in your working copy, there are limitations to this flexibility.

First, you cannot commit the deletion of a file or directory which isn't fully up-to-date. If a newer version of the item exists in the repository, your attempt to delete will be rejected, to prevent you from accidentally destroying changes you've not yet seen.

Second, you cannot commit a metadata change to a directory unless it's fully up-to-date. You'll learn about attaching “properties” to items in Chapter 7, Advanced Topics A directory's working revision defines a specific set of entries and properties, and thus committing a property change to an out-of-date directory may destroy properties you've not yet seen.

Summary

We've covered a number of fundamental Subversion concepts in this chapter:

  • We've introduced the notions of the central repository, the client working copy, and the array of repository revision trees.

  • We've seen some simple examples of how two collaborators can use Subversion to publish and receive changes from one another, using the “copy-modify-merge” model.

  • We've talked a bit about the way Subversion tracks and manages information in a working copy.

At this point, you should have a good idea of how Subversion works in the most general sense. Armed with this knowledge, you should now be ready to jump into the next chapter, which is a detailed tour of Subversion's commands and features.



[2] Technically you can have more than one depot, but well talk about that later.

[3] More on how this can happen in chapter 3

[4] Actually we could have caused the directory from which we imported to become a working copy simply by adding the --to-checkout switch to the import command.

[5] If your home directory is on a networked filesystem this is not strictly true, and it is in fact possible to share a depot amongst different users by having your depot on a shared volume. However in chapter 3 we will show better ways of working together on the same projects.

[6] Yes you can have more than one depot, but don't worry about it for now. Chances are you won't ever need more than one.

Chapter 3. Guided Tour

Now we will go into the details of using SVK. By the time you reach the end of this chapter, you will be able to perform almost all the tasks you need to use SVK 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.

Note that this chapter is not meant to be an exhaustive list of all SVK's commands—rather, it's a conversational introduction to the most common SVK tasks you'll encounter. This chapter assumes that you've read and understood Chapter 2, Basic Concepts and are familiar with the general model of SVK. For a complete reference of all commands, see Chapter 9, SVK Complete Reference.

Help!

Before reading on, here is the most important command you'll ever need when using SVK: svk help. The SVK command-line client is self-documenting—at any time, a quick svk help <subcommand> will describe the syntax, switches, and behavior of the subcommand.

Import

You use svk import to import a new project into a SVK depot. While this is most likely the very first thing you will do when you set up your depot, it's not something that happens very often. For a detailed description of import, see the section called “svk import later in this chapter.

Mirror

You use svk mirror to mirror a remote Subversion repository into a SVK depot[7]. SVK will then allow you to check out working copies from your local mirror as well as commit changes back to the mirrored repository. Basically this makes SVK a Subversion client with a local cache, which as it turns out makes SVK orders of magnitude faster than the basic Subversion client. In addition this opens up the possibility to create local branches and track changes between those and the mirror in both directions, for more information on working with local branches, see Chapter 4, Branching and Merging.

Revisions: Numbers, Keywords, and Dates, Oh My!

Before we go on, you should know a bit about how to identify a particular revision in your depot. As you learned in the section called “Revisions”, a revision is a “snapshot” of the depot at a particular moment in time. As you continue to commit and grow your depot, you need a mechanism for identifying these snapshots.

You specify these revisions by using the --revision (-r) switch plus the revision you want (svk <subcommand> --revision REV) or you can specify a range by separating two revisions with a colon (svk <subcommand> --revision REV1:REV2). And SVK lets you refer to these revisions by number, keyword, or date.

Revision Numbers

When you create a new SVK depot, it begins its life at revision zero and each successive commit increases the revision number by one. After your commit completes, the SVK client informs you of the new revision number:

$ svk commit --message "Corrected number of cheese slices."
Committed revision 3.

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 “3”.

If, however, you were committing from a working copy that was a direct checkout of a mirrored depotpath, things would be a little more complicated. This is because the mirrored repository has its own idea of revision numbers which is distinct from the local depots idea of revision numbers.

$ svk commit --message "Corrected number of cheese slices."
Commit into mirrored path: merging back directly.
Merging back to mirror source http://svn.sally.org/calc.
Merge back committed as revision 45.
Syncing http://svn.sally.org/calc
Retrieving log information from 45 to 45
Committed revision 15 from revision 45.

What happened here is that SVK first committed the change you made to the original mirrored repository. After that it automatically performs a svk sync to download the change on the mirror to the local depot again. This ensures that you can never commit anything to a mirrored path that isn't also on the mirror itself.

Above we showed you how to use the --revision switch to refer to a specific revision number. By default the revision numbers you specify are the ones in your depot. Sometimes you want to refer to a particular revision of the mirrored repository instead. Luckily SVK keeps a mapping from local to remote revision numbers and allows you to specify both local depot revision numbers or revision numbers in the mirrored repository when performing operations. To do so you only need to add a @ right after the revision number. To get the log message for the revision we just committed above you would use:

$ svk log --revision 45@
----------------------------------------------------------------------
r15 (orig r45):  sally | 2005-07-23 14:49:11 -0700

Corrected number of cheese slices.
----------------------------------------------------------------------

Notice how the log output shows both the local depots r15, and mirrored repositories r45 revision numbers. This can be a useful aid in certain situations as well.

Revision Keywords

The SVK client understands a number of revision keywords. These keywords can be used instead of integer arguments to the --revision switch, and are resolved into specific revision numbers by SVK:

Note

For every file and directory in your working copy SVK keeps track of the revision you last updated to. You can refer to this as the “BASE” revision.

HEAD

The latest revision in the depot.

BASE

The last revision an item in a working copy was updated to.

Note

BASE, can be used to refer to local paths, but not to DEPOTPATHs.

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:

$ svk diff --revision BASE:HEAD foo.c
# shows the changes in the depot not yet in your working copy.

$ svk log --revision HEAD
# shows log message for the latest depot commit

$ svk diff --revision HEAD
# compares your working file (with local mods) to the latest version
# in the depot.

$ svk diff --revision BASE:HEAD foo.c
# compares your “pristine” foo.c (no local mods) with the 
# latest version in the depot

$ svk log --revision BASE:HEAD
# shows all commit logs since you last updated

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.

Revision Dates

Anywhere that you specify a revision number or revision keyword, you can also specify a date inside curly braces “{}”. You can even access a range of changes in the depot using both dates and revisions together!

Here are examples of the date formats that SVK accepts. Remember to use quotes around any date that contains spaces.

$ svk checkout --revision {2002-02-17}
$ svk checkout --revision {15:30}
$ svk checkout --revision {15:30:00.200000}
$ svk checkout --revision {"2002-02-17 15:30"}
$ svk checkout --revision {"2002-02-17 15:30  0230"}
$ svk checkout --revision {2002-02-17T15:30}
$ svk checkout --revision {2002-02-17T15:30Z}
$ svk checkout --revision {2002-02-17T15:30-04:00}
$ svk checkout --revision {20020217T1530}
$ svk checkout --revision {20020217T1530Z}
$ svk checkout --revision {20020217T1530-0500}
…

When you specify a date as a revision, SVK finds the most recent revision of the depot as of that date:

$ svk log --revision {2005-07-23}
----------------------------------------------------------------------
r12 (orig r41):  sally | 2005-07-22 10:06:17 -0700
…

You can also use a range of dates. SVK will find all revisions between both dates, inclusive:

$ svk log --revision {2005-07-20}:{2005-07-29}
…

As we pointed out, you can also mix dates and revisions:

$ svk log --revision {2005-07-20}:4040

Users should be aware of a subtlety that can become quite a stumbling-block when dealing with dates in SVK. Since the timestamp of a revision is stored as a property of the revision—an unversioned, modifiable property—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 SVK performs.

Initial Checkout

Most of the time, you will want to start using SVK by creating a mirror of a remote Subversion repository containing your project. Mirroring a repository creates a copy of it on your local machine. This copy contains as much of the original history of the Subversion repository as you want. For this example let's mirror everything:

$ svk mirror svn://svn.clkao.org/svk //mirror/svk
Committed revision 1.
$ svk sync //mirror/svk
Retrieving log information from 1 to 1281
Committed revision 2 from revision 1.
Committed revision 3 from revision 2.
…
Committed revision 1282 from revision 1281.

Warning

When mirroring a project you will have the choice between mirroring just trunk or the branch you are interested in as opposed to the entire project. In most cases you will want to mirror the entire project tree including the trunk, branches and tags directories. Since branches and tags are cheap copies on the remote server the mirror will also store them as cheap copies and thus not use significantly more disk space.

If you choose not to do this and mirror just a single branch or trunk, and you later decide you need access to other branches or tags in the remote repository, separately mirroring those will cause you local depot to contain disjoint mirrors of the individual branches and tags, and copies that were originally cheap copies in the remote repository will become full blown copies in your local depot. In addition you might run into problems with merge tracking across remote branches.

Tip

Creating a mirror of a large Subversion repository can take quite a while. However rest assured that once you have the mirror keeping it up to date is very fast. We will also discuss several ways to speed up getting an initial mirror on a large number of machines, see ##TODO.

Now that we have a mirror of the Subversion repository in our depot we are ready to create a working copy:

$ svk checkout //mirror/svk/trunk
Syncing //mirror/svk/trunk(/mirror/svk/trunk) in /Users/sally/trunk to 1282.
A   trunk/utils
A   trunk/utils/extract-docs
A   trunk/utils/extract-message-catalog
A   trunk/utils/svk-ediff.el
A   trunk/SIGNATURE
A   trunk/pkg
…

Although the above example checks out the trunk directory, you can just as easily check out any deep subdirectory of a depot by specifying the subdirectory in the checkout DEPOTPATH:

$ svk checkout //mirror/svk/trunk/lib/SVK/Command
Syncing //mirror/svk/trunk(/mirror/svk/trunk) in /Users/sally/Command to 1282.
A   Command/Propdel.pm
A   Command/Checkout.pm
A   Command/Revert.pm
A   Command/Cat.pm
…

Since SVK uses a “copy-modify-merge” model instead of “lock-modify-unlock” (see Chapter 2, Basic Concepts), 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—though you should run svk checkout --detach to let svk know you removed it.

Note

While your working copy is “just like any other collection of files and directories on your system”, you need to let SVK 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 svk copy or svk move instead of the copy and move commands provided by your operating system. We'll talk more about them later in this chapter.

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 you mirrored from that you've done anything.

While you can certainly check out a working copy with the DEPOTPATH as the only argument, you can also specify a directory after your DEPOTPATH. This places your working copy in the new directory that you name. For example:

$ svk checkout //mirror/svk/trunk svk
Syncing //mirror/svk/trunk(/mirror/svk/trunk) in /Users/sally/svk to 1282.
A   svk/utils
A   svk/utils/extract-docs
A   svk/utils/extract-message-catalog
A   svk/utils/svk-ediff.el
A   svk/SIGNATURE
…

That will place your working copy in a directory named svk instead of a directory named trunk as we did previously.

Basic Work Cycle

SVK 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 SVK in the course of a day's work.

The typical work cycle looks like this:

  • Update your working copy

    • svk sync

    • svk update

  • Make changes

    • svk add

    • svk delete

    • svk copy

    • svk move

  • Examine your changes

    • svk status

    • svk diff

    • svk revert

  • Merge others' changes into your working copy

    • svk update

    • svk resolved

  • Commit your changes

    • svk commit

Update Your Working Copy

When working on a project with a team, you'll want to update your mirror to receive any changes made by other developers on the project since your last update.

$ svk sync //mirror/project
Retrieving log information from 500 to 502
Committed revision 503 from revision 500.
Committed revision 504 from revision 501.
Committed revision 505 from revision 502.

Then you'll want to bring those changes into your working copy. Use svk update to bring your working copy into sync with the latest revision in your depot.

$ svk update
Syncing //mirror/project/trunk(/mirror/project/trunk) in /Users/sally/project to 505.
U   foo.c
U   bar.c

Tip

You can combine the first 2 steps by passing the --sync (-s) switch to svk update

In this case, someone else checked in modifications to both foo.c and bar.c since the last time you updated, and SVK has updated your working copy to include those changes.

Let's examine the output of svk update 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 SVK performed to bring your working copy up-to-date:

U foo

File foo was Updated (received changes from the server).

A foo

File or directory foo was Added to your working copy.

D foo

File or directory foo was Deleted from your working copy.

R foo

File or directory foo was Replaced in your working copy; that is, foo was deleted, and a new item with the same name was added. While they may have the same name, the depot considers them to be distinct objects with distinct histories.

G foo

File foo received new changes from the depot, but your working copy version of the file had your modifications. The changes did not intersect, so SVK has successfully merGed the depot's changes into the file without a problem.

g foo

File foo received new changes from the depot, but your working copy version of the file had your modifications. However the changes were exactly the same as your local modifications, so SVK has successfully merged the depot's changes into the file without changing a thing.

C foo

File foo received Conflicting 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.

Make Changes to Your Working Copy

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 SVK commands that you will use here are svk add, svk delete, svk copy, and svk move. However, if you are merely editing files that are already in SVK, you may not need to use any of these commands until you commit. Changes you can make to your working copy:

File changes

This is the simplest sort of change. You don't need to tell SVK that you intend to change a file; just make your changes. SVK will be able to automatically detect which files have been changed.

Tree changes

You can ask SVK to “mark” 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 depot until you commit them.

To make file changes, use your text editor, word processor, graphics program, or whatever tool you would normally use. SVK handles binary files just as easily as it handles text files—and just as efficiently too.

Here is an overview of the four SVK subcommands that you'll use most often to make tree changes (we'll cover svk import and svk mkdir later).

Warning

While you can edit your files with whatever tool you like, you shouldn't change the structure of your working copy without letting SVK know what you're doing. Use the svk copy, svk delete, and svk move commands to change the structure of your working copy, and use the svk add command to place new files and directories under version control.

svk add foo

Schedule file, directory, or symbolic link foo to be added to the depot. When you next commit, foo will become a child of its parent directory. Note that if foo is a directory, everything underneath foo will be scheduled for addition. If you only want to add foo itself, pass the --non-recursive (-N) switch.

svk delete foo

Schedule file, directory, or symbolic link foo to be deleted from the depot. If foo is a file or link, it is immediately deleted from your working copy. If foo is a directory, it is not deleted, but SVK schedules it for deletion. When you commit your changes, foo will be removed from your working copy and the depot. [8]

svk copy foo bar

Create a new item bar as a duplicate of foo. bar is automatically scheduled for addition. When bar is added to the depot on the next commit, its copy history is recorded (as having originally come from foo). svk copy does not create intermediate directories unless you pass it the --parent switch.

svk move foo bar

This command is exactly the same as running svk copy foo bar; svk delete foo. That is, bar is scheduled for addition as a copy of foo, and foo is scheduled for removal. svk move does not create intermediate directories unless you pass it the --parent switch.

Examine Your Changes

Once you've finished making changes, you need to commit them to the depot, 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 svk status, svk diff, and svk revert. 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.

svk status

You'll probably use the svk status command more than any other SVK command.

If you run svk status at the top of your working copy with no arguments, it will detect all file and tree changes you've made. Below are examples of the different status codes that svk status can return. (Note that the text following # is not actually printed by svk status.)

M   bar.c               # the content in bar.c has local modifications
 M  baz.c               # baz.c has property but no content modifications
?   foo.o               # svk doesn't manage foo.o
!   some_dir            # svk manages this, but it's missing or incomplete
~   qux                 # versioned as file/dir/link, but type has changed
I   .screenrc           # svk doesn't manage this, and is set to ignore it
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        # file is scheduled for deletion
A   stuff/loot/bloo.h   # file is scheduled for addition
C   stuff/loot/lump.c   # file has textual conflicts from an update
 C  stuff/loot/glub.c   # file has property conflicts from an update
R   xyz.c               # file is scheduled for replacement

In this output format svk status prints three columns of characters, followed by a whitespace character, 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:

A item

The file, directory, or symbolic link item has been scheduled for addition into the depot.

C item

The file item 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 depot.

D item

The file, directory, or symbolic link item has been scheduled for deletion from the depot.

M item

The contents of the file item have been modified.

R item

The file, directory, or symbolic link item has been scheduled to replace item in the depot. This means that the object is first deleted, then another object of the same name is added, all within a single revision.

? item

The file, directory, or symbolic link item is not under version control. You can silence the question marks by either passing the --quiet (-q) switch to svk status, or by setting the svn:ignore property on the parent directory. For more information on ignored files, see the section called “”.

! item

The file, directory, or symbolic link item is under version control but is missing or somehow incomplete. The item can be missing if it's removed using a non-SVK command. In the case of a directory, it can be incomplete if you happened to interrupt a checkout or update. A quick svk revert --recursive item will refetch the directory from the depot, or svk revert item will restore a missing file.

~ item

The file, directory, or symbolic link item is in the depot as one kind of object, but what's actually in your working copy is some other kind. For example, SVK might have a file in the depot, but you removed the file and created a directory in its place, without using the svk delete or svk add command.

I item

The file, directory, or symbolic link item is not under version control, and SVK is configured to ignore it during svk add, svk import and svk status operations. For more information on ignored files, see the section called “”. Note that this symbol only shows up if you pass the --no-ignore switch to svk status—otherwise the file would be ignored and not listed at all!

The second column tells the status of a file or directory's properties (see the section called “” for more information on properties). If an M appears in the second column, then the properties have been modified, otherwise a whitespace will be printed.

The third column will only show whitespace or a which means that the file or directory is scheduled to be added or modified with additional attached history. This typically happens when you svk move or svk copy a file or directory. If you see A   , this means the item is scheduled for addition-with-history. It could be a file, or the root of a copied directory. 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. M   means the item is part of a subtree scheduled for addition-with-history, and 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.

If you pass a specific path to svk status, it gives you information about that item alone:

$ svk status stuff/fish.c
D   stuff/fish.c

svk status also has a --verbose (-v) switch, which will show you the status of every item in your working copy, even if it has not been changed:

$ svk 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

This is the “long form” output of svk status. 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.

None of the above invocations to svk status show you changes in the depot that your working copy does not yet have. To do this you need to use the svk update with the --check-only (-C) switch, which will show what would happen if you actually ran svk update:

$ svk update --check-only
Syncing //mirror/fish/trunk(/mirror/fish/trunk) in /Users/sally/svk to 35.
C   README
U   stuff/trout.c
1 conflict found.

Notice the two entries. svk update at this point, you would receive changes to README and trout.c. This tells you some very useful information—you'll need to update and get the server changes on README before you commit, or the depot will reject your commit for being out-of-date. (More on this subject later.)

svk diff

Another way to examine your changes is with the svk diff command. You can find out exactly how you've modified things by running svk diff with no arguments, which prints out file changes in unified diff format:[9]

$ svk diff
=== bar.c
==================================================================
--- bar.c	(revision 3)
    bar.c	(local)
@@ -1,7  1,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <stdio.h>

 int main(void) {
-  printf("Sixty-four slices of American Cheese...\n");
   printf("Sixty-five slices of American Cheese...\n");
 return 0;
 }

=== README
==================================================================
--- README	(revision 3)
    README	(local)
@@ -193,3  193,4 @@ 
 Note to self:  pick up laundry.

=== stuff/fish.c
==================================================================
--- stuff/fish.c	(revision 1)
    stuff/fish.c	(local)
-Welcome to the file known as 'fish'.
-Information on fish will be here soon.

=== stuff/things/bloo.h
==================================================================
--- stuff/things/bloo.h	(revision 8)
    stuff/things/bloo.h	(local)
 Here is a new file to describe
 things about bloo.

The svk diff command produces this output by comparing your working files against the BASE revision in the depot. Files scheduled for addition are displayed as all added-text, and files scheduled for deletion are displayed as all deleted text.

Output is displayed in unified diff format. That is, removed lines are prefaced with a - and added lines are prefaced with a . svk diff also prints filename and offset information useful to the patch program, so you can generate “patches” by redirecting the diff output to a file:

$ svk diff > patchfile

You could, for example, email the patch file to another developer for review or testing prior to commit.

Note

However SVK has a much better way to create patches, which is by using the --patch switch to svk commit or almost any other command that modifies the depot. Some notable advantages of this method over using svk diff include that patches contain log messages, and tree changes, as well as binary file changes, while remaining safe to be sent though email.

$ svk commit --message '' --patch - > patchfile

svk revert

Now suppose you see the above diff output, and realize that your changes to README are a mistake; perhaps you accidentally typed that text into the wrong file in your editor.

This is a perfect opportunity to use svk revert.

$ svk revert README
Reverted README

SVK reverts the file to its pre-modified state by overwriting it with the version your working copy was based on. But also note that svk revert can undo any scheduled operations—for example, you might decide that you don't want to add a new file after all:

$ svk status foo
?   foo

$ svk add foo
A   foo

$ svk revert foo
Reverted foo

$ svk status foo
?   foo

Or perhaps you mistakenly removed a file from version control:

$ svk status README 
$ svk delete README 
D   README
$ svk revert README
Reverted README
$ svk status README

Resolve Conflicts (Merging Others' Changes)

We've already seen how svk update --check-only can predict conflicts. Suppose you run svk update and some interesting things occur:

$ svk update
Syncing //mirror/fish/trunk(/mirror/fish/trunk) in /Users/sally/svk to 46.
U   INSTALL
G   README
g   foo.c

The U, G and g codes are no cause for concern; those files cleanly absorbed changes from the depot. The files marked with U contained no local changes but were Updated with changes from the repository. The G stands for merGed, which means that the file had local changes to begin with, but the changes coming from the depot didn't overlap with the local changes. Finally the g stands for merged, but in this case your local copy already contained all the changes from the depot, so the update operation did not modify the file.

When a file has local changes, and the changes coming from the depot overlap with the local changes, that file is considered to have a conflict. When this happens SVK gives you a number of choices:

$ svk update
Syncing //mirror/fish/trunk(/mirror/fish/trunk) in /Users/sally/svk to 47.
Conflict found in bar.c:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] 

At this point you have a number of options.

  • If SVK doesn't consider the file to be of a mergeable type then only the t and y options below are available. (SVK uses the svn:mime-type property to decide if a file is capable of contextual, line-based merging. See the section called “” to learn more.)

e—edit

After SVK places conflict markers—special strings of text which delimit the “sides” of the conflict—into the file to visibly demonstrate the overlapping areas, the file is opened in an editor window.

If after editing the file all the conflict markers have been removed SVK will now give you the option to accept (a) the changes you have made. All the other options remain available as well, so you can now view the diffs after your edits, re-edit the file, etc.

d—diff

Diff your file against the merged file. This runs the internal diff tool or that specified by the $SVKDIFF environment variable.

dm—diff merged

Diff the base revision of the file against the merged file. This runs the internal diff tool or that specified by the $SVKDIFF environment variable.

dt—diff theirs

Diff the base revision of the file against the revision of the file from the depot. This runs the internal diff tool or that specified by the $SVKDIFF environment variable.

dy—diff yours

Diff the base revision of the file against the local version of the file (or when merging directly to a depot against revision of the file being merged to). This runs the internal diff tool or that specified by the $SVKDIFF environment variable.

m—merge

Invokes a 3 way merging tool or your choice and lets you resolve the conflicts using that. If you have more than one supported merging tool installed SVK will prompt you to pick one like so:

e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [a] m
Multiple merge tools found, choose one:
(to skip this question, set the SVKMERGE environment variable to one of them)
1)FileMerge, 2)Vim, q)uit? 2

The merge tools listed will vary based on which ones you have installed. Like the message says you can set your $SVKMERGE environment variable to avoid having to choose a merge tool each time you select the merge (m) option. Currently SVK supports the following merge tools: AraxisMerge, Emacs, FileMerge, GVim, GtkDiff, Guiffy, KDiff3, Meld, P4WinMerge, TkDiff, TortoiseMerge, Vim, XXDiff.

Entering q will return you to the previous menu and let you choose any of the other options again.

This option is very similar to the edit (e) option in that, after merging the file SVK will give you the option to accept (a) the changes you have made. All the other options remain available as well, so you can now view the diffs after your edits, edit the file, re-merge it, etc.

s[10]—skip

SVK places conflict markers—special strings of text which delimit the “sides” of the conflict—into the file to visibly demonstrate the overlapping areas.

The file in question remains in conflict and running svk status on it will show it as being in state C or conflicting. You will need to manually edit the file to remove the conflicts, and run svk resolved once you have done so to let SVK know the file is no longer in conflict.

t—theirs

Keep the changes between the base and depot version of the file. This discards the local changes you made to the file (or when merging directly to a depot, discards the changes between the merge base and the revision of the file being merged to).

y—yours

Keep the local version of the file (or when merging directly to a depot keep the revision of the file being merged to). This discards the changes made between the base and the depot version of the file.

h—help

Displays help explaining all the different options presented.

For example, Sally makes changes to the file sandwich.txt in the depot. 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. She decides to skip doing the merge and do it by hand after the fact:

$ svk update
Syncing //bread/trunk(/bread/trunk) in /Users/sally/bread to 70.
Conflict found in sandwich.txt:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] s
C   sandwich.txt
1 conflict found.

At this point, SVK will not allow you to commit the file sandwich.txt until the conflict has been resolved.

$ svk commit --message "Add a few more things"
1 conflict detected. Use 'svk resolved' after resolving them.

If you get a conflict, you need to do one of three things:

  • Merge the conflicted text “by hand” (by examining and editing the conflict markers within the file).

  • Run svk revert <filename> to throw away all of your local changes.

Once you've resolved the conflict, you need to let SVK know by running svk resolved. After this SVK no longer considers the file to be in a state of conflict.

$ svk resolved sandwich.txt
/Users/sally/bread/sandwich.txt marked as resolved.

Merging Conflicts by Hand

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.

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

$ cat sandwich.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
>>>> YOUR VERSION sandwich.txt 112646405792039
Salami
Mortadella
Prosciutto
Djon Mustard
==== ORIGINAL VERSION sandwich.txt 112646405792039
Provolone
Creole Mustard
==== THEIR VERSION sandwich.txt 112646405792039
Provolone
Sauerkraut
Grilled Chicken
Creole Mustard
<<<< 112646405792039
Bottom piece of bread

The lines ending in 112646405792039[11] 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:

>>>> YOUR VERSION sandwich.txt 112646405792039
Salami
Mortadella
Prosciutto
Djon Mustard
==== ORIGINAL VERSION sandwich.txt 112646405792039

The text between the second and third sets of conflict markers (if any) is the text from the original revision of the file that both your working copy and Sally's version were based on:

==== ORIGINAL VERSION sandwich.txt 112646405792039
Provolone
Creole Mustard
==== THEIR VERSION sandwich.txt 112646405792039

The text between the third and fourth sets of conflict markers is the text from Sally's commit:

==== THEIR VERSION sandwich.txt 112646405792039
Provolone
Sauerkraut
Grilled Chicken
Creole Mustard
<<<< 112646405792039

Usually you won't want to just delete the conflict markers and Sally's changes—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.[12] Once you've agreed on the changes you will check in, edit your file and remove the conflict markers.

Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Grilled Chicken
Djon Mustard
Bottom piece of bread

Now run svk resolved, and you're ready to commit your changes:

$ svk resolved sandwich.txt
$ svk commit -m "Go ahead and use my sandwich, discarding Sally's Sauerkraut."

Resolving the changes

If you get a conflict and you want to resolve it right away you can choose the edit option to edit the file in conflict. SVK will launch your selected editor with a buffer containing the exact same contents you would have gotten if you used the skip option above. Once you finish editing the file and all the conflict markers have been removed SVK will allow you to accept the changes you made:

$ svk update
Syncing //bread/trunk(/bread/trunk) in /Users/sally/bread to 70.
Conflict found in sandwich.txt:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] e
Waiting for editor...
Merged sandwich.txt:
a)ccept, e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [a] a
G   sandwich.txt

Discarding Your Changes

If you get a conflict and decide that you want to throw out your changes, you can merely select the theirs option when ask to resolve the conflict:

$ svk update
Syncing //bread/trunk(/bread/trunk) in /Users/sally/bread to 70.
Conflict found in sandwich.txt:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] t
G   sandwich.txt

Discarding Changes Coming From the Depot

If you get a conflict and decide that you want to discard the changes someone else has made to a file you have modified, you can merely select the yours option when ask to resolve the conflict:

$ svk update
Syncing //bread/trunk(/bread/trunk) in /Users/sally/bread to 70.
Conflict found in sandwich.txt:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] y
G   sandwich.txt

It's rare that you would do this blindly (since you don't know what the changes are that you are discarding) so in most cases you'd want to look at the changes first. To do so you would use dt to show their changes:

$ svk update
Syncing //bread/trunk(/bread/trunk) in /Users/sally/bread to 70.
Conflict found in sandwich.txt:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] dt
--- sandwich.txt (BASE)
    sandwich.txt (THEIRS)
@@ -3,5  3,7 @@
 Lettuce
 Tomato
 Provolone
 Sauerkraut
 Grilled Chicken
 Creole Mustard
 Bottom piece of bread
Conflict found in sandwich.txt:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] y
G   sandwich.txt

Punting: Using svk revert

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:

$ svk revert sandwich.txt
Reverted 'sandwich.txt'

Note that when you revert a conflicted file, you don't have to run svk resolved.

Now you're ready to check in your changes. Note that svk resolved, 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 svk resolved when you're certain that you've fixed the conflict in your file—once you have run svk resolved, SVK will let you commit the file even if it still contains conflict markers.

Commit Your Changes

Finally! Your edits are finished, you've merged all changes from the server, and you're ready to commit your changes to the depot.

The svk commit command sends all of your changes to the depot. When you commit a change, you need to supply a log message, 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 --message (or -m) switch:

$ svk commit --message "Corrected number of cheese slices."
Committed revision 71.

However, if you've been composing your log message as you work, you may want to tell SVK to get the message from a file by passing the filename with the --file switch:

$ svk commit --file logmsg 
Committed revision 71.

If you fail to specify either the --message or --file switch, then SVK will automatically launch your favorite editor (see the $SVN_EDITOR section in the section called “”) for composing a log message.

Tip

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.

$ svk commit
Waiting for editor...
Log message not modified: a)bort, e)dit, c)ommit?a
Aborted.
$

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

$ svk commit --message "Add more cheese"
Transaction is out of date: Out of date: '/bread/trunk/sandwich.txt' in transaction '71-1'
Please update checkout first.

At this point, you need to run svk update, deal with any merges or conflicts that result, and attempt your commit again.

That covers the basic work cycle for using SVK. There are many other features in SVK 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.

Examining History

As we mentioned earlier, the depot 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 SVK command, you can check out the depot (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 peer into the past instead of going into the past.

There are several commands that can provide you with historical data from the depot:

svk log

Shows you broad information: log messages attached to revisions, and which paths changed in each revision.

svk diff

Shows you the specific details of how a file changed over time.

svk cat

This is used to retrieve any file as it existed in a particular revision number and display it on your screen.

svk list

Displays the files in a directory for any given revision.

svk log

To find information about the history of a file or directory, use the svk log command. svk log 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.

$ svk log
----------------------------------------------------------------------
r71:  sally | 2005-09-11 12:10:39 -0700

Corrected number of cheese slices.
----------------------------------------------------------------------
r70:  sally | 2005-09-11 09:02:15 -0700

Added some Sauerkraut and Grilled Chicken.
----------------------------------------------------------------------
r69:  sally | 2005-09-11 09:00:59 -0700

Made a sandwich.
----------------------------------------------------------------------
r68:  sally | 2005-09-11 09:00:50 -0700

Directory for svk import.
----------------------------------------------------------------------

Note that the log messages are printed in reverse chronological order by default. If you wish to see a different range of revisions in a particular order, or just a single revision, pass the --revision (-r) switch:

$ svk log --revision 5:19    # shows logs 5 through 19 in chronological order

$ svk log -r 19:5            # shows logs 5 through 19 in reverse order

$ svk log -r 8               # shows log for revision 8

You can also examine the log history of a single file or directory. For example:

$ svk log foo.c
…
$ svk log //trunk/code/foo.c
…

These will display log messages only for those revisions in which the working file (or DEPOTPATH) changed.

If you want even more information about a file or directory, svk log also takes a --verbose (-v) switch. Because SVK 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, svk log will include a list of changed paths in a revision in its output:

$ svk log -r8 -v //
----------------------------------------------------------------------
r8:  sally | 2005-07-20 14:37:21 -0700
Changed paths:
  A  /calc/button.c (from /calc/button2.c:7)
  D  /calc/button2.c

Journaled about trip to New York.
----------------------------------------------------------------------

svk diff

We've already seen svk diff before—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.

In fact, it turns out that there are three distinct uses of svk diff:

  • Examine local changes

  • Compare your working copy to the depot

  • Compare depot to depot

Examining Local Changes

As we've seen, invoking svk diff with no switches will compare your working files to the revision from the depot that your working copy is based on:

$ svk diff
=== rules.txt
==================================================================
--- rules.txt	(revision 3)
    rules.txt	(local)
@@ -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
$

Comparing Working Copy to Repository

If a single --revision (-r) number is passed, then your working copy is compared to the specified revision in the repository.

$ svk diff --revision 3 rules.txt 
=== rules.txt
==================================================================
--- rules.txt	(revision 3)
    rules.txt	(local)
@@ -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
$

Comparing Repository to Repository

If two revision numbers, separated by a colon, are passed via --revision (-r), then the two revisions are directly compared.

$ svk diff --revision 2:3 rules.txt 
=== 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 open
$

Not only can you use svk diff to compare files in your working copy to the depot, but if you supply a depotpath argument, you can examine the differences between items in the depot 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:

$ svk diff --revision 4:5 //example/trunk/text/rules.txt
…
$

svk cat

If you want to examine an earlier version of a file and not necessarily the differences between two files, you can use svk cat:

$ svk cat --revision 2 rules.txt 
Be kind to others
Freedom = Chocolate Ice Cream
Everything in moderation
Chew with your mouth open
$

You can also redirect the output directly into a file:

$ svk cat --revision 2 rules.txt > rules.txt.v2
$

You're probably wondering why we don't just use svk update --revision to update the file to the older revision. There are a few reasons why we might prefer to use svk cat.

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.

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.

svk list

The svk list command shows you what files are in a repository directory without actually downloading the files to your local machine:

$ svk list //
README
bread/
calc/
mirror/
paint/
tags/

If you want a more detailed listing, pass the --verbose (-v) flag to get output like this:

$ svk list --verbose //
     48 harry          1331 Jul 28 02:07 README
     71 sally               Sep 11 12:10 bread/
     63 sally               Aug 25 08:21 calc/
     46 svm                 Jul 23 15:16 mirror/
      4 sally               Jul 20 09:41 paint/
     31 sally               Jul 22 09:33 tags/

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.

A Final Word on History

In addition to all of the above commands, you can use svk update and svk checkout with the --revision switch to take an entire working copy “back in time[13]:

$ svk checkout --revision 1729 # Checks out a new working copy at r1729
…
$ svk update --revision 1729 # Updates an existing working copy to r1729
…

Other Useful Commands

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

svk cleanup

When SVK modifies your working copy, it tries to do so as safely as possible. Before changing the working copy, SVK writes its intentions to a log file. Next it executes the commands in the log file to apply the requested change. Finally, SVK removes the log file. Architecturally, this is similar to a journaled filesystem. If a SVK 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, SVK can complete the previously started operation, and your working copy can get itself back into a consistent state.

And this is exactly what svk cleanup does: it searches your working copy and runs any leftover logs, removing locks in the process. If SVK ever tells you that some part of your working copy is “locked”, then this is the command that you should run:

$ svk status
/Users/sally/bread/sandwich.txt already locked, use 'svk cleanup' if lock is stalled
$ svk cleanup
$ svk status
M   sandwich.txt

svk import

The svk import command is a quick way to copy an unversioned tree of files into a depot, creating intermediate directories as necessary.

$ svk import mytree //some/project --message "Initial import"
Committed revision 1.
Directory /Users/sally/mytree imported to depotpath //some/project as revision 1.

The previous example copied the contents of directory mytree under the directory some/project in the default depot:

$ svk list //some/project
bar.c
foo.c
subdir/

Note that after the import is finished, the original tree is not converted into a working copy. To start working, you still need to svk checkout a fresh working copy of the tree.

Tip

If you wish to convert the directory from which the import is done to a working copy right away, simply pass the --to-checkout (t) switch to the svk import command:

$ svk import mytree //some/project --message "Initial import" --to-checkout
Committed revision 1.
Directory /Users/sally/mytree imported to depotpath //some/project as revision 1.
$ svk status --verbose mytree
           1        1 sally        mytree/bar.c
           1        1 sally        mytree/foo.c
           1        1 sally        mytree/subdir/quux.h
           1        1 sally        mytree/subdir
           1        1 sally        mytree

Summary

Now we've covered most of the SVK client commands. Notable exceptions are those dealing with branching and merging (see Chapter 4, Branching and Merging) and properties (see the section called “”). However, you may want to take a moment to skim through Chapter 9, SVK Complete Reference to get an idea of all the many different commands that SVK has—and how you can use them to make your work easier.



[7] SVK can even mirror other types of repositories such as CVS and perforce by using vcp. However as of now this is a read only mirror.

[8] Of course, nothing is ever totally deleted from the depot—just from the HEAD of the depot. 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.

[9] SVK 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 with any options you wish to pass to it by setting the $SVKDIFF environment variable. For example, to see local differences in file foo.c in context output format while ignoring whitespace changes, you might run SVKDIFF="diff -bc" svk diff foo.c.

[10] This option is not available when merging directly to a depot

[11] This number is generated at by SVK for each conflict.

[12] And if you ask them for it, they may very well ride you out of town on a rail.

[13] See? We told you that SVK was a time machine.

Chapter 4. Branching and Merging

Branching, tagging, and merging are concepts common to almost all version control systems. If you're not familiar with these ideas, we provide a good introduction in this chapter. If you are familiar, then hopefully you'll find it interesting to see how SVK implements these ideas.

Branching is a fundamental part of version control. If you're going to allow SVK to manage your data, then this is a feature you'll eventually come to depend on. This chapter assumes that you're already familiar with SVK's basic concepts (Chapter 2, Basic Concepts).

What's a Branch?

Suppose it's your job to maintain a document for a division in your company, a handbook of some sort. One day a different division asks you for the same handbook, but with a few parts “tweaked” for them, since they do things slightly differently.

What do you do in this situation? You do the obvious thing: you make a second copy of your document, and begin maintaining the two copies separately. As each department asks you to make small changes, you incorporate them into one copy or the other.

You often want to make the same change to both copies. For example, if you discover a typo in the first copy, it's very likely that the same typo exists in the second copy. The two documents are almost the same, after all; they only differ in small, specific ways.

This is the basic concept of a branch—namely, a line of development that exists independently of another line, yet still shares a common history if you look far enough back in time. A branch always begins life as a copy of something, and moves on from there, generating its own history (see Figure 4.1, “Branches of development”).

Figure 4.1. Branches of development

Branches of development

SVK has commands to help you maintain parallel branches of your files and directories. It allows you to create branches by copying your data, and remembers that the copies are related to one another. It also helps you duplicate changes from one branch to another. Finally, it keep track of which changes are present on each branch so that you only need to resolve conflicting changes once.

Using Branches

At this point, you should understand how each commit creates an entire new filesystem tree (called a “revision”) in the depot. If not, go back and read about revisions in the section called “Revisions”.

For this chapter, we'll go back to the same example from Chapter 2. Remember that you and your collaborator, Sally, are sharing a depot that contains two projects, paint and calc. Notice that in Figure 4.2, “Starting depot layout”, however, each project directory now contains subdirectories named trunk and branches. The reason for this will soon become clear.

Figure 4.2. Starting depot layout

Starting depot layout

As before, assume that Sally and you both have working copies of the “calc” project. Specifically, you each have a working copy of /calc/trunk. All the files for the project are in this subdirectory rather than in /calc itself, because your team has decided that /calc/trunk is where the “main line” of development is going to take place.

Let's say that you've been given the task of performing a radical reorganization of the project. It will take a long time to write, and will affect all the files in the project. The problem here is that you don't want to interfere with Sally, who is in the process of fixing small bugs here and there. She's depending on the fact that the latest version of the project (in /calc/trunk) is always usable. If you start committing your changes bit-by-bit, you'll surely break things for Sally.

One strategy is to crawl into a hole: you and Sally can stop sharing information for a week or two. That is, start gutting and reorganizing all the files in your working copy, but don't commit or update until you're completely finished with the task. There are a number of problems with this, though. First, it's not very safe. Most people like to save their work to the depot frequently, should something bad accidentally happen to their working copy. Second, it's not very flexible. If you do your work on different computers (perhaps you have a working copy of /calc/trunk on two different machines), you'll need to manually copy your changes back and forth, or just do all the work on a single computer. By that same token, it's difficult to share your changes-in-progress with anyone else. A common software development “best practice” is to allow your peers to review your work as you go. If nobody sees your intermediate commits, you lose potential feedback. Finally, when you're finished with all your changes, you might find it very difficult to re-merge your final work with the rest of the company's main body of code. Sally (or others) may have made many other changes in the depot that are difficult to incorporate into your working copy—especially if you run svk update after weeks of isolation.

The better solution is to create your own branch, or line of development, in the depot. This allows you to save your half-broken work frequently without interfering with others, yet you can still selectively share information with your collaborators. You'll see exactly how this works later on.

Creating a Branch

Creating a branch is very simple—you make a copy of the project in the depot using the svk copy command. SVK is not only able to copy single files, but whole directories as well. In this case, you want to make a copy of the /calc/trunk directory. Where should the new copy live? Wherever you wish—it's a matter of project policy. Let's say that your team has a policy of creating branches in the /calc/branches area of the repository, and you want to name your branch my-calc-branch. You'll want to create a new directory, /calc/branches/my-calc-branch, which begins its life as a copy of /calc/trunk.

There are two different ways to make a copy. We'll demonstrate the messy way first, just to make the concept clear. To begin, check out a working copy of the project's root directory, /calc:

$ svk checkout //calc bigwc
Syncing //calc(/calc) in /Users/sally/bigwc to 78.
A   bigwc/trunk
A   bigwc/trunk/button.c
A   bigwc/trunk/Makefile
A   bigwc/trunk/integer.c
A   bigwc/branches

Making a copy is now simply a matter of passing two working-copy paths to the svk copy command:

$ cd bigwc
$ svk copy trunk branches/my-calc-branch
A   branches/my-calc-branch
A   branches/my-calc-branch/button.c
A   branches/my-calc-branch/Makefile
A   branches/my-calc-branch/integer.c
$ svk status
A   branches/my-calc-branch

In this case, the svk copy command recursively copies the trunk working directory to a new working directory, branches/my-calc-branch. As you can see from the svk status command, the new directory is now scheduled for addition to the repository. But also notice the “ ” sign in the third column. This indicates that the scheduled addition is a copy of something, not something new. When you commit your changes, SVK will create /calc/branches/my-calc-branch in the depot by copying /calc/trunk:

$ svk commit --message "Creating a private branch of /calc/trunk."
Committed revision 79.

And now the easier method of creating a branch, which we should have told you about in the first place: svk copy is able to operate directly on two DEPOTPATHs.

$ svk copy //calc/trunk //calc/branches/my-calc-branch \
      --message "Creating a private branch of /calc/trunk."
Committed revision 79.

There's really no difference between these two methods. Both procedures create a new directory in revision 79, and the new directory is a copy of /calc/trunk. This is shown in Figure 4.3, “Depot with new copy”. Notice that the second method, however, performs an immediate commit. [14] It's an easier procedure, because it doesn't require you to check out a large mirror of the depot. In fact, this technique doesn't even require you to have a working copy at all.

Figure 4.3. Depot with new copy

Depot with new copy

Working with Your Branch

Now that you've created a branch of the project, you can check out a new working copy to start using it:

$ svk checkout //calc/branches/my-calc-branch
Syncing //calc/branches/my-calc-branch(/calc/branches/my-calc-branch) in /Users/sally/my-calc-branch to 79.
A   my-calc-branch/button.c
A   my-calc-branch/Makefile
A   my-calc-branch/integer.c
 U  my-calc-branch

There's nothing special about this working copy; it simply mirrors a different directory in the depot. When you commit changes, however, Sally won't ever see them when she updates. Her working copy is of /calc/trunk. (Be sure to read the section called “Switching a Working Copy” later in this chapter: the svk switch command is an alternate way of creating a working copy of a branch.)

Let's pretend that a week goes by, and the following commits happen:

  • You make a change to /calc/branches/my-calc-branch/integer.c, which creates revision 80.

  • You make a change to /calc/branches/my-calc-branch/button.c, which creates revision 81.

  • Sally makes a change to /calc/trunk/integer.c, which creates revision 82.

There are now two independent lines of development, shown in Figure 4.4, “The branching of one file's history”, happening on integer.c.

Figure 4.4. The branching of one file's history

The branching of one file's history

Things get interesting when you look at the history of changes made to your copy of integer.c:

$ pwd
/home/user/my-calc-branch
$ svk log --verbose integer.c
----------------------------------------------------------------------
r80:  sally | 2005-09-11 13:12:31 -0700
Changed paths:
  M  /calc/branches/my-calc-branch/integer.c

frozzled the wazjub.
----------------------------------------------------------------------
r79:  sally | 2005-09-11 13:04:13 -0700
Changed paths:
  A  /calc/branches/my-calc-branch (from /calc/trunk:78)

Creating a private branch of /calc/trunk.
----------------------------------------------------------------------

Notice that SVK is only tracing the history of your branch's integer.c to the point where it was copied. It shows the creation of the branch as an event in the history, because integer.c was implicitly copied when all of /calc/trunk/ was copied. If you want to see the history prior to the copy you need to supply the --cross (-x) switch to the svk log command:

$ svk log --verbose --cross integer.c
----------------------------------------------------------------------
r80:  harry | 2005-09-11 13:12:31 -0700
Changed paths:
  M  /calc/branches/my-calc-branch/integer.c

frozzled the wazjub.
----------------------------------------------------------------------
r79:  harry | 2005-09-11 13:04:13 -0700
Changed paths:
  A  /calc/branches/my-calc-branch (from /calc/trunk:78)

Creating a private branch of /calc/trunk.
----------------------------------------------------------------------
r45:  sally | 2005-07-23 14:49:11 -0700
Changed paths:
  M  /calc/trunk/integer.c

* integer.c: changed a docstring.
----------------------------------------------------------------------
r2:  sally | 2005-07-20 09:40:50 -0700
Changed paths:
  A  /calc/trunk/Makefile
  A  /calc/trunk/button.c
  A  /calc/trunk/integer.c

Initial import of calc.
----------------------------------------------------------------------

Now look what happens when Sally runs the same command on her copy of the file:

$ pwd
/home/sally/calc
$ svk log --verbose integer.c
----------------------------------------------------------------------
r82:  sally | 2005-09-11 14:03:03 -0700
Changed paths:
   M /calc/trunk/integer.c

* integer.c:  fix a bunch of spelling errors.
----------------------------------------------------------------------
r45:  sally | 2005-07-23 14:49:11 -0700
Changed paths:
  M  /calc/trunk/integer.c

* integer.c: changed a docstring.
----------------------------------------------------------------------
r2:  sally | 2005-07-20 09:40:50 -0700
Changed paths:
  A  /calc/trunk/Makefile
  A  /calc/trunk/button.c
  A  /calc/trunk/integer.c

Initial import of calc.
----------------------------------------------------------------------

Sally sees her own revision 82 change, but not the change you made in revision 80. As far as SVK is concerned, these two commits affected different files in different depot locations. However, SVK does show that the two files share a common history. Before the branch-copy was made in revision 79, they used to be the same file. That's why you and Sally both see the changes made in revisions 45 and 2.

The Key Concepts Behind Branches

There are two important lessons that you should remember from this section.

  1. Unlike many other version control systems, SVK's branches exist as normal filesystem directories in the depot, not in an extra dimension. These directories just happen to carry some extra historical information.

  2. SVK has no internal concept of a branch—only copies. When you copy a directory, the resulting directory is only a “branch” because you attach that meaning to it. You may think of the directory differently, or treat it differently, but to SVK it's just an ordinary directory that happens to have been created by copying.

Copying Changes Between Branches

Now you and Sally are working on parallel branches of the project: you're working on a private branch, and Sally is working on the trunk, or main line of development.

For projects that have a large number of contributors, it's common for most people to have working copies of the trunk. Whenever someone needs to make a long-running change that is likely to disrupt the trunk, a standard procedure is to create a private branch and commit changes there until all the work is complete.

So, the good news is that you and Sally aren't interfering with each other. The bad news is that it's very easy to drift too far apart. Remember that one of the problems with the “crawl in a hole” strategy is that by the time you're finished with your branch, it may be near-impossible to merge your changes back into the trunk without a huge number of conflicts.

Instead, you and Sally might continue to share changes as you work. It's up to you to decide which changes are worth sharing; SVK gives you the ability to selectively “copy” changes between branches. And when you're completely finished with your branch, your entire set of branch changes can be copied back into the trunk.

Copying Specific Changes

In the previous section, we mentioned that both you and Sally made changes to integer.c on different branches. If you look at Sally's log message for revision 344, you can see that she fixed some spelling errors. No doubt, your copy of the same file still has the same spelling errors. It's likely that your future changes to this file will be affecting the same areas that have the spelling errors, so you're in for some potential conflicts when you merge your branch someday. It's better, then, to receive Sally's change now, before you start working too heavily in the same places.

It's time to use the svk merge command. This command, it turns out, is a very close cousin to the svk diff command (which you read about in Chapter 3). Both commands are able to compare any two objects in the repository and describe the differences. For example, you can ask svk diff to show you the exact change made by Sally in revision 82:

$ svk diff -r 81:82 //calc/trunk

=== integer.c
===================================================================
--- integer.c	(revision 81)
    integer.c	(revision 82)
@@ -147,7  147,7 @@
     case 6:  sprintf(info->operating_system, "HPFS (OS/2 or NT)"); break;
     case 7:  sprintf(info->operating_system, "Macintosh"); break;
     case 8:  sprintf(info->operating_system, "Z-System"); break;
-    case 9:  sprintf(info->operating_system, "CPM"); break;
     case 9:  sprintf(info->operating_system, "CP/M"); break;
     case 10:  sprintf(info->operating_system, "TOPS-20"); break;
     case 11:  sprintf(info->operating_system, "NTFS (Windows NT)"); break;
     case 12:  sprintf(info->operating_system, "QDOS"); break;
@@ -164,7  164,7 @@
     low = (unsigned short) read_byte(gzfile);  /* read LSB */
     high = (unsigned short) read_byte(gzfile); /* read MSB */
     high = high << 8;  /* interpret MSB correctly */
-    total = low   high; /* add them togethe for correct total */
     total = low   high; /* add them together for correct total */
 
     info->extra_header = (unsigned char *) my_malloc(total);
     fread(info->extra_header, total, 1, gzfile);
@@ -241,7  241,7 @@
      Store the offset with ftell() ! */
 
   if ((info->data_offset = ftell(gzfile))== -1) {
-    printf("error: ftell() retturned -1.\n");
     printf("error: ftell() returned -1.\n");
     exit(1);
   }
 
@@ -249,7  249,7 @@
   printf("I believe start of compressed data is %u\n", info->data_offset);
   #endif
   
-  /* Set postion eight bytes from the end of the file. */
   /* Set position eight bytes from the end of the file. */
 
   if (fseek(gzfile, -8, SEEK_END)) {
     printf("error: fseek() returned non-zero\n");

The svk merge command is almost exactly the same. Instead of printing the differences to your terminal, however, it applies them directly to your working copy as local modifications:

$ svk merge -r 81:82 //calc/trunk
U  integer.c
$ svk status
M  integer.c

The output of svk merge shows that your copy of integer.c was patched. It now contains Sally's change—the change has been “copied” from the trunk to your working copy of your private branch, and now exists as a local modification. At this point, it's up to you to review the local modification and make sure it works correctly.

In another scenario, it's possible that things may not have gone so well, and that integer.c may have entered a conflicted state. You might need to resolve the conflict using standard procedures (see Chapter 3), or if you decide that the merge was a bad idea altogether, simply give up and svk revert the local change.

But assuming that you've reviewed the merged change, you can svk commit the change as usual. At that point, the change has been merged into your repository branch. In version control terminology, this act of copying changes between branches is commonly called porting changes.

When you commit the local modification, make sure your log message mentions that you're porting a specific change from one branch to another. For example:

$ svk commit -m "integer.c: ported r344 (spelling fixes) from trunk."
Sending        integer.c
Transmitting file data .
Committed revision 360.

As you'll see in the next sections, this is a very important “best practice” to follow.

A word of warning: while svk diff and svk merge are very similar in concept, they do have different syntax in many cases. Be sure to read about them in Chapter 9 for details, or ask svk help. For example, svk merge requires a working-copy path as a target, i.e. a place where it should apply the tree-changes. If the target isn't specified, it assumes you are trying to perform one of the following common operations:

  1. You want to merge directory changes into your current working directory.

  2. You want to merge the changes in a specific file into a file by the same name which exists in your current working directory.

If you are merging a directory and haven't specified a target path, svk merge assumes the first case above and tries to apply the changes into your current directory. If you are merging a file, and that file (or a file by the same name) exists in your current working directory, svk merge assumes the second case and tries to apply the changes to a local file with the same name.

If you want changes applied somewhere else, you'll need to say so. For example, if you're sitting in the parent directory of your working copy, you'll have to specify the target directory to receive the changes:

$ svk merge -r 343:344 http://svk.example.com/repos/calc/trunk my-calc-branch
U   my-calc-branch/integer.c

The Key Concept Behind Merging

You've now seen an example of the svk merge command, and you're about to see several more. If you're feeling confused about exactly how merging works, you're not alone. Many users (especially those new to version control) are initially perplexed about the proper syntax of the command, and about how and when the feature should be used. But fear not, this command is actually much simpler than you think! There's a very easy technique for understanding exactly how svk merge behaves.

The main source of confusion is the name of the command. The term “merge” somehow denotes that branches are combined together, or that there's some sort of mysterious blending of data going on. That's not the case. A better name for the command might have been svk diff-and-apply, because that's all that happens: two repository trees are compared, and the differences are applied to a working copy.

The command takes three arguments:

  1. An initial repository tree (often called the left side of the comparison),

  2. An final repository tree (often called the right side of the comparison),

  3. A working copy to accept the differences as local changes (often called the target of the merge).

Once these three arguments are specified, the two trees are compared, and the resulting differences are applied to the target working copy as local modifications. When the command is done, the results are no different than if you had hand-edited the files, or run various svk add or svk delete commands yourself. If you like the results, you can commit them. If you don't like the results, you can simply svk revert all of the changes.

The syntax of svk merge allows you to specify the three necessary arguments rather flexibly. Here are some examples:

      
$ svk merge http://svk.example.com/repos/branch1@150 \
            http://svk.example.com/repos/branch2@212 \
            my-working-copy
            
$ svk merge -r 100:200 http://svk.example.com/repos/trunk my-working-copy

$ svk merge -r 100:200 http://svk.example.com/repos/trunk

The first syntax lays out all three arguments explictly, naming each tree in the form URL@REV and naming the working copy target. The second syntax can be used as a shorthand for situations when you're comparing two different revisions of the same URL. The last syntax shows how the working-copy argument is optional; if omitted, it defaults to the current directory.

Best Practices for Merging

Tracking Merges Manually

Merging changes sounds simple enough, but in practice it can become a headache. The problem is that if you repeatedly merge changes from one branch to another, you might accidentally merge the same change twice. When this happens, sometimes things will work fine. When patching a file, Subversion typically notices if the file already has the change, and does nothing. But if the already-existing change has been modified in any way, you'll get a conflict.

Ideally, your version control system should prevent the double-application of changes to a branch. It should automatically remember which changes a branch has already received, and be able to list them for you. It should use this information to help automate merges as much as possible.

Unfortunately, Subversion is not such a system. Like CVS, Subversion does not yet record any information about merge operations. When you commit local modifications, the repository has no idea whether those changes came from running svk merge, or from just hand-editing the files.

What does this mean to you, the user? It means that until the day Subversion grows this feature, you'll have to track merge information yourself. The best place to do this is in the commit log-message. As demonstrated in the earlier example, it's recommended that your log-message mention a specific revision number (or range of revisions) that are being merged into your branch. Later on, you can run svk log to review which changes your branch already contains. This will allow you to carefully construct a subsequent svk merge command that won't be redundant with previously ported changes.

In the next section, we'll show some examples of this technique in action.

Previewing Merges

Because merging only results in local modifications, it's not usually a high-risk operation. If you get the merge wrong the first time, simply svk revert the changes and try again.

It's possible, however, that your working copy might already have local modifications. The changes applied by a merge will be mixed with your pre-existing ones, and running svk revert is no longer an option. The two sets of changes may be impossible to separate.

In cases like this, people take comfort in being able to predict or examine merges before they happen. One simple way to do that is to run svk diff with the same arguments you plan to pass to svk merge, as we already showed in our first example of merging. Another method of previewing is to pass the --dry-run option to the merge command:

$ svk merge --dry-run -r 343:344 http://svk.example.com/repos/calc/trunk
U  integer.c

$ svk status
#  nothing printed, working copy is still unchanged.

The --dry-run option doesn't actually apply any local changes to the working copy. It only shows status codes that would be printed in a real merge. It's useful for getting a “high level” preview of the potential merge, for those times when running svk diff gives too much detail.

Merge Conflicts

Just like the svk update command, svk merge applies changes to your working copy. And therefore it's also capable of creating conflicts. The conflicts produced by svk merge, however, are sometimes different, and this section explains those differences.

To begin with, assume that your working copy has no local edits. When you svk update to a particular revision, the changes sent by the server will always apply “cleanly” to your working copy. The server produces the delta by comparing two trees: a virtual snapshot of your working copy, and the revision tree you're interested in. Because the left-hand side of the comparison is exactly equal to what you already have, the delta is guaranteed to correctly convert your working copy into the right-hand tree.

But svk merge has no such guarantees and can be much more chaotic: the user can ask the server to compare any two trees at all, even ones that are unrelated to the working copy! This means there's large potential for human error. Users will sometimes compare the wrong two trees, creating a delta that doesn't apply cleanly. svk merge will do its best to apply as much of the delta as possible, but some parts may be impossible. Just like the Unix patch command sometimes complains about “failed hunks”, svk merge will complain about “skipped targets”:

$ svk merge -r 1288:1351 http://svk.example.com/repos/branch
U  foo.c
U  bar.c
Skipped missing target: 'baz.c'
U  glub.c
C  glorb.h

$

In the previous example it might be the case that baz.c exists in both snapshots of the branch being compared, and the resulting delta wants to change the file's contents, but the file doesn't exist in the working copy. Whatever the case, the “skipped” message means that the user is most likely comparing the wrong two trees; they're the classic sign of driver error. When this happens, it's easy to recursively revert all the changes created by the merge (svk revert --recursive), delete any unversioned files or directories left behind after the revert, and re-run svk merge with different arguments.

Also notice that the previous example shows a conflict happening on glorb.h. We already stated that the working copy has no local edits: how can a conflict possibly happen? Again, because the user can use svk merge to define and apply any old delta to the working copy, that delta may contain textual changes that don't cleanly apply to a working file, even if the file has no local modifications.

Another small difference between svk update and svk merge are the names of the full-text files created when a conflict happens. In the section called “Resolve Conflicts (Merging Others' Changes)”, we saw that an update produces files named filename.mine, filename.rOLDREV, and filename.rNEWREV. When svk merge produces a conflict, though, it creates three files named filename.working, filename.left, and filename.right. In this case, the terms “left” and “right” are describing which side of the double-tree comparison the file came from. In any case, these differing names will help you distinguish between conflicts that happened as a result of an update versus ones that happened as a result of a merge.

Noticing or Ignoring Ancestry

When conversing with a Subversion developer, you might very likely hear reference to the term ancestry. This word is used to describe the relationship between two objects in a repository: if they're related to each other, then one object is said to be an ancestor of the other.

For example, suppose you commit revision 100, which includes a change to a file foo.c. Then foo.c@99 is an “ancestor” of foo.c@100. On the other hand, suppose you commit the deletion of foo.c in revision 101, and then add a new file by the same name in revision 102. In this case, foo.c@99 and foo.c@102 may appear to be related (they have the same path), but in fact are completely different objects in the repository. They share no history or “ancestry”.

The reason for bringing this up is to point out an important difference between svk diff and svk merge. The former command ignores ancestry, while the latter command is quite sensitive to it. For example, if you asked svk diff to compare revisions 99 and 102 of foo.c, you would see line-based diffs; the diff command is blindly comparing two paths. But if you asked svk merge to compare the same two objects, it would notice that they're unrelated and first attempt to delete the old file, then add the new file; you would see a D foo.c followed by a A foo.c.

Most merges involve comparing trees that are ancestrally related to one another, and therefore svk merge defaults to this behavior. Occasionally, however, you may want the merge command to compare two unrelated trees. For example, you may have imported two source-code trees representing different vendor releases of a software project (see the section called “”). If you asked svk merge to compare the two trees, you'd see the entire first tree being deleted, followed by an add of the entire second tree!

In these situations, you'll want svk merge to do a path-based comparison only, ignoring any relations between files and directories. Add the --ignore-ancestry option to your merge command, and it will behave just like svk diff. (And conversely, the --notice-ancestry option will cause svk diff to behave like the merge command.)

Common Use-Cases

There are many different uses for branching and svk merge, and this section describes the most common ones you're likely to run into.

Merging a Whole Branch to Another

To complete our running example, we'll move forward in time. Suppose several days have passed, and many changes have happened on both the trunk and your private branch. Suppose that you've finished working on your private branch; the feature or bug fix is finally complete, and now you want to merge all of your branch changes back into the trunk for others to enjoy.

So how do we use svk merge in this scenario? Remember that this command compares two trees, and applies the differences to a working copy. So to receive the changes, you need to have a working copy of the trunk. We'll assume that either you still have your original one lying around (fully updated), or that you recently checked out a fresh working copy of /calc/trunk.

But which two trees should be compared? At first glance, the answer may seem obvious: just compare the latest trunk tree with your latest branch tree. But beware—this assumption is wrong, and has burned many a new user! Since svk merge operates like svk diff, comparing the latest trunk and branch trees will not merely describe the set of changes you made to your branch. Such a comparison shows too many changes: it would not only show the addition of your branch changes, but also the removal of trunk changes that never happened on your branch.

To express only the changes that happened on your branch, you need to compare the initial state of your branch to its final state. Using svk log on your branch, you can see that your branch was created in revision 341. And the final state of your branch is simply a matter of using the HEAD revision. That means you want to compare revisions 341 and HEAD of your branch directory, and apply those differences to a working copy of the trunk.

Tip

A nice way of finding the revision in which a branch was created (the “base” of the branch) is to use the --stop-on-copy option to svk log. The log subcommand will normally show every change ever made to the branch, including tracing back through the copy which created the branch. So normally, you'll see history from the trunk as well. The --stop-on-copy will halt log output as soon as svk log detects that its target was copied or renamed.

So in our continuing example,

$ svk log --verbose --stop-on-copy \
          http://svk.example.com/repos/calc/branches/my-calc-branch
…
------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   A /calc/branches/my-calc-branch (from /calc/trunk:340)

$

As expected, the final revision printed by this command is the revision in which my-calc-branch was created by copying.

Here's the final merging procedure, then:

$ cd calc/trunk
$ svk update
At revision 405.

$ svk merge -r 341:405 http://svk.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svk status
M   integer.c
M   button.c
M   Makefile

# ...examine the diffs, compile, test, etc...

$ svk commit -m "Merged my-calc-branch changes r341:405 into the trunk."
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 406.

Again, notice that the commit log message very specifically mentions the range of changes that was merged into the trunk. Always remember to do this, because it's critical information you'll need later on.

For example, suppose you decide to keep working on your branch for another week, in order to complete an enhancement to your original feature or bug fix. The repository's HEAD revision is now 480, and you're ready to do another merge from your private branch to the trunk. But as discussed in the section called “Best Practices for Merging”, you don't want to merge the changes you've already merged before; you only want to merge everything “new” on your branch since the last time you merged. The trick is to figure out what's new.

The first step is to run svk log on the trunk, and look for a log message about the last time you merged from the branch:

$ cd calc/trunk
$ svk log
…
------------------------------------------------------------------------
r406 | user | 2004-02-08 11:17:26 -0600 (Sun, 08 Feb 2004) | 1 line

Merged my-calc-branch changes r341:405 into the trunk.
------------------------------------------------------------------------
…

Aha! Since all branch-changes that happened between revisions 341 and 405 were previously merged to the trunk as revision 406, you now know that you want to merge only the branch changes after that—by comparing revisions 406 and HEAD.

$ cd calc/trunk
$ svk update
At revision 480.

# We notice that HEAD is currently 480, so we use it to do the merge:

$ svk merge -r 406:480 http://svk.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svk commit -m "Merged my-calc-branch changes r406:480 into the trunk."
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 481.

Now the trunk contains the complete second wave of changes made to the branch. At this point, you can either delete your branch (we'll discuss this later on), or continue working on your branch and repeat this procedure for subsequent merges.

Undoing Changes

Another common use for svk merge is to roll back a change that has already been committed. Suppose you're working away happily on a working copy of /calc/trunk, and you discover that the change made way back in revision 303, which changed integer.c, is completely wrong. It never should have been committed. You can use svk merge to “undo” the change in your working copy, and then commit the local modification to the repository. All you need to do is to specify a reverse difference:

$ svk merge -r 303:302 http://svk.example.com/repos/calc/trunk
U  integer.c

$ svk status
M  integer.c

$ svk diff
…
# verify that the change is removed
…

$ svk commit -m "Undoing change committed in r303."
Sending        integer.c
Transmitting file data .
Committed revision 350.

One way to think about a repository revision is as a specific group of changes (some version control systems call these changesets). By using the -r switch, you can ask svk merge to apply a changeset, or whole range of changesets, to your working copy. In our case of undoing a change, we're asking svk merge to apply changeset #303 to our working copy backwards.

Keep in mind that rolling back a change like this is just like any other svk merge operation, so you should use svk status and svk diff to confirm that your work is in the state you want it to be in, and then use svk commit to send the final version to the repository. After committing, this particular changeset is no longer reflected in the HEAD revision.

Again, you may be thinking: well, that really didn't undo the commit, did it? The change still exists in revision 303. If somebody checks out a version of the calc project between revisions 303 and 349, they'll still see the bad change, right?

Yes, that's true. When we talk about “removing” a change, we're really talking about removing it from HEAD. The original change still exists in the repository's history. For most situations, this is good enough. Most people are only interested in tracking the HEAD of a project anyway. There are special cases, however, where you really might want to destroy all evidence of the commit. (Perhaps somebody accidentally committed a confidential document.) This isn't so easy, it turns out, because Subversion was deliberately designed to never lose information. Revisions are immutable trees which build upon one another. Removing a revision from history would cause a domino effect, creating chaos in all subsequent revisions and possibly invalidating all working copies. [16]

Resurrecting Deleted Items

The great thing about version control systems is that information is never lost. Even when you delete a file or directory, it may be gone from the HEAD revision, but the object still exists in earlier revisions. One of the most common questions new users ask is, “How do I get my old file or directory back?

The first step is to define exactly which item you're trying to resurrect. Here's a useful metaphor: you can think of every object in the repository as existing in a sort of two-dimensional coordinate system. The first coordinate is a particular revision tree, and the second coordinate is a path within that tree. So every version of your file or directory can be defined by a specific coordinate pair.

Subversion has no Attic directory like CVS does, [17] so you need to use svk log to discover the exact coordinate pair you wish to resurrect. A good strategy is to run svk log --verbose in a directory which used to contain your deleted item. The --verbose option shows a list of all changed items in each revision; all you need to do is find the revision in which you deleted the file or directory. You can do this visually, or by using another tool to examine the log output (via grep, or perhaps via an incremental search in an editor).

$ cd parent-dir
$ svk log --verbose
…
------------------------------------------------------------------------
r808 | joe | 2003-12-26 14:29:40 -0600 (Fri, 26 Dec 2003) | 3 lines
Changed paths:
   D /calc/trunk/real.c
   M /calc/trunk/integer.c

Added fast fourier transform functions to integer.c.
Removed real.c because code now in double.c.
…

In the example, we're assuming that you're looking for a deleted file real.c. By looking through the logs of a parent directory, you've spotted that this file was deleted in revision 808. Therefore, the last version of the file to exist was in the revision right before that. Conclusion: you want to resurrect the path /calc/trunk/real.c from revision 807.

That was the hard part—the research. Now that you know what you want to restore, you have two different choices.

One option is to use svk merge to apply revision 808 “in reverse”. (We've already discussed how to undo changes, see the section called “Undoing Changes”.) This would have the effect of re-adding real.c as a local modification. The file would be scheduled for addition, and after a commit, the file would again exist in HEAD.

In this particular example, however, this is probably not the best strategy. Reverse-applying revision 808 would not only schedule real.c for addition, but the log message indicates that it would also undo certain changes to integer.c, which you don't want. Certainly, you could reverse-merge revision 808 and then svk revert the local modifications to integer.c, but this technique doesn't scale well. What if there were 90 files changed in revision 808?

A second, more targeted strategy is not to use svk merge at all, but rather the svk copy command. Simply copy the exact revision and path “coordinate pair” from the repository to your working copy:

$ svk copy --revision 807 \
           http://svk.example.com/repos/calc/trunk/real.c ./real.c

$ svk status
A      real.c

$ svk commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
Adding         real.c
Transmitting file data .
Committed revision 1390.

The plus sign in the status output indicates that the item isn't merely scheduled for addition, but scheduled for addition “with history”. Subversion remembers where it was copied from. In the future, running svk log on this file will traverse back through the file's resurrection and through all the history it had prior to revision 807. In other words, this new real.c isn't really new; it's a direct descendant of the original, deleted file.

Although our example shows us resurrecting a file, note that these same techniques work just as well for resurrecting deleted directories.

Common Branching Patterns

Version control is most often used for software development, so here's a quick peek at two of the most common branching/merging patterns used by teams of programmers. If you're not using Subversion for software development, feel free to skip this section. If you're a software developer using version control for the first time, pay close attention, as these patterns are often considered best practices by experienced folk. These processes aren't specific to Subversion; they're applicable to any version control system. Still, it may help to see them described in Subversion terms.

Release Branches

Most software has a typical lifecycle: code, test, release, repeat. There are two problems with this process. First, developers need to keep writing new features while quality-assurance teams take time to test supposedly-stable versions of the software. New work cannot halt while the software is tested. Second, the team almost always needs to support older, released versions of software; if a bug is discovered in the latest code, it most likely exists in released versions as well, and customers will want to get that bugfix without having to wait for a major new release.

Here's where version control can help. The typical procedure looks like this:

  • Developers commit all new work to the trunk. Day-to-day changes are committed to /trunk: new features, bugfixes, and so on.

  • The trunk is copied to a “release” branch. When the team thinks the software is ready for release (say, a 1.0 release), then /trunk might be copied to /branches/1.0.

  • Teams continue to work in parallel. One team begins rigorous testing of the release branch, while another team continues new work (say, for version 2.0) on /trunk. If bugs are discovered in either location, fixes are ported back and forth as necessary. At some point, however, even that process stops. The branch is “frozen” for final testing right before a release.

  • The branch is tagged and released. When testing is complete, /branches/1.0 is copied to /tags/1.0.0 as a reference snapshot. The tag is packaged and released to customers.

  • The branch is maintained over time. While work continues on /trunk for version 2.0, bugfixes continue to be ported from /trunk to /branches/1.0. When enough bugfixes have accumulated, management may decide to do a 1.0.1 release: /branches/1.0 is copied to /tags/1.0.1, and the tag is packaged and released.

This entire process repeats as the software matures: when the 2.0 work is complete, a new 2.0 release branch is created, tested, tagged, and eventually released. After some years, the repository ends up with a number of release branches in “maintenance” mode, and a number of tags representing final shipped versions.

Feature Branches

A feature branch is the sort of branch that's been the dominant example in this chapter, the one you've been working on while Sally continues to work on /trunk. It's a temporary branch created to work on a complex change without interfering with the stability of /trunk. Unlike release branches (which may need to be supported forever), feature branches are born, used for a while, merged back to the trunk, then ultimately deleted. They have a finite span of usefulness.

Again, project policies vary widely concerning exactly when it's appropriate to create a feature branch. Some projects never use feature branches at all: commits to /trunk are a free-for-all. The advantage to this system is that it's simple—nobody needs to learn about branching or merging. The disadvantage is that the trunk code is often unstable or unusable. Other projects use branches to an extreme: no change is ever committed to the trunk directly. Even the most trivial changes are created on a short-lived branch, carefully reviewed and merged to the trunk. Then the branch is deleted. This system guarantees an exceptionally stable and usable trunk at all times, but at the cost of tremendous process overhead.

Most projects take a middle-of-the-road approach. They commonly insist that /trunk compile and pass regression tests at all times. A feature branch is only required when a change requires a large number of destabilizing commits. A good rule of thumb is to ask this question: if the developer worked for days in isolation and then committed the large change all at once (so that /trunk were never destabilized), would it be too large a change to review? If the answer to that question is “yes”, then the change should be developed on a feature branch. As the developer commits incremental changes to the branch, they can be easily reviewed by peers.

Finally, there's the issue of how to best keep a feature branch in “sync” with the trunk as work progresses. As we mentioned earlier, there's a great risk to working on a branch for weeks or months; trunk changes may continue to pour in, to the point where the two lines of development differ so greatly that it may become a nightmare trying to merge the branch back to the trunk.

This situation is best avoided by regularly merging trunk changes to the branch. Make up a policy: once a week, merge the last week's worth of trunk changes to the branch. Take care when doing this; the merging needs to be hand-tracked to avoid the problem of repeated merges (as described in the section called “Tracking Merges Manually”). You'll need to write careful log messages detailing exactly which revision ranges have been been merged already (as demonstrated in the section called “Merging a Whole Branch to Another”). It may sound intimidating, but it's actually pretty easy to do.

At some point, you'll be ready to merge the “synchronized” feature branch back to the trunk. To do this, begin by doing a final merge of the latest trunk changes to the branch. When that's done, the latest versions of branch and trunk will be absolutely identical except for your branch changes. So in this special case, you would merge by comparing the branch with the trunk:

$ cd trunk-working-copy

$ svk update
At revision 1910.

$ svk merge http://svk.example.com/repos/calc/trunk@1910 \
            http://svk.example.com/repos/calc/branches/mybranch@1910
U  real.c
U  integer.c
A  newdirectory
A  newdirectory/newfile
…

By comparing the HEAD revision of the trunk with the HEAD revision of the branch, you're defining a delta that describes only the changes you made to the branch; both lines of development already have all of the trunk changes.

Another way of thinking about this pattern is that your weekly sync of trunk to branch is analogous to running svk update in a working copy, while the final merge step is analogous to running svk commit from a working copy. After all, what else is a working copy but a very shallow private branch? It's a branch that's only capable of storing one change at a time.

Switching a Working Copy

The svk switch command transforms an existing working copy into a different branch. While this command isn't strictly necessary for working with branches, it provides a nice shortcut to users. In our earlier example, after creating your private branch, you checked out a fresh working copy of the new repository directory. Instead, you can simply ask Subversion to change your working copy of /calc/trunk to mirror the new branch location:

$ cd calc

$ svk info | grep URL
URL: http://svk.example.com/repos/calc/trunk

$ svk switch http://svk.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile
Updated to revision 341.

$ svk info | grep URL
URL: http://svk.example.com/repos/calc/branches/my-calc-branch

After “switching” to the branch, your working copy is no different than what you would get from doing a fresh checkout of the directory. And it's usually more efficient to use this command, because often branches only differ by a small degree. The server sends only the minimal set of changes necessary to make your working copy reflect the branch directory.

The svk switch command also takes a --revision (-r) option, so you need not always move your working copy to the “tip” of the branch.

Of course, most projects are more complicated than our calc example, containing multiple subdirectories. Subversion users often follow a specific algorithm when using branches:

  1. Copy the project's entire “trunk” to a new branch directory.

  2. Switch only part of the trunk working copy to mirror the branch.

In other words, if a user knows that the branch-work only needs to happen on a specific subdirectory, they use svk switch to move only that subdirectory to the branch. (Or sometimes users will switch just a single working file to the branch!) That way, they can continue to receive normal “trunk” updates to most of their working copy, but the switched portions will remain immune (unless someone commits a change to their branch). This feature adds a whole new dimension to the concept of a “mixed working copy”—not only can working copies contain a mixture of working revisions, but a mixture of repository locations as well.

If your working copy contains a number of switched subtrees from different repository locations, it continues to function as normal. When you update, you'll receive patches to each subtree as appropriate. When you commit, your local changes will still be applied as a single, atomic change to the repository.

Note that while it's okay for your working copy to reflect a mixture of repository locations, these locations must all be within the same repository. Subversion repositories aren't yet able to communicate with one another; that's a feature planned beyond Subversion 1.0.[18]

Because svk switch is essentially a variant of svk update, it shares the same behaviors; any local modifications in your working copy are preserved when new data arrives from the repository. This allows you to perform all sorts of clever tricks.

For example, suppose you have a working copy of /calc/trunk and make a number of changes to it. Then you suddenly realize that you meant to make the changes to a branch instead. No problem! When you svk switch your working copy to the branch, the local changes will remain. You can then test and commit them to the branch.

Tags

Another common version control concept is a tag. A tag is just a “snapshot” of a project in time. In Subversion, this idea already seems to be everywhere. Each repository revision is exactly that—a snapshot of the filesystem after each commit.

However, people often want to give more human-friendly names to tags, like release-1.0. And they want to make snapshots of smaller subdirectories of the filesystem. After all, it's not so easy to remember that release-1.0 of a piece of software is a particular subdirectory of revision 4822.

Creating a Simple Tag

Once again, svk copy comes to the rescue. If you want to create a snapshot of /calc/trunk exactly as it looks in the HEAD revision, then make a copy of it:

$ svk copy http://svk.example.com/repos/calc/trunk \
           http://svk.example.com/repos/calc/tags/release-1.0 \
      -m "Tagging the 1.0 release of the 'calc' project."

Committed revision 351.

This example assumes that a /calc/tags directory already exists. (If it doesn't, see svk mkdir). After the copy completes, the new release-1.0 directory is forever a snapshot of how the project looked in the HEAD revision at the time you made the copy. Of course you might want to be more precise about exactly which revision you copy, in case somebody else may have committed changes to the project when you weren't looking. So if you know that revision 350 of /calc/trunk is exactly the snapshot you want, you can specify it by passing -r 350 to the svk copy command.

But wait a moment: isn't this tag-creation procedure the same procedure we used to create a branch? Yes, in fact, it is. In Subversion, there's no difference between a tag and a branch. Both are just ordinary directories that are created by copying. Just as with branches, the only reason a copied directory is a “tag” is because humans have decided to treat it that way: as long as nobody ever commits to the directory, it forever remains a snapshot. If people start committing to it, it becomes a branch.

If you are administering a repository, there are two approaches you can take to managing tags. The first approach is “hands off”: as a matter of project policy, decide where your tags will live, and make sure all users know how to treat the directories they copy in there. (That is, make sure they know not to commit to them.) The second approach is more paranoid: you can use one of the access-control scripts provided with Subversion to prevent anyone from doing anything but creating new copies in the tags-area (See Chapter 6, Server Configuration.) The paranoid approach, however, isn't usually necessary. If a user accidentally commits a change to a tag-directory, you can simply undo the change as discussed in the previous section. This is version control, after all.

Creating a Complex Tag

Sometimes you may want your “snapshot” to be more complicated than a single directory at a single revision.

For example, pretend your project is much larger than our calc example: suppose it contains a number of subdirectories and many more files. In the course of your work, you may decide that you need to create a working copy that is designed to have specific features and bug fixes. You can accomplish this by selectively backdating files or directories to particular revisions (using svk update -r liberally), or by switching files and directories to particular branches (making use of svk switch). When you're done, your working copy is a hodgepodge of repository locations from different revisions. But after testing, you know it's the precise combination of data you need.

Time to make a snapshot. Copying one URL to another won't work here. In this case, you want to make a snapshot of your exact working copy arrangement and store it in the repository. Luckily, svk copy actually has four different uses (which you can read about in Chapter 9), including the ability to copy a working-copy tree to the repository:

$ ls
my-working-copy/

$ svk copy my-working-copy http://svk.example.com/repos/calc/tags/mytag

Committed revision 352.

Now there is a new directory in the repository, /calc/tags/mytag, which is an exact snapshot of your working copy—mixed revisions, URLs, and all.

Other users have found interesting uses for this feature. Sometimes there are situations where you have a bunch of local changes made to your working copy, and you'd like a collaborator to see them. Instead of running svk diff and sending a patch file (which won't capture tree changes), you can instead use svk copy to “upload” your working copy to a private area of the repository. Your collaborator can then either checkout a verbatim copy of your working copy, or use svk merge to receive your exact changes.

Branch Maintenance

You may have noticed by now that Subversion is extremely flexible. Because it implements branches and tags with the same underlying mechanism (directory copies), and because branches and tags appear in normal filesystem space, many people find Subversion intimidating. It's almost too flexible. In this section, we'll offer some suggestions for arranging and managing your data over time.

Repository Layout

There are some standard, recommended ways to organize a repository. Most people create a trunk directory to hold the “main line” of development, a branches directory to contain branch copies, and a tags directory to contain tag copies. If a repository holds only one project, then often people create these top-level directories:

/trunk
/branches
/tags

If a repository contains multiple projects, admins typically index their layout by project (see the section called “” to read more about “project roots”):

/paint/trunk
/paint/branches
/paint/tags
/calc/trunk
/calc/branches
/calc/tags

Of course, you're free to ignore these common layouts. You can create any sort of variation, whatever works best for you or your team. Remember that whatever you choose, it's not a permanent commitment. You can reorganize your repository at any time. Because branches and tags are ordinary directories, the svk move command can move or rename them however you wish. Switching from one layout to another is just a matter of issuing a series of server-side moves; if you don't like the way things are organized in the repository, just juggle the directories around.

Remember, though, that while moving directories may be easy to do, you need to be considerate of your users as well. Your juggling can be disorienting to users with existing working copies. If a user has a working copy of a particular repository directory, your svk move operation might remove the path from the latest revision. When the user next runs svk update, they'll be told that their working copy represents a path that no longer exists, and the user will be forced to svk switch to the new location.

Data Lifetimes

Another nice feature of Subversion's model is that branches and tags can have finite lifetimes, just like any other versioned item. For example, suppose you eventually finish all your work on your personal branch of the calc project. After merging all of your changes back into /calc/trunk, there's no need for your private branch directory to stick around anymore:

$ svk delete http://svk.example.com/repos/calc/branches/my-calc-branch \
             -m "Removing obsolete branch of calc project."

Committed revision 375.

And now your branch is gone. Of course it's not really gone: the directory is simply missing from the HEAD revision, no longer distracting anyone. If you use svk checkout, svk switch, or svk list to examine an earlier revision, you'll still be able to see your old branch.

If browsing your deleted directory isn't enough, you can always bring it back. Resurrecting data is very easy in Subversion. If there's a deleted directory (or file) that you'd like to bring back into HEAD, simply use svk copy -r to copy it from the old revision:

$ svk copy -r 374 http://svk.example.com/repos/calc/branches/my-calc-branch \
                  http://svk.example.com/repos/calc/branches/my-calc-branch

Committed revision 376.

In our example, your personal branch had a relatively short lifetime: you may have created it to fix a bug or implement a new feature. When your task is done, so is the branch. In software development, though, it's also common to have two “main” branches running side-by-side for very long periods. For example, suppose it's time to release a stable calc project to the public, and you know it's going to take a couple of months to shake bugs out of the software. You don't want people to add new features to the project, but you don't want to tell all developers to stop programming either. So instead, you create a “stable” branch of the software that won't change much:

$ svk copy http://svk.example.com/repos/calc/trunk \
         http://svk.example.com/repos/calc/branches/stable-1.0 \
         -m "Creating stable branch of calc project."

Committed revision 377.

And now developers are free to continue adding cutting-edge (or experimental) features to /calc/trunk, and you can declare a project policy that only bug fixes are to be committed to /calc/branches/stable-1.0. That is, as people continue to work on the trunk, a human selectively ports bug fixes over to the stable branch. Even after the stable branch has shipped, you'll probably continue to maintain the branch for a long time—that is, as long as you continue to support that release for customers.

Summary

We've covered a lot of ground in this chapter. We've discussed the concepts of tags and branches, and demonstrated how Subversion implements these concepts by copying directories with the svk copy command. We've shown how to use svk merge to copy changes from one branch to another, or roll back bad changes. We've gone over the use of svk switch to create mixed-location working copies. And we've talked about how one might manage the organization and lifetimes of branches in a repository.

Remember the Subversion mantra: branches and tags are cheap. So use them liberally!



[14] SVK does not support cross-depot copying. When using DEPOTPATHs with svk copy or svk move, you can only copy items within the same depot.

[15] In the future, the Subversion project plans to use (or invent) an expanded patch format that describes tree-changes.

[16] The Subversion project has plans, however, to someday implement an svnadmin obliterate command that would accomplish the task of permanently deleting information. In the meantime, see the section called “” for a possible workaround.

[17] Because CVS doesn't version trees, it creates an Attic area within each repository directory as a way of remembering deleted files.

[18] You can, however, use svk switch with the --relocate switch if the URL of your server changes and you don't want to abandon an existing working copy. See the svk switch section in Chapter 9, SVK Complete Reference for more information and an example.

Chapter 5. Repository Administration

Not yet written

Not yet written

Not yet written

Not yet written

Not yet written

Not yet written

Not yet written

Chapter 6. Server Configuration

Not yet written

Chapter 7. Advanced Topics

Not yet written

Not yet written

Not yet written

Not yet written

Not yet written

Not yet written

Not yet written

Chapter 8. Developer Information

Not yet written

Chapter 9. SVK Complete Reference

This chapter is intended to be a complete reference to using the command svk line client and all its subcommands.

The SVK Command Line Client: svk

To use the command line client, you type svk, the subcommand you wish to use [19], and any switches or targets that you wish to operate on—the switches always come after the subcommand that they apply to. There are no global switches to svk, with the exception of the --help (-h) switch, which will give you help for a particular subcommand.

To get help on how to use a command you could run any of:

$ svk -h status
$ svk --help status
$ svk status -h 
$ svk status --help                                                  
$ svk help status

One notable exception to the svk subcommand switches rule is the admin subcommand. This command takes it's own set of subcommands. It's described below in the the section called “svk admin section.

You can find examples of how to use most client commands in Chapter 3, Guided Tour and commands for managing properties in the section called “”.

svk Switches

While SVK has different switches for its subcommands, all switches are global[20]—that is, each switch is guaranteed to mean the same thing regardless of the subcommand you use it with. For example, --verbose (-v) always means “verbose output”, regardless of the subcommand you use it with.

You can specify a command line switch anywhere on the command line after the name of the subcommand itself. So it's OK to mix switches and options. SVK knows what is what.

--all (-a)

Causes SVK to operate on all instances of a particular kind. It depends on the subcommand what exactly this means.

--auto (-a)

Requests svk uses the previous merge point as the starting point for this cmerge or merge operation.

--base (-b) REV[@]

Use REV[@] as the merge base. See the --revision for an explanation of valid values for REV[@].

--baseless (-B)

Use the youngest revision as the merge base.

--change (-c) [-]REV[@]

Act on the change made by revision [-]REV[@]. Specifying an @ after the revision number will cause SVK to operate on the mirrored repository's revision number rather than the local depots revision number if the path being operated on is a mirrored path. Specifying REV is the same as --revision REV-1:REV, whereas specifying -REV is equivalent to --revision REV:REV-1.

--check-only (-C)

Goes through all the motions of running a command, but makes no actual changes—either on disk or in the depot.

--cross (-x)

Causes a SVK subcommand which is traversing the history of a versioned resource to continue harvesting that historical information when a copy—that is, a location in history where that resource was copied from another location in the repository—is encountered.

--depot DEPOTNAME

Apply the svk patch operation to the depot specified by DEPOTNAME.

--depth (-d) LEVEL

Recurse at most LEVEL levels deep. This is used together with the --recursive switch to svk list.

--detach (-d) [DEPOTPATH | PATH]

Request that SVK forget about a depot, mirror or working copy.

--direct

Commit directly even if the path is mirrored.

Warning

Don't ever use this option unless you know what you are doing. Better yet don't use this option unless your IRC handle is clkao.

--encoding ENC

Tells SVK that your commit message is encoded in the charset provided. The default is your operating system's native locale, and you should specify the encoding if your commit message is in any other encoding.

--export

Export mode, checkout a detached copy.

--file (-F) FILENAME

Uses the contents of the file passed as an argument to this switch for the specified subcommand.

--from (-f)

Merges or pushes from the specified PATH.

--from-checkout (-f)

Allows a svk import to be run on a working copy.

--full-path (-f)

Shows the full path of listed files rather than showing files and directories as a tree.

--help (-h or -?)

If used with one or more subcommands, shows the built-in help text for each subcommand. If used alone, it displays the general client help text.

--host HOST

Use HOST as the hostname shown in the merge log.

--import

Import mode. Automatically add any new nodes and delete any missing ones. This switch is used with the commit command. An example of how it could be used to track a third party product is:

$ svk checkout --non-recursive //thirdparty/trunk thirdparty-1.2.3
$ tar xvf thirdparty-1.2.3.tar
$ svk commit --import thirdparty-1.2.3
--incremental (-I)

Applies each change individually.

--init (-i)

Initialize the default depot.

--keep-local (-K)

Prevents svk from removing a file from a working copy when it is scheduled for deletion via svk delete.

--limit (-l) NUM

Show only the first NUM log messages.

--list (-l)

Show a list of pairs. Shows depotpath, working copy pairs with svk checkout, depotpath, mirror source pairs with svk mirror and depotname, repository path pairs with svk depotmap.

--log (-l)

Generate a commit log message consisting of all the log messages of the revision being merged.

--lump (-l)

When causes the svk push and svk pull commands to lump all the changes together in a single commit, rather than commit each change incrementally when calling svk smerge.

--merge (-m)

If the depotpath for the working copy being updated is a copy of another depotpath—i.e. a branch, perform a svk smerge --log --message '' from the original to the copy before executing the actual command.

--message (-m) MESSAGE

Indicates that you will specify a commit message on the command line, following this switch. For example:

$ svk commit --message "They don't make Sunday."
--parent (-p)

Recursively create intermediate directories in the depot as required.

--patch (-P) NAME

Rather than committing a change SVK will generate a patch named NAME. The name - will cause svk to output the patch the standard output rather than storing it.

--non-recursive (-N)

Stops a subcommand from recursing into subdirectories. Most subcommands recurse by default, but some subcommands—usually those that have the potential to remove or undo your local modifications—do not.

--no-ignore

Do not ignore files that would normally be ignored.

--no-ticket

Indicates that you do not with this merge point to be recorded for merge tracking purposes.

--quiet (-q)

Requests that the client print only essential information while performing an operation.

--recover

Recover the state of a mirrored depot path.

--recursive (-R)

Makes a subcommand recurse into subdirectories. Most subcommands recurse by default.

--relocate [FROM] TO

Used with the svk mirror subcommand, changes the location of the remote repository that the mirror in a local depot references. This is useful if the location of your repository changes and you have an existing mirror that you'd like to continue to use. See svk mirror for an example.

Used with the svk checkout to move a working copy to a different location.

Used with the svk depotmap to move a depot to a different location.

--remoterev

Makes a generated merge log use revision numbers from the remote mirror rather than those in the depot.

--revision (-r) REV[@]:[REV2[@]]

Indicates that you're going to supply a revision (or range of revisions) for a particular operation. You can provide revision numbers, revision keywords or dates (in curly braces), as arguments to the revision switch. If you wish to provide a range of revisions, you can provide two revisions separated by a colon. For example:

$ svk log --revision 1729
$ svk log --revision 1729:HEAD
$ svk log --revision 1729:1744
$ svk log --revision {2001-12-04}:{2002-02-17}
$ svk log --revision 1729:{2002-02-17}

If the path for which you specified REV is a mirrored path, you may append an @ to then end of the REV to refer to the revision number in the remote mirror rather than the one in the local depot. For example:

$ svk log --revision 1729@ //mirrors/test
$ svk log --revision 1729@:1744@

See the section called “Revision Keywords” for more information.

--revprop

Operates on a revision property instead of a property specific to a file or directory. This switch requires that you also pass a revision with the --revision (-r) switch. See the section called “” for more details on unversioned properties.

--sign (-S)

Causes SVK to use sign the change being committed.

--skipto (-s) REMOTEREV

During svk sync will start mirroring from the remote repositories revision REMOTEREV, rather than the first not yet mirrored revision.

--strict

Causes SVK to use strict semantics, a notion which is rather vague unless talking about specific subcommands.

--summarize (-s)

Causes svk diff to show a status like summary of changes rather than the actual diffs.

--sync (-s)

Synchronize with mirrored sources before starting the operation.

--template

Used together with the --message (-m) or the --file (-F) switch, it uses the specified message as a template to edit rather than as the actual commit message.

--to (-t)

Merges to the specified PATH.

--to-checkout (-t)

Request that a tree on which svk import is run be turned into a working copy immediately

--torev (-t) REMOTEREV

During svk sync will mirror up to the specified remote repositories revision REMOTEREV, rather than HEAD.

--track-rename

Requests that SVK track changes made to renamed nodes and do the right thing when this occurs.

--unlock

Forcibly remove a stale lock on a mirror.

--upgrade

Upgrade a mirror to the latest version.

--verbatim

Produces a verbatim merge log without any indents or headers.

--verbose (-v)

Requests that the client print out as much information as it can while running any subcommand. This may result in SVK printing out additional fields, detailed information about every file, or additional information regarding its actions.

--version

Prints the client version info.

svk Subcommands

Name

svk add — Add files, directories, or symbolic links.

Synopsis

svk add PATH...

Description

Add files, directories, or symbolic links to your working copy and schedule them for addition to the repository. They will be uploaded and added to the repository on your next commit. If you add something and change your mind before committing, you can unschedule the addition using svk revert.

Alternate Names

None

Changes

Working Copy

Accesses Depot

No

Accesses Mirrored Repository

No

Switches

--non-recursive (-N)
--quiet (-q)

Examples

To add a file to your working copy:

$ svk add foo.c 
A   foo.c

When adding a directory, the default behavior of svk add is to recurse:

$ svk add testdir
A   testdir
A   testdir/a
A   testdir/b
A   testdir/c
A   testdir/d

You can add a directory without adding its contents:

$ svk add --non-recursive otherdir
A   otherdir

The command svk add * will even recurse down into directories that are already under version control, looking for unversioned objects deeper down in the tree.

$ svk add *
A   foo.c
A   somedir/bar.c
A   otherdir/docs/baz.doc
…

Name

svk admin — Administration tools.


Name

svk annotate — Show author and revision information in-line for the specified files or URLs.

Synopsis

svk annotate TARGET[@REV[@]]...

Description

Show author and revision information in-line for the specified files or URLs. Each line of text is annotated at the beginning with the author (username) and the revision number for the last change to that line.

Alternate Names

ann, blame, praise

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--revision (-r) REV[@]
--cross (-x)

Examples

If you want to see annotated source for readme.txt in your test depot:

$ svk ann //calc/integer.c
Annotations for /calc/integer.c (3 active revisions):
****************
     2  (   sally 2005-07-20):          /* integer.c */
    10  (   sally 2005-07-21):
    10  (   sally 2005-07-21):          #define ZERO  0
    10  (   sally 2005-07-21):          #define ONE   1

By default svk annotate will not look further back than the closest copy. If you wish to see the entire history of the file including who changed what before the copy use the --cross switch. In particular if you are running annotate on a branched or tagged revision of a file you might want to see it history back beyond the copy:

$ svk annotate //tags/calc-1.0/integer.c
Annotations for /tags/calc-1.0/integer.c (1 active revisions):
****************
    31  (   sally 2005-07-22):          /* integer.c */
    31  (   sally 2005-07-22):
    31  (   sally 2005-07-22):          #define ZERO  0
    31  (   sally 2005-07-22):          #define ONE   1
$ svk annotate --cross //tags/calc-1.0/integer.c
Annotations for /tags/calc-1.0/integer.c (4 active revisions):
****************
     2  (   sally 2005-07-20):          /* integer.c */
    10  (   sally 2005-07-21):
    10  (   sally 2005-07-21):          #define ZERO  0
    10  (   sally 2005-07-21):          #define ONE   1

Name

svk cat — Output the contents of the specified files or URLs.

Synopsis

svk cat TARGET[@REV[@]]...

Description

Output the contents of the specified files or URLs. For listing the contents of directories, see svk list.

Alternate Names

None

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--revision (-r) REV[@]

Examples

If you want to view readme.txt in your depot without checking it out:

$ svk cat //test/readme.txt
This is a README file.
You should read this.

Tip

If your working copy is out of date (or you have local modifications) and you want to see the HEAD revision of a file in your working copy, svk cat will automatically fetch the HEAD revision when you give it a path:

$ cat foo.c
This file is in my local working copy 
and has changes that I've made.

$ svk cat foo.c
Latest revision fresh from the repository!

Name

svk checkout — Check out a working copy from a repository.

Synopsis

svk checkout DEPOTPATH[@REV[@]] [PATH]
svk checkout URL [PATH]
svk checkout --list
svk checkout --relocate DEPOTPATH|PATH PATH
svk checkout --detach [DEPOTPATH|PATH]
svk checkout --purge

Description

Check out a working copy from a repository. If PATH is omitted, the basename of the DEPOTPATH will be used as the destination.

Using the second form, svk will setup a mirror of the specified URL if you don't have one already, sync the mirror and checkout a working copy from the mirror.

Warning

Unlike Subversion or CVS, SVK working copies do not contain any administrative files or directories. This means things like diff -r and find work great on SVK working copies. However because of this it's not possible to simply rename an svk working copy or remove it without telling svk about it. SVK keeps the metadata associated with a working copy inside your $SVKROOT (which defaults to ~/.svk). Because of this you need to use the commands listed here to manage working copies.

With the --list switch, output one line per checked out working copy. Each line consists of the depotpath followed by an absolute path to the working copy.

If you wish to change the location of a checked out working copy you need to use the svk checkout with the --relocate. Give it both the old and the new path to the working copy. Either before or after that you should move the working copy to it's new location so SVK can find it.

Once you are done using a working copy you should tell svk this since it keeps track of all checked out working copies. To do so you would run svk checkout with the --detach switch. This lets SVK know it no longer needs to keep track of this particular working copy. This command does not actually remove the working copy from disk. That's still your job.

Tip

If you want to create a working copy that svk doesn't track at all you can use the --export switch to the svk checkout command.

If you accidentally remove a working copy or working copies that svk was tracking for you, running svk checkout with the --purge switch will prompt svk to forget about each working copy it can no longer find on disk.

Alternate Names

co

Changes

Creates a working copy.

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--revision (-r) REV[@]
--non-recursive (-N)
--list (-l)
--detach (-d) [DEPOTPATH|PATH]
--quiet (-q)
--export
--relocate DEPOTPATH|PATH PATH
--purge

Examples

Check out a working copy into a directory called mine:

$ svk checkout //test mine
Syncing //test(/test) in /Users/sally/mine to 2.
A  mine/a
A  mine/b
$ ls
mine

List which working copies you have checked out:

$ svk checkout --list
  Depot Path                            Path
========================================================================
  //test                                /Users/sally/mine

Change the location of the checked out working copy:

$ mkdir test
$ svk checkout --relocate mine test/mine
Checkout '/Users/sally/mine' relocated to '/Users/sally/test/mine'.
$ svk checkout --list
  Depot Path                            Path
========================================================================
  //test                                /Users/sally/test/mine

Get rid of the working copy since we don't need it anymore:

$ svk checkout --detach test/mine
Checkout path '/Users/sally/test/mine' detached.
$ svk checkout --list
  Depot Path                            Path
========================================================================
$ rm -rf test/mine

Using the --purge switch after you have removed a working copy:

$ svk checkout --quiet //test mine
Syncing //test(/test) in /Users/sally/mine to 2.
$ rm -rf mine
$ svk checkout --purge
Purge checkout of //test to non-existing directory /Users/sally/mine? (y/n) y
Checkout path '/Users/sally/mine' detached.

Name

svk cleanup — Remove stale locks left behind by an aborted svk sync of a mirror.

Synopsis

svk cleanup [PATH...]

Description

If, for some reason, an svk commit fails due to a network problem or otherwise. You can run this command to remove the lock left behind.

Alternate Names

None

Changes

Lock file in working copy metadata

Accesses Depot

Only the lockfile

Accesses Mirrored Repository

No

Switches

--all (-a)

Examples

Well, there's not much to the examples here as svk cleanup generates no output. If you pass no PATH, “.” is used.

$ svk commit
# Do a kill -9 of svk in a different shell window
$ svk update
/Users/sally/mine already locked, use 'svk cleanup' if lock is stalled
$ svk cleanup
Cleaned up stalled lock on /Users/sally/mine.

Name

svk cmerge — Cherry pick specific changes and merge them

Synopsis

cmerge REVRANGE DEPOTPATH [TARGET]

Description

Merge the changes specified by REVRANGE in DEPOTPATH to TARGET, or . if no TARGET is specified. If TARGET is a depotpath, commit the result directly to that depot.

The range REVRANGE can be specified either as --revision REV1[@]:REV2[@] or --change [-]REV[@].

Warning

This command is currently deprecated, pending improvements to the Subversion API. In the meantime, use svk merge --change to obtain similar functionality.

Alternate Names

cm

Changes

Working copy if TARGET is a working copy or not specified. Depot if TARGET is a depotpath, and mirrored repository if it's a mirrored depotpath.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if committing to a mirrored depotpath

Switches

--change (-c) [-]REV[@]
--log (-l)
--host HOST
--track-rename
--revision (-r) REV1[@]:REV2[@]
--auto (-a)
--verbatim
--no-ticket
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--direct

Examples

This command is deprecated until subversion itself is fixed use svk merge --change instead.


Name

svk commit — Send changes from your working copy to the repository.

Synopsis

svk commit [PATH...]

Description

Send changes from your working copy to the repository. If you do not supply a log message with your commit by using either the --file or --message switch, svk will launch your editor for you to compose a commit message. See the editor-cmd section in the section called “”.

Tip

If you begin a commit and SVK launches your editor to compose the commit message, you can still abort without committing your changes. If you want to cancel your commit, just quit your editor without saving your commit message and Subversion will prompt you to either abort the commit, continue with no message, or edit the message again.

Alternate Names

ci (short for “check in”; not “co”, which is short for “checkout”)

Changes

Working copy, depot, mirrored repository

Accesses Depot

Yes

Accesses Mirrored Repository

Yes, if committing to a mirrored depot path

Switches

--import
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--non-recursive (-N)
--direct

Examples

Commit a simple modification to a file with the commit message on the command line and an implicit target of your current directory (“.”):

$ svk commit --message "added howto section."
Sending        a
Transmitting file data .
Committed revision 3.

Commit a modification to the file foo.c (explicitly specified on the command line) with the commit message in a file named msg:

$ svk commit --file msg foo.c
Committed revision 5.

To commit a file scheduled for deletion:

$ svk commit --message "removed file 'c'."
Committed revision 7.

To recursively commit all changes to the working copy you run:

$ svk commit
Waiting for editor...
    <svk will launch your favorite editor here, with a buffer open
    that looks something like this:>

=== Targets to commit (you may delete items from it) ===
M   /Users/sally/calc/integer.c
A   /Users/sally/calc/foo.c

Tip

Sometimes you may wish only to commit a subset of the changes in a working copy. For example in the case above let's assume you wish to only commit the change to integer.c. You would edit the buffer to look like:

Fixed typo in documentation.
=== Targets to commit (you may delete items from it) ===
M   /Users/sally/calc/integer.c

When you save the commit message and exit the editor, SVK will only commit the files still listed below the === Targets to commit (you may delete items from it) === line in the commit message.


Name

svk copy — Copy a file or directory in a working copy or in a depot.

Synopsis

svk copy src [DST]

Description

Copy a file or directory in a working copy or in the repository. src and DST can each be either a working copy (WC) path or a depot path. In addition src can also be a URL:

WC -> WC

Copy and schedule an item for addition (with history).

WC -> DEPOTPATH

Immediately commit a copy of WC to DEPOTPATH.

Warning

Although svk supports having mixed revision working copies, for example by backreving certain files or directories with a svk update --revision, creating a copy of such a mixed revision working copy using this form of the svk copy command will not create a mixed revision tag or branch. Instead it creates a tag or branch which is a copy of the same revision that the WC path specified is at without regard to the revisions of any subdirectories or files.

DEPOTPATH

If the current directory is inside a working copy, check out DEPOTPATH into the current directory, and schedule it for addition. Otherwise prompt for a destination depot path to copy to.

DEPOTPATH -> WC

Check out DEPOTPATH into WC, and schedule it for addition.

DEPOTPATH -> DEPOTPATH

Complete in depot copy. This is usually used to branch and tag.

URL

Interactively sets up a mirror of URL if you do not have one already. After the optional setup of the mirror, creates a local copy of the mirror in DEPOTPATH, finally checks out that local branch in a new working copy using the basename of the local copy. See svk mirror for more information on valid URL values.

URL -> PATH

Interactively sets up a mirror of URL if you do not have one already. After the optional setup of the mirror, prompts for a DEPOTPATH to create a local copy of the mirror in, finally checks out that local branch in a new working copy called PATH.

URL -> DEPOTPATH

Interactively sets up a mirror of URL if you do not have one already. After the optional setup of the mirror, creates a local copy of the mirror in DEPOTPATH.

Note

You can only copy files within a single depot. SVK does not support cross-depot copying.

Tip

It is possible to copy files from one mirrored repository to another, if both mirrors live inside the same depot. This allows you to copy with history between different mirrored repositories.

Alternate Names

cp

Changes

Depot if destination is a DEPOT or source is a URL.

Working copy if destination is a WC path.

Creates a working copy if source is a URL.

Accesses Depot

If source or destination is in the depot, or if needed to look up the source revision number.

Accesses Mirrored Repository

If destination is in the depot at a mirrored path or if the source is a URL which isn't yet being mirrored.

Switches

--revision (-r) REV[@]
--parent (-p)
--quiet (-q)
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--direct

Examples

Copy an item within your working copy (just schedules the copy—nothing goes into the depot until you commit):

$ svk copy foo.txt bar.txt
A   bar.txt
$ svk status
A   bar.txt

Copy an item in your working copy to a PATH in the depot (an immediate commit, so you must supply a commit message):

$ svk copy --message "Remote copy." near.txt //test/far-away.txt
Committed revision 8.

Copy an item from the depot to your working copy (just schedules the copy—nothing goes into the depot until you commit):

Tip

This is the recommended way to resurrect a dead file in your depot!

$ svk copy //test/far-away near-here
A   near-here

And finally, copying between two DEPOTPATHS:

$ svk copy --message "remote copy." //test/far-away //test/over-there
Committed revision 9.

Tip

This is the easiest way to “tag” a revision in your depot—just svk copy that revision (usually HEAD) into your tags directory.

$ svk copy --message "tag tree" //test/trunk //test/tags/0.6.32-prerelease
Committed revision 12.

And don't worry if you forgot to tag—you can always specify an older revision and tag anytime:

$ svk copy --revision 11 --message "Forgot to tag at rev 11" //test/trunk //test/tags/0.6.32-prerelease
Committed revision 13.

Name

svk delete — Delete an item from a working copy or a depot.

Synopsis

svk delete PATH...
svk delete DEPOTPATH

Description

Items specified by PATH are scheduled for deletion upon the next commit. Files (and directories that have not been committed) are immediately removed from the working copy. The command will not remove any modified items or items scheduled for addition; use the svk revert first for those.

Items specified by DEPOTPATH are deleted from the repository via an immediate commit. Multiple DEPOTPATHS are currently not supported.

Alternate Names

del, remove, rm

Changes

Working copy if operating on files, Depot if operating on a DEPOTPATH, Mirrored repository if operation on a mirrored DEPOTPATH

Accesses Depot

Only if operating on a DEPOTPATH

Accesses Mirrored Repository

Only if operating on a mirrored DEPOTPATH

Switches

--keep-local (-K)
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--direct

Examples

Using svk to delete a file from your working copy merely schedules it to be deleted. When you commit, the file is deleted in the depot.

$ svk delete myfile
D   myfile
$ svk commit --message "Deleted file 'myfile'."
Committed revision 14.

Deleting a DEPOTPATH, however, is immediate, so you have to supply a log message:

$ svk delete --message "Deleting file 'yourfile'" //test/yourfile
Committed revision 15.

Here's an example of how to delete a file that has local mods:

$ svk delete over-there 
over-there is modified, use 'svk revert' first.
$ svk revert over-there 
Reverted over-there
$ svk delete over-there 
D   over-there

Here's an example of how to delete a file which was scheduled for addition but not yet committed:

$ svk delete new-file 
new-file is scheduled, use 'svk revert'.
$ svk revert new-file
Reverted new-file
$ rm new-file

Name

svk depotmap — Create or edit the depot mapping configuration.

Synopsis

depotmap
depotmap DEPOTNAME REPOPATH
depotmap --list
depotmap --detach [DEPOTNAME|REPOPATH]
depotmap --relocate [DEPOTNAME|REPOPATH] REPOPATH2

Description

The first form will launch you preferred editor and show you a list of DEPOTNAME: REPOPATH mappings. You can add or remove new mappings in your editor, rename depots, or move where the repository for a depot is—it won't move it but you can update the location in the depotmap after you have moved the repository yourself. After you save the depotmap and exit the editor svk will ask you to create repositories for each of the new depot entries you have made.

The second form will display a list of depotname and corresponding repository location pairs.

The third form will remove the specified depot from the depotname to repository path mappings. However it will not delete the repository that the depot referred to.

The fourth form allows you to let svk know you moved the repository for a depot to a new location.

Alternate Names

depot

Changes

$SVKROOT/config

Accesses Depot

No

Accesses Mirrored Repository

No

Switches

--init (-i)
--list (-l)
--detach (-d) [DEPOTNAME|REPOPATH]
--relocate [DEPOTNAME|REPOPATH] REPOPATH2

Examples

Create the default depot the first time you use svk:

$ svk depotmap --init
Repository /Users/sally/.svk/local does not exist, create? (y/n)y

Add a depot named tmp in /tmp/tmp— this isn't a good place to store a real depot but works for this example:

$ svk depotmap /tmp/ /tmp/tmp
New depot map saved.
Repository /tmp/tmp does not exist, create? (y/n)y

Show a listing of depots and their corresponding Subversion repositories:

$ svk depotmap --list
Depot                   Path
============================================================
//                      /Users/sally/.svk/local
/tmp/                   /tmp/tmp

Move the repository for the /tmp/ depot we just created to a different location:

$ mv /tmp/tmp /tmp/tmp-repository
$ svk depotmap --relocate /tmp/ /tmp/tmp-repository
Depot 'tmp' relocated to '/tmp/tmp-repository'.

Get rid of the /tmp/ depot and the repository for it:

$ svk depotmap --detach /tmp/
Depot 'tmp' detached.
$ rm -rf /tmp/tmp-repository

Note that in all the examples above you could use plain tmp instead of /tmp/ to refer to the depot as well.


Name

svk describe — Describe a change

Synopsis

svk describe REV [TARGET]

Description

Given DEPOT is the root of the depot containing TARGET or the depot for the current working copy if TARGET isn't specified. This command is equivalent to running svk log --revision REV DEPOT followed by svk diff --revision REV-1:REV DEPOT

Alternate Names

desc

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

None

Examples

Show what exactly changed and why at revision 10 in the depot for the current working copy:

$ svk describe 10 integer.c
----------------------------------------------------------------------
r10:  sally | 2005-07-20 21:46:51 -0700

Added defines.
----------------------------------------------------------------------
=== integer.c
==================================================================
--- integer.c  (revision 9)
    integer.c  (revision 10)
@@ -1  1,4 @@
 /* integer.c */
 
 #define ZERO  0
 #define ONE   1

Name

svk diff — Display the differences between two paths.

Synopsis

diff [--revision REV[@]] [PATH...]
diff --revision REV1[@][:REV2[@]]] DEPOTPATH|PATH...
diff DEPOTPATH1 DEPOTPATH2
diff DEPOTPATH [PATH]

Description

Display the differences between two paths. The four different ways you can use svk diff are:

svk diff [--revision REV[@]] [PATH...] displays the differences between each file or directory specified in the working copy, if none are specified . is implied, with the BASE or REV (if it's specified) revision of that file in the depot

svk diff --revision REV1[@]:REV2[2] DEPOTPATH|PATH... displays the differences between REV1 and REV2 of the DEPOTPATH specified, or of each file or directory specified in the working copy.

svk diff DEPOTPATH1 DEPOTPATH2 shows the differences between 2 depot paths—this is useful for displaying the difference between branches or tags.

svk diff DEPOTPATH [PATH] shows the differences between the current working copy (or the PATH directory and the contents of DEPOTPATH.

Running svk diff ignores the ancestry of files and merely compares the contents of the two files being compared.

Alternate Names

di

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--revision (-r) REV1[@][:REV2[@]]
--summarize (-s)
--verbose (-v)
--non-recursive (-N)

Examples

Compare BASE and your working copy (one of the most popular uses of svk diff):

$ echo 'Added some stuff.' >> file.txt
$ svk diff file.txt 
=== file.txt
==================================================================
--- file.txt  (revision 15)
    file.txt  (local)
@@ -0,0  1 @@
 Added some stuff.

See how your working copy's modifications compare against an older revision:

$ svk diff --revision 14 file.txt
=== file.txt
==================================================================
--- file.txt  (revision 14)
    file.txt  (local)

Compare revision 12 to revision 15 using range notation:

$ svk diff --revision 12:15 //trunk/file.txt
=== file.txt
==================================================================
--- file.txt  (revision 12)
    file.txt  (revision 15)

Compare revision 3000 to revision 3500 of all files in trunk using range notation:

$ svk diff --revision 3000:3500 //test/trunk

If you have a working copy, you can obtain the differences without typing in the long URLs:

$ svk diff --revision 12:15 file.txt 
=== file.txt
==================================================================
--- file.txt  (revision 12)
    file.txt  (revision 15)

Tip

Set the $SVKDIFF environment variable to run and external diff program instead of the built in diff.

$ SVKDIFF="/usr/bin/diff -i -b" svk diff file.txt
1,2c1
< This is a README file.
< You should read this.
---
> Added some stuff.

Name

svk help — Help!

Synopsis

svk help [SUBCOMMAND...]

Description

This is your best friend when you're using SVK and this book isn't within reach!

Invoking this command will display a usage message for the given subcommand.

Alternate Names

?, h

Changes

Nothing

Accesses Depot

No

Accesses Mirrored Repository

No

Switches

None


Name

svk import — Recursively commit a copy of PATH to DEPOTPATH.

Synopsis

svk import [PATH] DEPOTPATH
svk import DEPOTPATH PATH

Description

Recursively commit a copy of PATH to DEPOTPATH. If PATH is omitted “.” is assumed. Parent directories are created in the repository as necessary.

Alternate Names

None

Changes

Depot, and Mirrored Repository if DEPOTPATH refers to a mirror.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if importing to a mirrored path in the depot.

Switches

--from-checkout (-f)
--to-checkout (-t)
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--non-recursive (-N)
--direct

Examples

This imports the local directory myproj into the root of your depot:

$ svk import --message "New import" myproj //
Committed revision 25.
Directory /Users/sally/myproj imported to depotpath // as revision 25.

This imports the local directory myproj into trunk/misc in your depot. The directory trunk/misc need not exist before you import into it—svk import will recursively create directories for you:

$ svk import --message "New import" myproj //trunk/misc/myproj
Committed revision 26.
Import path //trunk/misc/myproj initialized.
Committed revision 27.
Directory /Users/sally/myproj imported to depotpath //trunk/misc/myproj as revision 27.

After importing data, note that the original tree is not under version control. If you wish to use the original tree as a working copy right away you need to specify the --to-checkout switch to import. Alternatively you can svk checkout a fresh working copy of the tree.

By default svk will not let you import from a tree that is already a working copy. If you wish to do so anyway you need to specify the --from-checkout switch.


Name

svk info — Print information about PATHs.

Synopsis

svk info [TARGET...]

Description

Print information about both working copy paths and DEPOTPATHS, including:

  • Checkout Path

  • Depot Path

  • Revision

  • Last Changed Rev.

  • Mirrored From:

  • Copied From:

  • Merged From:

Alternate Names

None

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

None

Examples

svk info will show you all the useful information that it has for your working copy.

$ svk info
Checkout Path: /Users/sally/myproj
Depot Path: //trunk/myproj
Revision: 24254
Last Changed Rev.: 24253
Mirrored From: http://server.sally.com/, Rev. 24751
Merged From: //branches/branch-a, Rev. 24179
Merged From: //branches/branch-b, Rev. 23849

svk info also acts on DEPOTPATHS

$ svk info //trunk/myproj
Depot Path: //trunk/myproj
Revision: 24254
Last Changed Rev.: 24253
Mirrored From: http://server.sally.com/, Rev. 24751
Merged From: //branches/branch-a, Rev. 24179
Merged From: //branches/branch-b, Rev. 23849

Name

svk list — List directory entries in the depot.

Synopsis

svk list [TARGET[@REV]...]

Description

List each TARGET file and the contents of each TARGET directory as they exist in the repository. If TARGET is a working copy path, the corresponding repository URL will be used.

The default TARGET is “.”, meaning the depotpath of the current working copy directory.

With --verbose, the following fields show the status of the item:

  • Revision number of the last commit

  • Author of the last commit

  • Size (in bytes)

  • Date and time of the last commit

Alternate Names

ls

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

Yes

Switches

--revision (-r) REV
--recursive (-R)
--depth (-d) LEVEL
--full-path (-f)
--verbose (-v)

Examples

svk list is most useful if you want to see what files a depot has without checking out a working copy:

$ svk list //test/support
README.txt
INSTALL
examples/
…

You can pass the --verbose switch for additional information, rather like the UNIX command ls -l:

$ svk list --verbose //test/support
     16 sally         28361 Jan 16 23:18 README.txt
     27 sally             0 Jan 18 15:27 INSTALL
     24 harry               Jan 18 11:27 examples/
…

For further details, see the section called “svk list.


Name

svk log — Display commit log messages.

Synopsis

svk log DEPOTPATH
svk log PATH

Description

The default target is the path of your current directory. If no arguments are supplied, svk log shows the log messages for all files and directories inside of (and including) the current working directory of your working copy. You can refine the results by specifying a path, one or more revisions, or any combination of the two. The default revision range for a local path is BASE:1.

If you specify a DEPOTPATH alone, then it prints log messages for everything that the DEPOTPATH contains. The default revision range for a URL is HEAD:1.

With --verbose, svk log will also print all affected paths with each log message. With --quiet, svk log will not print the log message body itself (this is compatible with --verbose).

Note

Logs do not follow copy history by default. Use --cross to enable following of copy history.

Alternate Names

None

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--revision (-r) REV
--limit (-l) NUM
--quiet (-q)
--cross (-x)
--verbose (-v)

Examples

You can see the log messages for all the paths that changed in your working copy by running svk log from the top:

$ svk log
----------------------------------------------------------------------
r20:  harry | 2005-07-19 10:43:54 -0700

Tweak.
----------------------------------------------------------------------
r17:  sally | 2005-07-19 10:35:41 -0700
…

Examine all log messages for a particular file in your working copy:

$ svk log foo.c
----------------------------------------------------------------------
r32:  sally | 2005-07-19 11:43:13 -0700

Added defines.
----------------------------------------------------------------------
r28:  sally | 2005-07-19 11:48:33 -0700
…

If you don't have a working copy handy, you can log a DEPOTPATH:

$ svk log //test/foo.c
----------------------------------------------------------------------
r32:  sally | 2005-07-19 11:43:13 -0700

Added defines.
----------------------------------------------------------------------
r28:  sally | 2005-07-19 11:48:33 -0700
…

Tip

If you run svk log on a specific path and provide a specific revision and get no output at all

$ svk log --revision 20 //untouched.txt
----------------------------------------------------------------------

That just means that the path was not modified in that revision. If you log from the top of the repository, or know the file that changed in that revision, you can specify it explicitly:

$ svk log --revision 20 touched.txt 
----------------------------------------------------------------------
r20:  harry | 2005-07-19 10:43:54 -0700

Tweak.
----------------------------------------------------------------------

Sometimes you might not care about the log messages themselves, but just about the meta information. To only display a one line header for each revision use the --quiet (-q) switch to svk log:

$ svk log --quiet //test/foo.c
----------------------------------------------------------------------
r32:  sally | 2005-07-19 11:43:13 -0700
----------------------------------------------------------------------
r28:  sally | 2005-07-19 11:48:33 -0700
----------------------------------------------------------------------
…

Name

svk merge — Apply differences between two sources.

Synopsis

svk merge --revision N:M DEPOTPATH [WCPATH]
svk merge --revision DEPOTPATH1 DEPOTPATH2
svk merge --revision N:M [--to|--from] [WCPATH]

Description

TODO ## In the first and second forms, the source paths (URLs in the first form, working copy paths in the second) are specified at revisions N and M. These are the two sources to be compared. The revisions default to HEAD if omitted.

In the third form, SOURCE can be a URL or working copy item, in which case the corresponding URL is used. This URL, at revisions N and M, defines the two sources to be compared.

WCPATH is the working copy path that will receive the changes. If WCPATH is omitted, a default value of “.” is assumed, unless the sources have identical basenames that match a file within “.”: in which case, the differences will be applied to that file.

Unlike svk diff, the merge command takes the ancestry of a file into consideration when performing a merge operation. This is very important when you're merging changes from one branch into another and you've renamed a file on one branch but not the other.

Alternate Names

None

Changes

Working copy if merging to a working copy. Depot if merging to a depotpath, and mirrored repository if the destination is a mirrored depotpath.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if merging to a mirrored path.

Switches

--revision (-r) REV
--change (-c) REV
--incremental (-I)
--auto (-a)
--log (-l)
--sync (-s)
--to (-t)
--from (-f)
--verbatim
--no-ticket
--track-rename
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--direct

Examples

Merge a branch back into the trunk (assuming that you have a working copy of the trunk, and that the branch was created in revision 250):

$ svk merge --revision 250:HEAD //branches/my-branch
U  myproj/tiny.txt
U  myproj/thhgttg.txt
U  myproj/win.txt
U  myproj/flo.txt

If you branched at revision 23, and you want to merge changes on trunk into your branch, you could do this from inside the working copy of your branch:

$ svk merge --revision 23:30 //trunk/vendors
U  myproj/thhgttg.txt
…

To merge changes to a single file:

$ cd myproj
$ svk merge --revision 30:31 thhgttg.txt 
U  thhgttg.txt

Name

svk mirror — Manage mirrors

Synopsis

mirror DEPOTPATH URL
mirror --list [DEPOTNAME...]
mirror --relocate DEPOTPATH URL
mirror --detach DEPOTPATH
mirror --recover DEPOTPATH
mirror --upgrade /DEPOTNAME/

Description

The first form sets up a new mirror of the repository at URL in DEPOTPATH. DEPOTPATH must not yet exist, nor can any of it's parent directories already be a mirror. The URL can either be a Subversion repository URL, or something that vcp understands if you have that installed. Subversion repository mirrors are read/write, vcp based mirrors (such as a mirror of a CVS repository) are read only. For more details on valid URL values, see ##TODO.

The second form lists all the mirrors in the depots listed by DEPOTNAME, or all mirrors if no DEPOTNAME is given.

The third form detaches the specified path from it's mirrored URL, causing that path and it's children to be treated as regular DEPOTPATHs from now one. The contents of DEPOTPATH remain unchanged, so any revisions retrieved into the mirror prior to the detaching remain available.

Tip

To completely remove a mirror you can use svk delete on the mirrored path. However when doing so be careful not to delete the parent of an attached mirror since doing so will confuse svk greatly right now.

If you accidentally do an SVN commit onto a mirrored path—because you used the svn client to commit directly to the depot's repository, or the --direct switch to svk, running svk mirror --recover can undo it (reverse apply the commit(s), and set the appropriate revprop), to get the mirror working again.

The final form is used to upgrade the mirrors inside a given DEPOTNAME to the current standard way of tracking mirrored revisions. This command is only relevant if you are upgrading from an older version of SVK. ##TODO—How old? Which version?

Alternate Names

mi

Changes

Depot, except mirror --list, which changes nothing.

Accesses Depot

Yes

Accesses Mirrored Repository

Yes

Switches

--list (-l)
--detach (-d)
--relocate
--recover
--unlock
--upgrade

Examples

To mirror the svkbook sources in the /mirror/svkbook directory of the default depot (the mirror directory will get created automatically if it doesn't yet exist), run:

$ svk mirror svn://svn.clkao.org/svkbook //mirror/svkbook
Committed revision 12.

Note

Setting up a mirrored path doesn't actually mirror anything yet. To do so you need to run svk sync.

To view which repositories you have set up to mirror and where they are being mirrored to you would use:

$ svk mirror --list
Path                    Source
============================================================
//mirror/svkbook        svn://svn.clkao.org/svkbook

Sometimes an administrator might change the “base location” of the repository you are mirroring—in other words, the contents of the repository doesn't change, but the main URL used to reach the root of the repository does. For example, the hostname may change, the URL scheme, or any part of the URL which leads to the repository itself. Rather than create a new mirror, you can use the svn mirror --relocate command to point the depot to the new location of the mirrored repository.

For the sake of this example let's assume that the book repository we mirrored, switched from using the svnprotocol to http instead, and that the hostname changed from svn to svkbook, and that the svkbook virtual host has the repos at it's root. To change our depot to refer to the mirrored repository by it's new URL we would run:

$ svk mirror --relocate //mirror/svkbook http://svkbook.clkao.org/
Committed revision 13.

Note

SVK won't let you relocate a mirror unless the new mirrored repository has the same UUID as the original mirror had. This prevents you from accidentally using relocate to point a mirror at something that isn't really the same repository after all.


Name

svk mkdir — Create a new directory under version control.

Synopsis

svk mkdir PATH...
svk mkdir DEPOTPATH

Description

Create a directory with a name given by the final component of the PATH or DEPOTPATH. A directory specified by a working copy PATH is scheduled for addition in the working copy. A directory specified by a DEPOTPATH is created in the depot via an immediate commit. In both cases all the intermediate directories must already exist, unless the --parent (-p) switch is specified.

Alternate Names

None

Changes

Working copy, depot if operating on a DEPOTPATH, Mirrored repository if the DEPOTPATH is a mirrored path.

Accesses Depot

Only if operating on a DEPOTPATH.

Accesses Mirrored Repository

Only if operating on a DEPOTPATH which is mirrored.

Switches

--parent (-p)
--message (-m) TEXT
--file (-F) FILE
--template
--encoding ENC
--patch (-P)
--sign (-S)
--check-only (-C)
--direct

Examples

Create a directory in your working copy:

$ svk mkdir newdir
A   newdir

Create one in the repository (instant commit, so a log message is required):

$ svk mkdir --message "Making a new dir." //newdir
Committed revision 6.

Name

svk move — Move a file or directory.

Synopsis

svk move src DST

Description

This command moves a file or directory in your working copy or in the repository.

Tip

This command is equivalent to an svk copy followed by svk delete.

Note

SVK does not support moving between working copies and DEPOTs. In addition, you can only move files within a single depot—SVK does not support cross-depot moving. However if you have two mirrored repositories in the same depot, you can move files and directories between them.

WC -> WC

Move and schedule a file or directory for addition (with history).

DEPOTPATH -> DEPOTPATH

Complete in depot rename.

Alternate Names

mv, ren, rename

Changes

Working copy, depot if operating on a DEPOTPATH, Mirrored repository if either DEPOTPATH is a mirrored path.

Accesses Depot

Only if operating on DEPOTPATHs.

Accesses Mirrored Repository

Only if operating on a DEPOTPATH which is mirrored.

Switches

--revision (-r) REV
--parent (-p)
--message (-m) TEXT
--file (-F) FILE
--template
--encoding ENC
--patch (-P)
--sign (-S)
--check-only (-C)
--direct

Examples

Move a file in your working copy:

$ svk move foo.c bar.c
D   foo.c
A   bar.c

Move a file in the repository (an immediate commit, so it requires a commit message):

$ svk move --message "Move a file" //foo.c //bar.c
Committed revision 27.

Name

svk patch — Manage patches.

Synopsis

svk patch --list|--ls
svk patch --cat|--view PATCHNAME
svk patch --regenerate|--regen PATCHNAME
svk patch --update|--up PATCHNAME
svk patch --apply PATCHNAME [TARGET] [-- MERGEOPTIONS]
svk patch --delete|--rm PATCHNAME

Description

##TODO

Alternate Names

None

Changes

Depot and $SVKROOT/patch directory

Accesses Depot

Yes

Accesses Mirrored Repository

Only when using --apply to a mirrored depotpath

Switches

--depot DEPOTNAME

Examples

Let say you want to create a patch for something rather than actually commit it. To do so you would:

$ touch foo
$ svk add foo
$ svk commit --message "Added foo" --patch bug1
Patching locally against mirror source file:///Users/sally/.svk/local/calc.
Patch bug1 created.

Tip

Currently SVK doesn't track which depot a patch is for. If you are using more than one depot and a patch applies to a depot other than the default, or // depot you need to specify the --depot DEPOTNAME switch to let SVK know which depot the patch is meant for.

To view the contents of a patch you would run:

$ svk patch --cat bug1
==== Patch <bug1> level 1
Source: [No source]
Target: f5a4d37e-57fc-0310-86b3-8bf2ff90d511:/calc:53 [local]
Log:
Added foo
=== foo
==================================================================

Now let's revert the uncommitted change and apply the patch to our wc:

$ svk revert foo
$ rm foo
$ svk patch --apply bug1
A   foo

We could also apply the patch directly to the depot—this could be on a different machine, like the one we are mirroring from:

$ svk patch --apply bug1 //calc
A   foo
Committed revision 54.

If we no longer need a patch we can delete it:

$ svk patch --delete bug1

Name

svk propdel — Remove a property from an item.

Synopsis

svk propdel PROPNAME [DEPOTPATH|PATH...]
svk propdel PROPNAME --revprop --revision REV[@] [DEPOTPATH]

Description

This removes properties from files, directories, or revisions. The first form removes versioned properties, while the second removes unversioned properties on a depot revision.

Alternate Names

pd, pdel

Changes

Working copy, depot only if operating on a DEPOTPATH, mirrored repository if the depotpath is mirrored.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if operating on a depotpath which is mirrored

Switches

--recursive (-R)
--revision (-r) REV
--revprop
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--quiet (-q)
--direct

Examples

Delete a property from a file in your working copy

$ svk propdel svn:mime-type some-script
 M  some-script

Delete a revision property:

$ svk propdel --revprop --revision 26 release-date 
property 'release-date' deleted from repository revision 26.

Name

svk propedit — Edit the property of one or more items under version control.

Synopsis

svk propedit PROPNAME DEPOTPATH|PATH...
svk propedit PROPNAME --revprop --revision REV[@] [DEPOTPATH]

Description

Edit one or more properties on files, directories, or revisions. The first form edits versioned properties, while the second edits unversioned properties on a depot revision.

Alternate Names

pe, pedit

Changes

Working copy, depot only if operating on a DEPOTPATH, mirrored repository if the depotpath is mirrored.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if operating on a depotpath which is mirrored

Switches

--recursive (-R)
--revision (-r) REV
--revprop
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--direct

Examples

svk propedit makes it easy to modify properties that have multiple values:

$ svk propedit svn:keywords foo.c 
Waiting for editor...
    <svk will launch your favorite editor here, with a buffer open
    containing the current contents of the svn:keywords property.  You
    can add multiple values to a property easily here by entering one
    value per line.>
 M  foo.c

Name

svk propget — Print the value of a property.

Synopsis

svk propget PROPNAME [TARGET[@REV]...]
svk propget PROPNAME --revprop --revision REV[@] [DEPOTPATH]

Description

Print the value of a property on files, directories, or revisions. The first form prints the versioned property of an item or items in your working copy, while the second prints unversioned remote property on a depot revision. See the section called “” for more information on properties.

Alternate Names

pg, pget

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--recursive (-R)
--revision (-r) REV[@]
--revprop
--strict

The --strict switch will prevent extra newlines from being printed at the end of the property values; when there are multiple paths involved, it causes svk to not prefix the path name before each value.

Examples

Examine a property of a file in your working copy:

$ svk propget svn:keywords foo.c
Author
Date
Rev

The same goes for a revision property:

$ svk propget svn:log --revprop --revision 20 
Began journal.

Name

svk proplist — List all properties.

Synopsis

svk proplist [TARGET[@REV]...]
svk proplist --revprop --revision REV[@] [DEPOTPATH]

Description

List all properties on files, directories, or revisions. The first form lists versioned properties in your working copy, while the second lists unversioned properties on a depot revision.

Alternate Names

pl, plist

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--recursive (-R)
--verbose (-v)
--revision (-r) REV
--revprop

Examples

You can use proplist to see the properties on an item in your working copy:

$ svk proplist foo.c
Properties on foo.c:
  svn:mime-type
  svn:keywords
  owner

But with the --verbose flag, svn proplist is extremely handy as it also shows you the values for the properties:

$ svk proplist --verbose foo.c
Properties on foo.c:
  svn:mime-type : text/plain
  svn:keywords : Author Date Rev
  owner : sally

Name

svk propset — Set PROPNAME to PROPVAL on files, directories, or revisions.

Synopsis

svn propset PROPNAME PROPVAL [DEPOTPATH|PATH...]
svn propset PROPNAME --revprop --revision REV@ PROPVAL [DEPOTPATH|PATH]

Description

Set PROPNAME to PROPVAL on files, directories, or revisions. The first example creates a versioned, local property change in the working copy, or directly in the depot if a depotpath is specified. If neither are specified it set the property on .. The second creates an unversioned, property change on a depot revision, using the DEPOT specified by DEPOTPATH or PATH or the depot associated with ..

Tip

SVK has a number of “special” properties that affect its behavior. See the section called “” for more on these properties.

Alternate Names

ps, pset

Changes

Working copy, depot only if operating on a DEPOTPATH, mirrored repository if the depotpath is mirrored.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if operating on a depotpath which is mirrored

Switches

--revision (-r) REV
--recursive (-R)
--revprop
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--quiet (-q)
--direct

Examples

Set the mimetype on a file:

$ svk propset svn:mime-type image/jpeg foo.jpg 
 M  foo.jpg

On a UNIX system, if you want a file to have the executable permission set:

$ svk propset svn:executable ON script.sh
 M  script.sh

Perhaps you have an internal policy to set certain properties for the benefit of your coworkers:

$ svk propset owner sally foo.c
 M  foo.c

If you made a mistake in a log message for a particular revision and want to change it, use --revprop and set svn:log to the new log message:

$ svk propset --revprop --revision 25 svn:log "Journaled about trip to New York."
Property 'svn:log' set on repository revision 25.

Or, if you don't have a working copy, you can provide a DEPOTPATH.

$ svn propset --revprop --revision 26 svn:log "Document nap." //
property 'svn:log' set on repository revision 26.

Note

If you are working with a mirrored repository changes to revision properties will only affect your own depot. Also if you were to make changes to revision properties in the Subversion repository you are mirroring from, other people would only see the changes you make if they hadn't already synced up to the revision you are changing. This is because changing revision properties does not commit a change to the repository so the mirroring code has no way of knowing that anything changed.


Name

svk pull — Bring changes from another repository.

Synopsis

svk pull [PATH...]
svk pull DEPOTPATH

Description

##TODO

Alternate Names

None

Changes

##TODO

Accesses Depot

##TODO

Accesses Mirrored Repository

##TODO

Switches

--all (-a)
--lump (-l)

Examples

##TODO


Name

svk push — Move changes into another repository.

Synopsis

svk push [DEPOTPATH|PATH]

Description

##TODO

Alternate Names

None

Changes

##TODO

Accesses Depot

##TODO

Accesses Mirrored Repository

##TODO

Switches

--from (-f) PATH
--lump (-l)
--check-only (-C)
--patch (-P) NAME
--sign (-S)
--verbatim

Examples

##TODO


Name

svk resolved — Remove “conflicted” state on working copy files or directories.

Synopsis

svk resolved PATH...

Description

Remove “conflicted” state on working copy files or directories. This routine does not semantically resolve conflict markers; it merely removes conflict-related artifact files and allows PATH to be committed again; that is, it tells Subversion that the conflicts have been “resolved”. See the section called “Resolve Conflicts (Merging Others' Changes)” for an in-depth look at resolving conflicts.

Alternate Names

None

Changes

Working copy

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--recursive (-R)

Examples

If you get a conflict on an update, and you decide to skip resolving it at update time, your file will have conflict markers in it and it will be marked as in conflict by svk:

$ svk update
Syncing //calc(/calc) in /Users/sally/calc to 11.
Conflict found in integer.c:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] 
    You type s<return>
C  integer.c
$ cat integer.c 
/* integer.c */
>>>> YOUR VERSION integer.c 112192333646711

#include <conflict.h>
==== ORIGINAL VERSION integer.c 112192333646711
==== THEIR VERSION integer.c 112192333646711

#define ZERO  0
#define ONE   1
<<<< 112192333646711

Once you've resolved the conflict and integer.c is ready to be committed, run svk resolved integer.c to let SVK know you've taken care of everything.


Name

svk revert — Undo all local edits.

Synopsis

svk revert PATH...

Description

Reverts any local changes to a file or directory and resolves any conflicted states. svk revert will not only revert the contents of an item in your working copy, but also any property changes. Finally, you can use it to undo any scheduling operations that you may have done (e.g. files scheduled for addition or deletion can be “unscheduled”).

Alternate Names

None

Changes

Working copy

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--recursive (-R)
--quiet (-q)

Examples

Discard changes to a file:

$ svk revert integer.c
Reverted integer.c

If you want to revert a whole directory of files, use the --recursive flag:

$ svk revert --recursive .
Reverted newdir/afile
Reverted foo.c
Reverted bar.txt

Lastly, you can undo any scheduling operations:

$ svk add mistake.txt whoops
A   mistake.txt
A   whoops
A   whoops/oopsie.c
$ svk revert mistake.txt whoops
Reverted mistake.txt
Reverted whoops
$ svk status
?   mistake.txt
?   whoops

Note

If you provide no targets to svk revert, it will do nothing—to protect you from accidentally losing changes in your working copy, svk revert requires you to provide at least one target. ##TODO Sadly currently this is not true and the svk revert actually defaults to . if no path is given.

Tip

You can use svk revert --recursive together with svk checkout --non-recursive to create a sparse working copy tree. Lets say you have a project called multi with 4 subdirectories and you only need the p1 and p2 subdirectories. To do so you could run:

$ svk checkout --non-recursive //multi
Syncing //multi(/multi) in /Users/sally/multi to 11.
 U  multi
$ cd multi
$ svk revert -R p1 p2
Reverted p1
Reverted p1/foo.c
Reverted p2
Reverted p2/bar.c
…

Name

svk smerge — Automatically merge all changes between branches.

Synopsis

svk smerge DEPOTPATH [PATH]
svk smerge DEPOTPATH1 DEPOTPATH2
svk smerge --from [TARGET]
svk smerge --to [TARGET]

Description

The first form merges changes from the specified DEPOTPATH to the working copy specified by PATH or . if PATH is omitted.

The second form performs a direct in depot merge from DEPOTPATH1 to DEPOTPATH2.

The third form will merge changes from the closest copy anchor in the depot of the specified TARGET—which must be a depotpath that is a copy of something else, or a working copy who's depotpath is a copy of something. Directly in the depot to the source from which TARGET was copied. Essentially this pushes the changes since the last smerge on the specified branch to it's parent.

The fourth form will merge changes directly in the depot to the closest copy anchor in the depot specified by TARGET—which must be a depotpath that is a copy of something else, or a working copy who's depotpath is a copy of something, from the source of the original upstream copy. Essentially this pulls the parents changes since the last smerge into the specified branch.

Alternate Names

sm

Changes

Working copy if merging to a working copy. Depot if merging to a depotpath, and mirrored repository if the destination is a mirrored depotpath.

Accesses Depot

Yes

Accesses Mirrored Repository

Only if merging to a mirrored path.

Switches

--incremental (-I)
--log (-l)
--baseless (-B)
--base (-b) REV[@]
--sync (-s)
--to (-t)
--from (-f)
--verbatim
--no-ticket
--track-rename
--host HOST
--remoterev
--message (-m)
--file (-F)
--template
--encoding ENC
--patch (-P) NAME
--sign (-S)
--check-only (-C)
--direct

Examples

Let's say you have worked on a project locally in your svk depot until now, and you've decided it's time to publish your project and it's history to a remote Subversion repository. Furthermore let's assume you have already mirrored the repository in question and there are empty trunk tags and branches folders in the mirror. Let's say locally your project is at //project and the new mirror of the Subversion reository you wish to publish to is at //mirrors/project. To publish the entire history of you local project you would run:

$ svk smerge --baseless --incremental --verbatim //project //mirrors/project/trunk
Auto-merging (0, 4) /project to /mirrors/project/trunk (base /:0).
===> Auto-merging (0, 1) /project to /mirrors/project/trunk (base /:0).
Merging back to mirror source svn ssh://localhost/Users/sally/project-repo.
Empty merge.
===> Auto-merging (1, 2) /project to /mirrors/project/trunk (base /:0).
Merging back to mirror source svn ssh://localhost/Users/sally/project-repo.
A   README
New merge ticket: 8b976603-c150-4cc8-864b-160347647051:/project:2
Merge back committed as revision 2.
yncing svn ssh://localhost/Users/sally/project-repo
Retrieving log information from 2 to 2
Committed revision 7 from revision 2.
…

The --baseless switch makes the smerge assume there is no common ancestor (which there isn't yet). The --incremental switch will make svk merge each commit to your local branch as a separate commit to the upstream repository. And finally the --verbatim switch will cause the log messages of the commits to the upstream repository to be identical to the original ones in your local svk depot.


Name

svk status — Print the status of working copy files and directories.

Synopsis

svk status [PATH...]

Description

Print the status of working copy files and directories. With no arguments, it prints only locally modified items (no repository access).

The first three columns in the output are each one character wide, and each column gives you information about different aspects of each working copy item.

The first column indicates that an item was added, deleted, or otherwise changed.

' '

No modifications.

'A'

Item is scheduled for Addition.

'D'

Item is scheduled for Deletion.

'M'

Item has been Modified.

'R'

Item has been Replaced in your working copy.

'C'

The contents (as opposed to the properties) of the item conflict with updates received from the depot.

'I'

Item is being ignored (e.g. with the svn:ignore property).

'?'

Item is not under version control—not displayed if --quiet switch is present.

'!'

Item is missing (e.g. you moved or deleted it without using svk). This also indicates that a directory is incomplete (a checkout or update was interrupted).

'~'

Item is versioned as one kind of object (file, directory, link), but has been replaced by different kind of object.

The second column tells the status of a file's or directory's properties.

' '

No modifications.

'M'

Properties for this item have been modified.

'C'

Properties for this item are in conflict with property updates received from the repository.

The third column is populated only if the item is scheduled for addition-with-history.

' '

No history scheduled with commit.

' '

History scheduled with commit.

Remaining fields are variable width and delimited by spaces: The working revision (with -v) The last committed revision and last committed author (with -v) The working copy path is always the final field, so it can include spaces.

Alternate Names

st, stat

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--quiet [-q]

do not display files not under version control

--no-ignore

disregard default and svn:ignore property ignores

-N [--non-recursive]

do not descend recursively

-v [--verbose]

print full revision information on every item

Examples

This is the easiest way to find out what changes you have made to your working copy:

$ svk status wc
 M  wc/bar.c
A   wc/qax.c

If you want to find out what files in your working copy are out-of-date, you should use svk update --check-only instead of svk status, see svk update.

For many more examples of svk status, see the section called “svk status.


Name

svk switch — Update working copy to a different DEPOTPATH.

Synopsis

svk switch DEPOTPATH [PATH]

Description

This subcommand updates your working copy to mirror a new DEPOTPATH—this must be a DEPOTPATH which shares a common ancestor with your working copy. This is the svk way to move a working copy to a new branch. See the section called “Switching a Working Copy” for an in-depth look at switching.

Alternate Names

sw

Changes

Working copy

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

--revision (-r) REV
--detach (-d)
--quiet (-q)

Examples

If you're currently inside the directory vendors which was branched to vendors-with-fix and you'd like to switch your working copy to that branch:

$ svk switch //branches/vendors-with-fix
Syncing //trunk(/trunk) in /Users/sally/vendors to 31.
U   myproj/foo.txt
U   myproj/bar.txt
U   myproj/baz.c
U   myproj/qux.c

And to switch back, just provide the DEPOTPATH to the location in the repository from which you originally checked out your working copy:

$ svk switch //trunk
Syncing //branches/vendors-with-fix(/branches/vendors-with-fix) in /Users/sally/vendors to 31.
U   myproj/foo.txt
U   myproj/bar.txt
U   myproj/baz.c
U   myproj/qux.c

Note

It's not possible to switch part of your working copy to a branch. Currently SVK doesn't support mixed depot path working copies.


Name

svk sync — Download upstream changes into mirrored DEPOTPATHs.

Synopsis

svk sync [--skipto REV] [--torev REV] DEPOTPATH
svk sync --all [DEPOTNAME|DEPOTPATH]...

Description

The first form downloads upstream changes to the mirror anchored at the specified DEPOTPATH, optionally limited to the specified revision range.. The second form downloads all upstream changes to all mirrors in the specified depots (which can be specified by name or a path in the depot).

Alternate Names

sy

Changes

Depot or depots being updated.

Accesses Depot

Yes

Accesses Mirrored Repository

Yes

Switches

--all (-a)
--skipto (-s) REV
--torev (-t) REV

Examples

To mirror the svkbook sources and just mirror the current HEAD rather than the entire history run:

$ svk mirror svn://svn.clkao.org/svkbook //mirror/svkbook
Committed revision 12.
$ svk sync --skipto HEAD //mirror/svkbook
Retrieving log information from 58 to 58
Committed revision 13 from revision 58.

To download all changes you don't yet have for all your mirrors run:

$ svk sync --all
Starting to synchronize //mirror/svkbook
Syncing svn://svn.clkao.org/svkbook
Retrieving log information from 59 to 60
Committed revision 14 from revision 59.
Committed revision 15 from revision 60.

Note

Running svk sync will never modify any working copies, nor will it ever cause any conflicts or merges to happen. This is because it's the only way a mirrored depotpath will ever get written to[21]. So it's safe (and recommended) to run svk sync whenever you have connectivity. Even committing to a mirrored path using svk commit or any other command the does a direct modification of the depot will not actually change the mirrored path directly. Instead it commits to the mirror first and then runs an implicit svk sync for you.



[21] With the exception of the property changes at the mirrors anchor made by svk mirror --relocate.


Name

svk update — Update your working copy.

Synopsis

svk update [PATH...]

Description

svk update brings changes from the depot into your working copy. If no revision given, it brings your working copy up-to-date with the HEAD revision. Otherwise, it synchronizes the working copy to the revision given by the --revision switch.

For each updated item a line will start with a character reporting the action taken. These characters have the following meaning:

A

Added

D

Deleted

U

Updated

C

Conflict

G

Merged

g

Merged, but the file in your working copy already had the changes being merged so the file is unchanged.

A character in the first column signifies an update to the actual file, while updates to the file's properties are shown in the second column.

Alternate Names

up

Changes

Working copy

Accesses Depot

Yes

Accesses Mirrored Repository

Only if the --sync switch is given.

Switches

--revision (-r) REV
--non-recursive (-N)
--check-only (-C)
--sync (-s)
--merge (-m)
--quiet (-q)

Examples

Pick up repository changes that have happened since your last update:

$ svk update
Syncing //myproj(/myproj) in /Users/sally/myproj to 31.
A   newdir/toggle.c
A   newdir/disclose.c
A   newdir/launch.c
D   newdir/README

You can also update your working copy to an older revision (SVK doesn't have the concept of “sticky” files like CVS does; see Appendix A, SVK for CVS Users):

$ svn update --revision 30
Syncing //myproj(/myproj) in /Users/sally/myproj to 30.
A   newdir/README
D   newdir/toggle.c
D   newdir/disclose.c
D   newdir/launch.c
U   foo.c

Tip

If you want to examine an older revision of a single file, you may want to use svk cat.

To see what would happen if you ran svk update without actually modifying your working copy use the --check-only switch:

$ svk update ---check-only
Syncing //myproj(/myproj) in /Users/sally/myproj to 31.
A   newdir/toggle.c
A   newdir/disclose.c
A   newdir/launch.c
D   newdir/README

Name

svk verify — Verify change signatures.

Synopsis

svk verify CHANGE [DEPOTNAME]

Description

Verify if a particular change (or revision) has been signed and is valid. The revision in question should have been committed with the --sign (-S) switch.

This command and the --sign (-S) switch require gpg to be installed in the users PATH somewhere.

Alternate Names

None

Changes

Nothing

Accesses Depot

Yes

Accesses Mirrored Repository

No

Switches

None

Examples

To verify revision 42 in the local depot:

$ svk verify 42 //

svk admin

svk admin is the administrative tool for monitoring and repairing your svk depots. For detailed information, see the section called “”.

Since svk admin works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL.

svk admin Switches

--bdb-log-keep

(Berkeley DB specific) Disable automatic log removal of database log files.

--bdb-txn-nosync

(Berkeley DB specific) Disables fsync when committing database transactions.

--bypass-hooks

Bypass the repository hook system.

--clean-logs

Removes unused Berkeley DB logs.

--force-uuid

By default, when loading data into repository that already contains revisions, svk admin will ignore the UUID from the dump stream. This switch will cause the repository's UUID to be set to the UUID from the stream.

--ignore-uuid

By default, when loading an empty repository, svk admin will use the UUID from the dump stream. This switch will cause that UUID to be ignored.

--incremental

Dump a revision only as a diff against the previous revision, instead of the usual fulltext.

--parent-dir DIR

When loading a dump file, root paths at DIR instead of /.

--revision (-r) ARG

Specify a particular revision to operate on.

--quiet

Do not show normal progress—show only errors.

--use-post-commit-hook

When loading a dump file, run the repository's post-commit hook after finalizing each newly loaded revision.

--use-pre-commit-hook

When loading a dump file, run the repository's pre-commit hook before finalizing each newly loaded revision. If the hook fails, abort the commit and terminate the load process.

svk admin Subcommands

Name

svk admin create — Create a new, empty repository.

Synopsis

svk admin create REPOS_PATH

Description

Create a new, empty repository at the path provided. If the provided directory does not exist, it will be created for you.[22] As of Subversion 1.2, svk admin creates new repositories with the fsfs filesystem backend by default.

Switches

--bdb-txn-nosync
--bdb-log-keep
--config-dir DIR
--fs-type TYPE

Examples

Creating a new repository is just this easy:

$ svk admin create /usr/local/svn/repos

In Subversion 1.0, a Berkeley DB repository is always created. In Subversion 1.1, a Berkeley DB repository is the default repository type, but an FSFS repository can be created using the --fs-type switch:

$ svk admin create /usr/local/svn/repos --fs-type fsfs


[22] Remember, svk admin works only with local paths, not URLs.


Name

svk admin deltify — Deltify changed paths in a revision range.

Synopsis

svk admin deltify [-r LOWER[:UPPER]] REPOS_PATH

Description

svk admin deltify only exists in 1.0.x due to historical reasons. This command is deprecated and no longer needed.

It dates from a time when Subversion offered administrators greater control over compression strategies in the repository. This turned out to be a lot of complexity for very little gain, and this “feature” was deprecated.

Switches

--revision (-r)
--quiet

Name

svk admin dump — Dump the contents of filesystem to stdout.

Synopsis

svk admin dump REPOS_PATH [-r LOWER[:UPPER]] [--incremental]

Description

Dump the contents of filesystem to stdout in a “dumpfile” portable format, sending feedback to stderr. Dump revisions LOWER rev through UPPER rev. If no revisions are given, dump all revision trees. If only LOWER is given, dump that one revision tree. See the section called “” for a practical use.

If the size of your Subversion dumpfile is a concern, you can use the --deltas switch to (in some cases drastically) reduce the size of the dumpfile that svk admin creates. With this switch, instead of writing the full content of each revision to the dumpfile, svk admin dump will only emit the differences from one revision to the next. There are, however, disadvantages to creating deltified dumpfiles—it's more CPU intensive to create them, svndumpfilter can't operate on them, and non-deltified dumpfiles tend to compress better.

Switches

--revision (-r)
--incremental
--quiet
--deltas

Examples

Dump your whole repository:

$ svk admin dump /usr/local/svn/repos
SVN-fs-dump-format-version: 1
Revision-number: 0
* Dumped revision 0.
Prop-content-length: 56
Content-length: 56
…

Incrementally dump a single transaction from your repository:

$ svk admin dump /usr/local/svn/repos --revision 21 --incremental 
* Dumped revision 21.
SVN-fs-dump-format-version: 1
Revision-number: 21
Prop-content-length: 101
Content-length: 101
…

Name

svk admin help

Synopsis

svk admin help [SUBCOMMAND...]

Description

This subcommand is useful when you're trapped on a desert island with neither a net connection nor a copy of this book.

Alternate Names

?, h


Name

svk admin hotcopy — Make a hot copy of a repository.

Synopsis

svk admin hotcopy REPOS_PATH NEW_REPOS_PATH

Description

This subcommand makes a full “hot” backup of your repository, including all hooks, configuration files, and, of course, database files. If you pass the --clean-logs switch, svk admin will perform a hotcopy of your repository, and then remove unused Berkeley DB logs from the original repository. You can run this command at any time and make a safe copy of the repository, regardless of whether other processes are using the repository.

Switches

--clean-logs

Name

svk admin list-dblogs — Ask Berkeley DB which log files exist for a given Subversion repository (applies only to repositories using the bdb backend).

Synopsis

svk admin list-dblogs REPOS_PATH

Description

Berkeley DB creates logs of all changes to the repository, which allow it to recover in the face of catastrophe. Unless you enable DB_LOGS_AUTOREMOVE, the log files accumulate, although most are no longer used and can be deleted to reclaim disk space. See the section called “” for more information.


Name

svk admin list-unused-dblogs — Ask Berkeley DB which log files can be safely deleted (applies only to repositories using the bdb backend).

Synopsis

svk admin list-unused-dblogs REPOS_PATH

Description

Berkeley DB creates logs of all changes to the repository, which allow it to recover in the face of catastrophe. Unless you enable DB_LOGS_AUTOREMOVE, the log files accumulate, although most are no longer used and can be deleted to reclaim disk space. See the section called “” for more information.

Examples

Remove all unused log files from a repository:

$ svk admin list-unused-dblogs /path/to/repos
/path/to/repos/log.0000000031
/path/to/repos/log.0000000032
/path/to/repos/log.0000000033

$ svk admin list-unused-dblogs /path/to/repos | xargs rm
## disk space reclaimed!

Name

svk admin load — Read a “dumpfile”-formatted stream from stdin.

Synopsis

svk admin load REPOS_PATH

Description

Read a “dumpfile”-formatted stream from stdin, committing new revisions into the repository's filesystem. Send progress feedback to stdout.

Switches

--quiet (-q)
--ignore-uuid
--force-uuid
--use-pre-commit-hook
--use-post-commit-hook
--parent-dir

Example

This shows the beginning of loading a repository from a backup file (made, of course, with svk admin dump):

$ svk admin load /usr/local/svn/restored < repos-backup
<<< Started new txn, based on original revision 1
     * adding path : test ... done.
     * adding path : test/a ... done.
…

Or if you want to load into a subdirectory:

$ svk admin load --parent-dir new/subdir/for/project /usr/local/svn/restored < repos-backup
<<< Started new txn, based on original revision 1
     * adding path : test ... done.
     * adding path : test/a ... done.
…

Name

svk admin lslocks — Print descriptions of all locks.

Synopsis

svk admin lslocks REPOS_PATH

Description

Print descriptions of all locks in a repository.

Switches

None

Example

This lists the one locked file in the repository at /svn/repos

$ svk admin lslocks /svn/repos
Path: /tree.jpg
UUID Token: opaquelocktoken:ab00ddf0-6afb-0310-9cd0-dda813329753
Owner: harry
Created: 2005-07-08 17:27:36 -0500 (Fri, 08 Jul 2005)
Expires: 
Comment (1 line):
Rework the uppermost branches on the bald cypress in the foreground.

Name

svk admin lstxns — Print the names of all uncommitted transactions.

Synopsis

svk admin lstxns REPOS_PATH

Description

Print the names of all uncommitted transactions. See the section called “” for information on how uncommitted transactions are created and what you should do with them.

Examples

List all outstanding transactions in a repository.

$ svk admin lstxns /usr/local/svn/repos/ 
1w
1x

Name

svk admin recover — Bring a repository database back into a consistent state (applies only to repositories using the bdb backend). In addition, if repos/conf/passwd does not exist, it will create a default password file .

Synopsis

svk admin recover REPOS_PATH

Description

Run this command if you get an error indicating that your repository needs to be recovered.

Switches

--wait

Examples

Recover a hung repository:

$ svk admin recover /usr/local/svn/repos/ 
Repository lock acquired.
Please wait; recovering the repository may take some time...

Recovery completed.
The latest repos revision is 34.

Recovering the database requires an exclusive lock on the repository. If another process is accessing the repository, then svk admin recover will error:

$ svk admin recover /usr/local/svn/repos
svn: Failed to get exclusive repository access; perhaps another process
such as httpd, svnserve or svn has it open?

$

The --wait switch, however, will cause svk admin recover to wait indefinitely for other processes to disconnect:

$ svk admin recover /usr/local/svn/repos --wait
Waiting on repository lock; perhaps another process has it open?

### time goes by...

Repository lock acquired.
Please wait; recovering the repository may take some time...

Recovery completed.
The latest repos revision is 34.

Name

svk admin rmlocks — Unconditionally remove one or more locks from a repository.

Synopsis

svk admin rmlocks REPOS_PATH LOCKED_PATH...

Description

Remove lock from each LOCKED_PATH.

Switches

None

Example

This deletes the locks on tree.jpg and house.jpg in the repository at /svn/repos

$ svk admin rmlocks /svn/repos tree.jpg house.jpg
Removed lock on '/tree.jpg.
Removed lock on '/house.jpg.

Name

svk admin rmtxns — Delete transactions from a repository.

Synopsis

svk admin rmtxns REPOS_PATH TXN_NAME...

Description

Delete outstanding transactions from a repository. This is covered in detail in the section called “”.

Switches

--quiet (-q)

Examples

Remove named transactions:

$ svk admin rmtxns /usr/local/svn/repos/ 1w 1x

Fortunately, the output of lstxns works great as the input for rmtxns:

$ svk admin rmtxns /usr/local/svn/repos/  `svk admin lstxns /usr/local/svn/repos/`

Which will remove all uncommitted transactions from your repository.


Name

svk admin setlog — Set the log-message on a revision.

Synopsis

svk admin setlog REPOS_PATH --revision REVISION FILE

Description

Set the log-message on revision REVISION to the contents of FILE.

This is similar to using svn propset --revprop to set the svn:log property on a revision, except that you can also use the option --bypass-hooks to avoid running any pre- or post-commit hooks, which is useful if the modification of revision properties has not been enabled in the pre-revprop-change hook.

Warning

Revision properties are not under version control, so this command will permanently overwrite the previous log message.

Switches

--revision (-r) ARG
--bypass-hooks

Examples

Set the log message for revision 19 to the contents of the file msg:

$ svk admin setlog /usr/local/svn/repos/ --revision 19 msg

Name

svk admin verify — Verify the data stored in the repository.

Synopsis

svk admin verify REPOS_PATH

Description

Run this command if you wish to verify the integrity of your repository. This basically iterates through all revisions in the repository by internally dumping all revisions and discarding the output.

Examples

Verify a hung repository:

$ svk admin verify /usr/local/svn/repos/ 
* Verified revision 1729.

Name

svk admin rmcache — Purge the inode/mtime/size cache for working copies.

Synopsis

svk admin rmcache

Description

Use this command to remove SVK's cache of inode, mtime, size tuples for files for all working copies. Having the cache around dramatically speeds up most working copy related SVK commands, however SVK might sometimes leave unused cache entries around—for example entries from since detached working copies. Running this command purges the cache and frees up some disk space.

Examples

Purge the cache:

$ ls ~/.svk/cache
_Users_sally_calc
…
$ svk admin rmcache
$ ls ~/.svk/cache


[19] Yes, yes, you don't need a subcommand to use the --version switch, but we'll get to that in just a minute.

[20] While this true for the long versions of all switches there is some aliasing going on with the short (one letter versions) of some.

[21] With the exception of the property changes at the mirrors anchor made by svk mirror --relocate.

[22] Remember, svk admin works only with local paths, not URLs.

Chapter 10. Depot Management

This chapter goes into greater depth about the depot. It explains what depots are, and how you manage them and how you can best make use of them.

The primary focus of this chapter is the depotmap command, and is best read with reference to svk depotmap.

What is the depot?

As you will already know, a depot is SVK's primary storage area. It is the place from which all of your code is checked out, and to where you commit your changes and mirror other repositories. Up to this point this book has intentionally kept the inner workings of the depot away from the reader, as they are not essential to using SVK for most tasks, and would undoubtedly confuse the new user unnecessarily.

However, knowing more about how depots work and how to manage them can be of use to all users of SVK in terms of flexibility, and can help the reader gain a deeper understanding of SVK; beyond the basics.

As was explained in the section called “The Depot” depot is simply a Subversion repository, which can be located anywhere in the filesystem. The Subversion file system used for this repository is defined by the $SVNFSTYPE environment variable. If $SVNFSTYPE is not set, the file system is determined by the version of the Subversion client installed (fsfs for version 1.1 and newer, bdb for older versions of Subversion).

Outside of this Subversion repository, SVK also keeps higher-level information about the depot in the $SVKROOT/config file. The two key pieces of information stored about a depot are:

DEPOTNAME

The DEPOTNAME is a symbolic name give to the depot which makes up a part of the DEPOTPATHs that you pass to SVK commands.

REPOPATH

The REPOPATH is the full absolute path to the Subversion repository itself.

Multiple depots

Is is possible to have multiple depots in a single user's SVK configuration. Of course, you need to have at least one depot in order to use SVK, and after SVK was first installed you created this depot before doing anything else. This is the depot that you have been using throughout the book up to this point, and is called the Default Depot.

The default depot

The default depot is special because it has no DEPOTNAME. Or rather, its DEPOTNAME is the empty string. By default its REPOPATH is $SVKROOT/local.

The Default Depot is created using the depotmap --init command. This is the only time that the --init switch is used with the depotmap command

Named depots

For many users, the default depot is all that is needed. However, some users find it useful to be able to create additional named depots.

You can create as many additional named depots as you like. Depots are created using svk depotmap command.

For example, to create a new depot with DEPOTNAME 'test' and REPOPATH /tmp/test-depot, you can use this command:

$ svk depotmap test /tmp/test-depot
New depot map saved.
Repository /tmp/test-depot does not exist, create? (y/n)y

Note that depotmap prompts you to create the REPOPATH if it does not already exist. This allows you to create more than one DEPOTNAME pointing at the same REPOPATH if you want:

$ svk depotmap test2 /tmp/test-depot
New depot map saved.

In Depot Paths

Why use multiple depots?

At this point you may be wondering why you'd want to use multiple depots. After all, a depot is just a Subversion repository, and that means you are free to structure your depot in any way you wish, with the root folder perhaps containing a folder for each project you're working on, with each project possibly containing a mirror for that project.

Indeed, many people do use SVK just like this: with everything placed in the default depot, and often never even realizing that it is possible to have more than one depot.

There are however some good reasons why you might want to use more than one depot:

Separating interests

Imagine that you are mirroring two repositories: an Open Source project and also a project for your employer. You might want to keep the two mirrors in separate depots so that the two projects can't affect each other.

Disk space

You are free to create depots anywhere you have permission to. You may want to create a depot on a partition that has a lot of space, for example if you are mirroring a particularly large repository.

Easy disposal

A project in its own depot can easily be thrown away completely without having any effect on other projects. If the projects were in the same depot you could of course delete the relevant paths in the depot, but the history of the deleted paths would remain, which may be precisely what you are trying to remove.

Different purposes

You may want to use different depots for different purposes. For example, you might have one depot for mirrors, and another for your personal depot containing your local repository that only you commit to.

Network sharing

If you are using the fsfs Subversion filesystem for your depot, it is possible to host a depot on a remote filesystem mounted via NFS. This allows you to share the same depot with other developers.

Why not use multiple depots?

While using multiple depots has many advantages, there are a few things that you should consider before using them. Different depots really are completely separate entities: you can't create a branch in one depot that is a copy of a directory in another, and you can't do merging between them.

General depot manipulation

Most of the time depots just sit there and are used by the other SVK commands that you use in general operation, but occasionally depots needs to be operated on directly. This section describes how to do the more general depot administration operations.

For reference documentation on the depotmap command that is used throughout this section, see svk depotmap.

Listing depots

When dealing with depots it's often useful to be able to find out what depots you have on your system. This is accomplished using the depotmap command with the --list option. For example:

$ svk depotmap --list
Depot               	Path
============================================================
//                    /home/me/.svk/local
/my_project/          /home/me/.svk/my_project
/my_company/          /var/share/depot

The left column lists the depot path, while the right column lists the actual path to the depot on your filesystem. In this case we see that two of the depots this user has mapped to are located in their home directory, while the other is located in a shared place in the filesystem. The first depot listed is the default depot.

Detaching depots

If you reach a point where you no longer want to treat a depot as a depot (for example if you want to use it as a repository or you want to delete it completely) you can tell SVK to forget about it using the --detach option. For example:

$ svk depotmap --detach /my_project
Depot 'my_project' detached.

Use the --list to see that the depot is no longer known by SVK

$ svk depotmap --list
Depot               	Path
============================================================
//                    /home/me/.svk/local
/my_company/          /var/share/depot

Note that if you do this by mistake you can undo the operation by mapping the depot again. For example, to undo the --detach operation above do this:

$ svk depotmap my_project /var/share/depot
New depot map saved.

$ svk depotmap --list
Depot               	Path
============================================================
//                    /home/me/.svk/local
/my_project/          /home/me/.svk/my_project
/my_company/          /var/share/depot

The --list command shows that the depot is once again known about by SVK.

Relocating depots

Describe relocating depots.

Advanced depot administration

This is basically going to be about svk admin.

Appendix A. SVK for CVS Users

Not yet written

Appendix B. WebDAV and Autoversioning

Not yet written

Appendix C. Repository Administration

Not yet written

Appendix D. Copyright


Copyright (c) 2002-2005
Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato.  

This work is licensed under the Creative Commons Attribution License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by/2.0/ or send a letter to
Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305,
USA.

A summary of the license is given below, followed by the full legal
text.

--------------------------------------------------------------------

You are free:

    * to copy, distribute, display, and perform the work
    * to make derivative works
    * to make commercial use of the work

Under the following conditions:
	
Attribution. You must give the original author credit.

    * For any reuse or distribution, you must make clear to others the
      license terms of this work.

    * Any of these conditions can be waived if you get permission from
      the author.

Your fair use and other rights are in no way affected by the above.

The above is a summary of the full license below.

====================================================================

Creative Commons Legal Code
Attribution 2.0

CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
DAMAGES RESULTING FROM ITS USE.

License

THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF
SUCH TERMS AND CONDITIONS.

1. Definitions

   a. "Collective Work" means a work, such as a periodical issue,
      anthology or encyclopedia, in which the Work in its entirety in
      unmodified form, along with a number of other contributions,
      constituting separate and independent works in themselves, are
      assembled into a collective whole. A work that constitutes a
      Collective Work will not be considered a Derivative Work (as
      defined below) for the purposes of this License.

   b. "Derivative Work" means a work based upon the Work or upon the
      Work and other pre-existing works, such as a translation,
      musical arrangement, dramatization, fictionalization, motion
      picture version, sound recording, art reproduction, abridgment,
      condensation, or any other form in which the Work may be recast,
      transformed, or adapted, except that a work that constitutes a
      Collective Work will not be considered a Derivative Work for the
      purpose of this License. For the avoidance of doubt, where the
      Work is a musical composition or sound recording, the
      synchronization of the Work in timed-relation with a moving
      image ("synching") will be considered a Derivative Work for the
      purpose of this License.

   c. "Licensor" means the individual or entity that offers the Work
      under the terms of this License.

   d. "Original Author" means the individual or entity who created the Work.

   e. "Work" means the copyrightable work of authorship offered under
      the terms of this License.

   f. "You" means an individual or entity exercising rights under this
      License who has not previously violated the terms of this
      License with respect to the Work, or who has received express
      permission from the Licensor to exercise rights under this
      License despite a previous violation.

2. Fair Use Rights. Nothing in this license is intended to reduce,
   limit, or restrict any rights arising from fair use, first sale or
   other limitations on the exclusive rights of the copyright owner
   under copyright law or other applicable laws.

3. License Grant. Subject to the terms and conditions of this License,
   Licensor hereby grants You a worldwide, royalty-free,
   non-exclusive, perpetual (for the duration of the applicable
   copyright) license to exercise the rights in the Work as stated
   below:

   a. to reproduce the Work, to incorporate the Work into one or more
      Collective Works, and to reproduce the Work as incorporated in
      the Collective Works;

   b. to create and reproduce Derivative Works;

   c. to distribute copies or phonorecords of, display publicly,
      perform publicly, and perform publicly by means of a digital
      audio transmission the Work including as incorporated in
      Collective Works;

   d. to distribute copies or phonorecords of, display publicly,
      perform publicly, and perform publicly by means of a digital
      audio transmission Derivative Works.

   e.

      For the avoidance of doubt, where the work is a musical composition:

         i. Performance Royalties Under Blanket Licenses. Licensor
            waives the exclusive right to collect, whether
            individually or via a performance rights society
            (e.g. ASCAP, BMI, SESAC), royalties for the public
            performance or public digital performance (e.g. webcast)
            of the Work.

        ii. Mechanical Rights and Statutory Royalties. Licensor waives
            the exclusive right to collect, whether individually or
            via a music rights agency or designated agent (e.g. Harry
            Fox Agency), royalties for any phonorecord You create from
            the Work ("cover version") and distribute, subject to the
            compulsory license created by 17 USC Section 115 of the US
            Copyright Act (or the equivalent in other jurisdictions).

   f. Webcasting Rights and Statutory Royalties. For the avoidance of
      doubt, where the Work is a sound recording, Licensor waives the
      exclusive right to collect, whether individually or via a
      performance-rights society (e.g. SoundExchange), royalties for
      the public digital performance (e.g. webcast) of the Work,
      subject to the compulsory license created by 17 USC Section 114
      of the US Copyright Act (or the equivalent in other
      jurisdictions).

The above rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right to make
such modifications as are technically necessary to exercise the rights
in other media and formats. All rights not expressly granted by
Licensor are hereby reserved.

4. Restrictions.The license granted in Section 3 above is expressly
   made subject to and limited by the following restrictions:

   a. You may distribute, publicly display, publicly perform, or
      publicly digitally perform the Work only under the terms of this
      License, and You must include a copy of, or the Uniform Resource
      Identifier for, this License with every copy or phonorecord of
      the Work You distribute, publicly display, publicly perform, or
      publicly digitally perform. You may not offer or impose any
      terms on the Work that alter or restrict the terms of this
      License or the recipients' exercise of the rights granted
      hereunder. You may not sublicense the Work. You must keep intact
      all notices that refer to this License and to the disclaimer of
      warranties. You may not distribute, publicly display, publicly
      perform, or publicly digitally perform the Work with any
      technological measures that control access or use of the Work in
      a manner inconsistent with the terms of this License
      Agreement. The above applies to the Work as incorporated in a
      Collective Work, but this does not require the Collective Work
      apart from the Work itself to be made subject to the terms of
      this License. If You create a Collective Work, upon notice from
      any Licensor You must, to the extent practicable, remove from
      the Collective Work any reference to such Licensor or the
      Original Author, as requested. If You create a Derivative Work,
      upon notice from any Licensor You must, to the extent
      practicable, remove from the Derivative Work any reference to
      such Licensor or the Original Author, as requested.

   b. If you distribute, publicly display, publicly perform, or
      publicly digitally perform the Work or any Derivative Works or
      Collective Works, You must keep intact all copyright notices for
      the Work and give the Original Author credit reasonable to the
      medium or means You are utilizing by conveying the name (or
      pseudonym if applicable) of the Original Author if supplied; the
      title of the Work if supplied; to the extent reasonably
      practicable, the Uniform Resource Identifier, if any, that
      Licensor specifies to be associated with the Work, unless such
      URI does not refer to the copyright notice or licensing
      information for the Work; and in the case of a Derivative Work,
      a credit identifying the use of the Work in the Derivative Work
      (e.g., "French translation of the Work by Original Author," or
      "Screenplay based on original Work by Original Author"). Such
      credit may be implemented in any reasonable manner; provided,
      however, that in the case of a Derivative Work or Collective
      Work, at a minimum such credit will appear where any other
      comparable authorship credit appears and in a manner at least as
      prominent as such other comparable authorship credit.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR
WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED,
STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF
TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT
DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
   APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
   LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
   OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE
   WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
   DAMAGES.

7. Termination

   a. This License and the rights granted hereunder will terminate
      automatically upon any breach by You of the terms of this
      License. Individuals or entities who have received Derivative
      Works or Collective Works from You under this License, however,
      will not have their licenses terminated provided such
      individuals or entities remain in full compliance with those
      licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any
      termination of this License.

   b. Subject to the above terms and conditions, the license granted
      here is perpetual (for the duration of the applicable copyright
      in the Work). Notwithstanding the above, Licensor reserves the
      right to release the Work under different license terms or to
      stop distributing the Work at any time; provided, however that
      any such election will not serve to withdraw this License (or
      any other license that has been, or is required to be, granted
      under the terms of this License), and this License will continue
      in full force and effect unless terminated as stated above.

8. Miscellaneous

   a. Each time You distribute or publicly digitally perform the Work
      or a Collective Work, the Licensor offers to the recipient a
      license to the Work on the same terms and conditions as the
      license granted to You under this License.

   b. Each time You distribute or publicly digitally perform a
      Derivative Work, Licensor offers to the recipient a license to
      the original Work on the same terms and conditions as the
      license granted to You under this License.

   c. If any provision of this License is invalid or unenforceable
      under applicable law, it shall not affect the validity or
      enforceability of the remainder of the terms of this License,
      and without further action by the parties to this agreement,
      such provision shall be reformed to the minimum extent necessary
      to make such provision valid and enforceable.

   d. No term or provision of this License shall be deemed waived and
      no breach consented to unless such waiver or consent shall be in
      writing and signed by the party to be charged with such waiver
      or consent.

   e. This License constitutes the entire agreement between the
      parties with respect to the Work licensed here. There are no
      understandings, agreements or representations with respect to
      the Work not specified here. Licensor shall not be bound by any
      additional provisions that may appear in any communication from
      You. This License may not be modified without the mutual written
      agreement of the Licensor and You.

Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.

Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, neither party will use the trademark
"Creative Commons" or any related trademark or logo of Creative
Commons without the prior written consent of Creative Commons. Any
permitted use will be in compliance with Creative Commons'
then-current trademark usage guidelines, as may be published on its
website or otherwise made available upon request from time to time.

Creative Commons may be contacted at http://creativecommons.org/.

====================================================================