Grant’s SVK Notes
This isn’t supposed to be a comprehensive tutorial on
SVK: See #External below for that,
or run the
svk intro command). Even though I often address the reader in the second person, it’s more a
reminder to myself of my SVK habits and setup. If you read this, and find any of it useful, that’s grand, though.
Disclaimer: I’m pretty sure I got most of the example commands right, but you really should
double-check things yourself. Most SVK commands accept the
-C option, which is
the “just tell me what you would have done” mode (à la
-n in subversion).
What I like about SVK
Works well with svn: SVK reportedly works with other version control systems (Perforce, CVS, ...),
but I’ve only tried it on (remote) subversion repositories. SVK’s commands are very similar to svn’s:
There are extra commands that have no analog in svn (
mirror/sync/push/pull/smerge), and some of the
command-line switches differ, but the familiar svn commands (
checkout, commit etc.) are all there.
Under the covers, SVK uses a subversion repository (stored in
~/.svk) to maintain all its
revisions, so it’s possibly not surprising that it uses a svn-like command syntax.
Offline use: SVK is built around “mirroring” a remote repository, or part of one, which you
create using the
svn mirror command.
This means you get a local copy of the tree on your machine: you can browse and/or diff revisions,
or copy/move parts of the tree without needing to be on the network. You do need to be connected to
commit to a mirrored repository; the same is true when you run the
svk sync command,
allows you to pick up the changes made in a remote repository since your last sync.
Knows where your checkouts are: I tend to check out a lot of copies of Chandler, to try
out fixes or improvements. It turns out this is a good way to pile up lots of checkouts:
Occasionally I’ll thrash about on a few ideas in different checkouts, and then go on vacation for a
week, and come back and have a lot of trouble figuring out where sets of changes went. In SVK, the
command
svk co --list will tell me where they went. A downside of this is that you
can’t just move checked-out copies around in the filesystem — you need
svk co --relocate
if you want to do that — but for me the benefits way outweigh the cost.
Local branches: A common model in SVK is to make a
local branch of a mirrored checkout. That
means that the branch (i.e. copy of some part of a repository) exists only in your local repository,
not on the server, so you can commit changes there without them going back to the server. However,
SVK is aware where your branch came from, and there are commands that help you with local branches:
-
svk pull will update the mirror you created the branch from, and then merge in changes into your checkout of the branch.
-
svk push does the opposite: it allows you to commit your changes in the local branches back to the remote repository it was originally copied from.
-
svk smerge (smerge means “star merge”) is the remote-repository-and-local-branch-aware version of svn merge: it allows you to merge changes across different trees, possibly from different repositories.
Less backup headache: I tend to work in local branches, and commit often. That means that the only
thing I need to back up is my
~/.svk directory in order to avoid losing any work.
Handy linkies
External
- The SVK Home Page, http://svk.elixus.org/, has many useful links.
- To get set up, I found the 3-part posts on Bieber Labs very illuminating: 1, 2, 3.
- There’s an online reference manual (similar in spirit to the one for Subversion) at http://svkbook.elixus.org/. When I started out, this was still in a pretty rudimentary state, but it seems to have acquired a whole lot of interesting-looking content recently.
- Vinu points out that the #svk channel on irc.freenode.net is good for getting your questions answered.
Other OSAF SVK Journal entries
Installation
I’m running Mac OS X 10.4, and have svn version 1.3.1 (I built it myself). I initially
tried messing with Perl and CPAN, but that failed with some error I could’t understand.
So, I found an OS X dmg containing an installer package on
http://homepage.mac.com/hiirem/svkbuilds.html, and installed version 1.08. Easy nuff.
Mirrors
In the case of Chandler, where I’m interested in checking out and working on svn branches (e.g. now,
we’re working on 0.7alpha4, and that has its own svn branch), so I mirrored the whole repository, via
bash$ svk mirror svn+ssh://svn.osafoundation.org/svn/chandler //mirror/chandler
What this command done is suck down every revision of chandler from the subversion repository on
svn.osafoundation.org into SVK’s local database (stored in
~/.svk). For chandler,
that’s around 12k revisions right now, so this took a while! The
//mirror/chandler is what’s
called a
depot path: It’s how you refer to files stored in your local database (the depot).
You don’t have to mirror the whole repository, though. In the case of our
docs repository,
where I’m only interested in the
specs folder, I did:
bash$ svk mirror svn+ssh://svn.osafoundation.org/svn/docs/trunk/docs/specs //mirror/specs
and similarly, with our
sandbox repository, I only mirrored my personal subdirectory.
Also, you can mirror read-only repositories (http: URLs in our case); I don’t have any use for that
right now (maybe I’ll mirror cosmo, or python, readonly some day, though).
Like many other commands in SVK,
mirror accepts a
--list argument, which
in this case lists all the remote repositories you have mirrored:
bash$ svk mirror --list
Path Source
============================================================
//mirror/osaf/chandler svn+ssh://svn.osafoundation.org/svn/chandler
//mirror/osaf/specs svn+ssh://svn.osafoundation.org/svn/docs/trunk/docs/specs
//mirror/sandbox svn+ssh://svn.osafoundation.org/svn/sandbox/grant
...
One final thing to note is that
svk mirror is (in my usage) the
only SVK command that refers to a URL-style remote repository path. The paths
in other SVK commands are either depot paths, or disk paths. Presumably, the
reason depot paths start with ‘//’ is so that SVK can tell which you mean
when a command takes either kind (like
svk merge).
Checkouts
You check things out in SVK in a similar way to svn, except you pass in a depot path instead
a repository URL. So, for example, I checked out chandler via:
bash$ svk co //mirror/osaf/chandler/trunk/chandler
At this point, I can go and make changes inside
chandler as usual, and commit
them via
svk commit. One thing that might trip you up is that
bash$ svk update
is a purely local operation: you don’t get more recent commits from
svn.osafoundation.org.
If you want those, either issue
bash$ svk sync //mirror/chandler
first to get those commits into your local depot. Or, to combine those two operations into one, do
bash$ svk pull
(but see the warning in #BranchPull below first!).
Revisions
SVK’s revisions number work pretty much the same as svn’s: each represents the state of
all the files and metadata in your entire SVK depot (a.k.a. local repository), and they
increment by 1 every time. This isn’t a coinkydink: really the depot is a local svn
repository, with a few extra properties that SVK uses to track mirroring, syncing and
merging.
When you mirror or sync a remote repository, each new remote revision SVK discovers
gets its own local revision. This is the revision number that is used in SVK commands:
It is almost always different from the remote revision number, and also varies from
user to user.
Of course, you often want to know the “real” (remote) revision number:
If someone else wants to know if they have picked up an important fix from
you, telling them your depot revision isn’t so useful.
A handy trick here is that most SVK commands that take revision numbers
understand that a revision number ending in ‘@’ means a remote
revision. For example:
bash$ svk log -r12345@ //mirror/chandler
will give you the same commit log as
bash$ svn log -r12345 svn+ssh://svn.osafoundation.org/svn/chandler
except that it completes in a fraction of the time, and won’t hang if the svn server
is down!
Local branches
The
svk copy works pretty much like its svn counterpart, and
is used to make tags or branches. However, since it copies between two
depot paths, you can copy from a mirrored to a non-mirrored path, which
creates a
local branch.
For example, when I was working on stamping, which involved making
pretty widespread changes to the codebase, I worked a lot on a local
branch, created with
svk cp -p //mirror/chandler/trunk/chandler //local/stamping/chandler
(the
-p tells SVK to create the intermediate depot paths
//local and
//local/stamping if necessary).
Then, after checking out
//local/stamping/chandler, I could
commit as often as I liked, which encourages a mode where your (local) commit
logs make a record of the changes you’re making.
Of course, you can use
svk cp to make the kind of branches
familiar to svn users, by passing in two paths inside a mirrored repository.
Or, you could copy trees from one remote repository to another (see
Merging between repositories).
Merging
In a local branch, you still want to be able to pick up changes as necessary
from the remote repository as necessary. Here, the
smerge command
comes to the rescue. In the above case, once I’d synced
//mirror/chandler,
I could get those changes using
svk smerge //mirror/chandler/trunk/chandler //local/stamping/chandler
This basically says: “Merge the changes that have occurred in the
remote repository into my local branch”. SVK would proceed by prompting
you for a commit message, pulling changes as necessary, and committing
those to the local branch.
If conflicts arise, you get prompted on a per-file basis as to what to
do. One option is to edit the file, where the text in the conflict appears
in a form familiar to svn users, with yours, the original and
the new text shown.
<<Grant: an example? or a link to one>>
I’m glossing over the procedure here a little. What I actually was doing
was:
svk smerge -C -l --remoterev //mirror/chandler/trunk/chandler //local/stamping/chandler
where the options meant:
| -C | (check only) Show what files would change, which is handy to show conflicts. |
| -l | Make the commit log (that you get to edit) be the concatenation of the logs of the changes being merged. |
| --remoterev | In the above commit log, show the remote revision numbers instead of local |
and then following up without the
-C if I still felt it was a good idea to merge.
A few notes:
- You can also specify a local checkout as the destination of
smerge; that way you can commit the files yourself afterwards.
- SVK uses a special property,
svk:merge, to track what merges you have done on a given depot path. That way, if you reissue the above command at a later date, it’s not going to confuse itself trying to replay a bunch of changes you already have. The values of that property are a combination of UUID-like things and depot paths, and are called “merge tickets” (On completion, smerge prints out a message about creating a new merge ticket).
- I think that the
svk pull command would combine svk sync and svk smerge here, but:
- You don’t get the chance to edit the commit log in this case
- I’m a little wary of
pull because of #BranchPull below
- At the time, I wasn’t aware of
svk pull :).
- There’s nothing to stop you using
smerge to run merge between two mirrored trees. In fact, I always found the svn merge command very confusing (every time I read the output of svn merge --help my eyes start to glaze over). For example, now that I’m doing some work on a branch chandler I do the following to do merges regularly (with a simple edit to change the commit log to be something like “merge in trunk rXXXXXX--YYYYYY”):
bash$ svk smerge --remoterev -l //mirror/chandler/trunk/chandler //mirror/chandler/branches/recurrence-0.7alpha5/chandler
Switching between branches
Ultimately, when it came to committing my stamping branch changes, I could have used
smerge to
merge the branch’s changes back into the trunk. Another option would be to use
svk push, but
see #PushCommand for why this probably wouldn’t have been a good idea without tweaking command-line arguments.
Instead, I used the following sequence of commands, after a
sync and
smerge to
get the branch up-to-date:
bash$ svk checkout //local/stamping/chandler
bash$ cd chandler
bash$ svk status
(shows no changes)
bash$ svk switch //mirror/chandler/trunk/chandler
bash$ svk status
(shows all the changes in my branch compared to the trunk)
(run unit tests, make last-minute comment changes, etc)
bash$ svk commit
(commits to the trunk)
Hmm.... Does this actually work? I might be misremembering the command — Grant
The
switch command basically let you change the depot path out from
underneath a checked-out tree. It’s very handy in cases like this.
Merging between repositories
One other case I ran into when working on my local stamping branch was that
at some point I wanted to have other people try out the code. One way would
have been to create a branch in the Chandler svn repository, but in the
end I made copies over to a separate repository at OSAF, the sandbox,
which isn’t tracked as rigorously: I didn’t really want to use the main
Chandler one, because that would have involved sending relatively frequent
large commit notices to the (fairly large) commits list.
So, to create the copy, I did:
bash$ svk cp -p //local/stamping/chandler //sandbox/stamping/chandler
which allowed svn users to check that chandler out of my sandbox. For subsequent
pushes to the sandbox,
smerge was the ticket:
bash$ svk smerge //local/stamping/chandler //sandbox/stamping/chandler
Patches
The
smerge and
commit commands both take a
--patch, which
means that a patch in your depot will be created out of the new changes, instead of making new
revisions. You can then use the
patch command to manipulate that patch.
I haven’t used this command much, except to upload patches to Bugzilla. Someday, when I’m feeling enthusiastic,
I’ll write an SVKZilla script, like
subzilla,
which would automate this process.
My SVK dashboard
At some point I was thinking about triage status and how it relates to my development process.
I really work with code checkouts in two ways:
- For longer features (the stamping changes I’ve alluded to earlier are an example), I tend to check out a copy of the tree, and work on it on and off. For example, I might have an idea for fixing some performance problem, but then have to wait a while for someone else to implement a feature or fix a bug till I can make progress.
- For smaller fixes, I sometimes still work from a clean Chandler checkout, just because my usual checkout has a bunch of uncommitted changes.
It’s not unheard of for the second case to morph into the first, e.g. when what I thought was
a simple fix turns out to have unexpected quincequonces.
So, inspired by the Chandler dashboard design, I decided to lay out the non-mirrored part of
my SVK repository like this:
//work/now
//work/later
//work/done
In
//work/now, I’ll have the local branches I’m actually working on at the moment.
On disk, I have a checkout of
//work/now, which is where I edit, test and commit
changes.
If I work on something that doesn’t pan out, I’ll check in my changes (to the local branch,
not the remote repository, of course), and then use
svk mv to stash it
away in
//work/later.
Once I’m ready to commit back into the Chandler trunk, I’ll typically do that and then
svk mv over into
//work/done (actually, into a release-specific
subfolder).
In GTD style, my weekly review (so far as code is concerned) starts off with:
bash$ svk ls //work/now //work/later
followed possibly by shuffling branches around, creating new ones, and finally
a
bash$ svk update ~/now # where //work/now is mirrored
Don’ts
svk pull in a mirrored branch
I’m still not entirely sure of why this happened (it might have something to do with
a Chandler merge I had done in the past), but what I did was:
bash$ # Check out the 0.7alpha4 chandler branch
bash$ svk co //mirror/chandler/branches/0.7alpha4/chandler chandler-0.7alpha4
... time elapses ...
bash$ # Try to get the branch’s changes from the remote repository via:
bash$ cd chandler-0.7alpha4
bash$ svk pull
At this point,
svk applied all the
mainline changes to Chandler,
and committed them back to the 0.7alpha4 branch, without asking for confirmation.
This seems like counter-intuitive behaviour, and led to the following mondo
commit:
12207,
which had to be backed out.
svk push
Without arguments, this command will send out all commits in the branch, including
merges from the mirror, one by one, without asking you for any commit message.
If you’re using the “commit and pull often” model, like me, you end up with a lovely
sequence of commits like the following:
12161,
12162,
12163,
12164,
12165,
12166,
12167,
12168,
12169,
12170.
This may not be what you wanted :).
--
GrantBaillie - 02 Nov 2006