Revision Control Not-So-Quickie
Introduction to darcs
The other day I found myself needing to put some relatively minor code
under revision control. Traditionally I've used rcs,
as it's very simple, not hard to understand, and was available damn near
everywhere (on Un*x machines, at least).
This time though, my laptop didn't have it installed, so I looked
around for alternatives. cvs
and its successor Subversion (svn) both
require a central repository to be set up, which was neither simple enough to
do on the spur of the moment, nor a convenient architecture for my
circumstances, working as I do on a laptop, public server, and (frequently
powered down) home machine.
What I found instead was darcs, which has a
number of things going for it. Firstly, it has a good manual and plenty of support. Secondly, it has a well
thought-out formal
semantics underneath it, which (writing as a computer scientist) is
always a good thing to see. This is bolstered by the fact that it's written
in Haskell,
by a physicist who appears to know what he's on about. Finally,
it's a decentralised architecture, meaning the options available at one
installation are much the same as those available anywhere else, whether they
happen to be on the same machine or not.
Anyway, enough of that: here's what it looks like to use.
- Get things started.
$ cd ~/SRC $ vi foo.lisp # Create the masterpiece $ darcs initialize $ ls _darcs foo.lisp # All darcs' stuff is in _darcs
- Add something to the repository.
$ darcs add foo.lisp $ darcs whatsnew { addfile ./foo.lisp hunk ./foo.lisp 1 +(format t "Hello, world!") } - Check things in.
$ darcs record Darcs needs to know what name to use as the author so that [...] <snip> What is your e-mail address? foo@bar.baz addfile ./foo.lisp Shall I record this change? (1/?) [ynWsfqadjkc], or ? for help: y hunk ./foo.lisp 1 +(format t "Hello, world!") Shall I record this change? (2/?) [ynWsfqadjkc], or ? for help: y What is the patch name? Initial revision Do you want to add a long comment? [yn]n Finished recording patch 'Initial revision' $ darcs whatsnew No changes!
- Make more changes
$ vi foo.lisp $ darcs whatsnew { hunk ./foo.lisp 1 +;; Print "Hello, world!" message } $ darcs record hunk ./foo.lisp 1 +;; Print "Hello, world!" message Shall I record this change? (1/?) [ynWsfqadjkc], or ? for help: y What is the patch name? Add "Hello, world!" comment Do you want to add a long comment? [yn]n Finished recording patch 'Add "Hello, world!" comment' - See what we've got.
$ darcs changes Mon Nov 6 22:15:12 GMT 2006 foo@bar.baz * Add "Hello, world!" comment Mon Nov 6 21:45:46 GMT 2006 foo@bar.baz * Initial revision
- Let's make a new copy to work on different branch — on another
machine, if we want to.
$ cd ~/BRANCHES $ ls $ darcs get ~/SRC Copying patch 2 of 2... done! Finished getting. $ ls SRC $ darcs get foo@machine.com:/home/foo/SRC --repo-name=SRC-SSH Enter passphrase for key '/home/foo/.ssh/id_dsa': Applying patch 2 of 2... done! Finished getting. $ ls SRC SRC-SSH $ cd SRC-SSH $ darcs changes Mon Nov 6 22:15:12 GMT 2006 foo@bar.baz * Add "Hello, world!" comment Mon Nov 6 21:45:46 GMT 2006 foo@bar.baz * Initial revision $ vi foo.lisp $ darcs whatsnew { hunk ./foo.lisp 3 +(format t "The End.") } $ darcs record Darcs needs to know what name [...] <snip> What is your e-mail address? foo-ssh@bar.baz hunk ./foo.lisp 3 +(format t "The End.") Shall I record this change? (1/?) [ynWsfqadjkc], or ? for help: y What is the patch name? Add ending. Do you want to add a long comment? [yn]n Finished recording patch 'Add ending.' - Now bring the changes back into the original repository. This could just
as easily be done over HTTP if the directory were visible on a web server.
$ cd ~/SRC $ darcs pull ~/BRANCHES/SRC-SSH Mon Nov 6 22:26:32 GMT 2006 foo-ssh@bar.baz * Add ending. Shall I pull this patch? (1/1) [ynWvpxqadjk], or ? for help: y Finished pulling and applying. $ cat foo.lisp ;; Print "Hello, world!" message (format t "Hello, world!") (format t "The End.")
- We're bored of this, so let's e-mail the changes off, create a tarball
of the current state, and get rid of all the
darcsstuff. Here the web-site has already got the first two patches, sodarcsonly sends the third.$ darcs send http://foo.bar.baz/projects/demo Mon Nov 6 22:26:32 GMT 2006 foo-ssh@bar.baz * Add ending. Shall I send this patch? (1/1) [ynWvpxqadjk], or ? for help: y What is the target email address? foo-mail@bar.baz Successfully sent patch bundle to: foo-mail@bar.baz $ darcs dist Created dist as SRC.tar.gz $ ls _darcs foo.lisp SRC.tar.gz $ tar tzf SRC.tar.gz SRC/ SRC/foo.lisp $ rm -rf _darcs $ ls foo.lisp SRC.tar.gz $ darcs changes darcs failed: Not a repository
The e-mail contains an attachment, which can be saved and applied using
darcs apply. You can also sign the e-mail with your GPG key
when you send, and have the other end automatically check the signature
against its keyring. Oh, and there's a helpful setting
that lets you specify a command which runs any tests you might have, for
example HTML validators or unit tests; this lets you stop patches which would
break things from getting committed to the repository. And of course, you
can do lots of other stuff, like back changes out, tag versions with numbers
and labels, etc.
It might not be so industrial-strength as a full Subversion installation, but it's just right for setting up in a couple of seconds where its needed and getting things done. And if you later find you need the big guns, don't worry — there's tool support for converting to (and from) most major alternatives.