It's time to move from the abstract to the concrete. In this section, we'll show real examples of SVK being used.
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, 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
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,
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”.
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
(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
$ 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
Suppose you make changes to
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
To publish your changes to others, you can use SVK's commit command:
$ svk commit button.c Committed revision 57.
Now your changes to
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
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
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.
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
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
appear in your working copy, and your change will still be
button.c. In this example,
the text of
Makefile is identical in
revisions 4, 5, and 6, but SVK will mark your working
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.
For each working copy, SVK records
three essential pieces of information in the
hash: subsection of the
checkout: section in the
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:
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.
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.
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.
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”.
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.
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
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
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.
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.
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.
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.
 More on how this can happen in chapter 3
 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.
 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.
 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.