Subsections

Best practices

Introduction

This chapter is intended to review various scenarios and describe in each case effective ways of using darcs. There is no one ``best practice'', and darcs is a sufficiently low-level tool that there are many high-level ways one can use it, which can be confusing to new users. The plan (and hope) is that various users will contribute here describing how they use darcs in different environments. However, this is not a wiki, and contributions will be edited and reviewed for consistency and wisdom.

Basics

This section will lay down the concepts around which darcs functions. The aim is to develop a way of thinking that corresponds well to how darcs is behaving -- even in complicated situations.

Darcs is change based. Changes are recorded in patches. Patches are copied to other branches to incorporate the changes there. Patches can be thrown away to make a branch go back in time. Patches are, as much as possible, independent; you can include some patches but exclude others in a branch. This can be used to find out exactly what patch introduced a bug.

Creating patches

In a single darcs repository you can think of two ``versions'' of the source tree. They are called the working and pristine trees. Working is your normal source tree, with or without darcs alongside. The only thing that makes it part of a darcs repository is the _darcs directory in its root. Pristine is the recorded state of the source tree. The pristine tree is constructed from groups of changes, called patches (some other version control use the term changeset instead of patch).footnoteIf you look inside _darcs you will find files or directories named `patches' and `inventories', which store all the patches ever recorded. If the repository holds a cached pristine tree, it is stored in a directory called pristine or current; otherwise, the fact that there is no prisine tree is marked by the presence of a file called pristine.none or current.none.

Changes

If working and pristine are the same, there are ``no changes'' in the repository. Changes can be introduced (or removed) by editing the files in working. They can also be caused by darcs commands, which can modify both working and pristine. It is important to understand for each darcs command how it modifies working, pristine or both of them.

whatsnew (as well as diff) can show the difference between working and pristine to you. It will be shown as a difference in working. In advanced cases it need not be working that has changed; it can just as well have been pristine, or both. The important thing is the difference and what darcs can do with it.

Keeping or discarding changes

If you have a difference in working, you do two things with it: record it to keep it, or revert it to lose the changes.5.1

If you have a difference between working and pristine--for example after editing some files in working--whatsnew will show some ``unrecorded changes''. To save these changes, use record. It will create a new patch in pristine with the same changes, so working and pristine are no longer different. To instead undo the changes in working, use revert. It will modify the files in working to be the same as in pristine (where the changes do not exist).

Unrecording changes

unrecord is a command meant to be run only in private repositories. It's intention is to allow developers the flexibility to undo patches that haven't been distributed yet.

However, darcs does not prevent you from unrecording a patch that has been copied to another repository. Be aware of this danger!

If you unrecord a patch, that patch will be deleted from pristine. This will cause working to be different from pristine, and whatsnew to report unrecorded changes. The difference will be the same as just before that patch was recorded. Think about it. record examines what's different with working and constructs a patch with the same changes in pristine so they are no longer different. unrecord deletes this patch; the changes in pristine disappear and the difference is back.

If the recorded changes included an error, the resulting flawed patch can be unrecorded. When the changes have been fixed, they can be recorded again as a new--hopefully flawless--patch.

If the whole change was wrong it can be discarded from working too, with revert. revert will update working to the state of pristine, in which the changes do no longer exist after the patch was deleted.

Keep in mind that the patches are your history, so deleting them with unrecord makes it impossible to track what changes you really made. Redoing the patches is how you ``cover the tracks''. On the other hand, it can be a very convenient way to manage and organize changes while you try them out in your private repository. When all is ready for shipping, the changes can be reorganized in what seems as useful and impressive patches. Use it with care.

All patches are global, so don't ever replace an already ``shipped'' patch in this way! If an erroneous patch is deleted and replaced with a better one, you have to replace it in all repositories that have a copy of it. This may not be feasible, unless it's all private repositories. If other developers have already made patches or tags in their repositories that depend on the old patch, things will get complicated.

Special patches and pending

Write me!

Using patches

Write me!


Distributed development with one primary developer

This is how darcs itself is developed. There are many contributors to darcs, but every contribution is reviewed and manually applied by myself. For this sort of a situation, 'darcs send' is ideal, since the barrier for contributions is very low, which helps encourage contributors.

One could simply set the _darcs/prefs/email value to the project mailing list, but I also use darcs send to send my changes to the main server, so instead the email address is set to ``Davids Darcs Repo <droundy@abridgegame.org>''. My .procmailrc file on the server has the following rule:

:0:
* ^TODavids Darcs Repo
|(umask 022; darcs apply --reply darcs-devel@abridgegame.org \
             --repodir /path/to/repo --verify /path/to/allowed_keys)
This causes darcs apply to be run on any emails sent to ``Davids Darcs Repo''. Apply actually applies them only if they are signed by an authorized key. Currently, the only authorized key is mine, but of course this could be extended easily enough.

The central darcs repository contains the following values in its _darcs/prefs/defaults:

apply test
apply verbose
apply happy-forwarding
The first line tells apply to always run the test suite. The test suite is in fact the main reason I use send rather than push, since it allows me to easily continue working (or put my computer to sleep) while the tests are being run on the main server. The second line is just there to improve the email response that I get when a patch has either been applied or failed the tests. The third line makes darcs not complain about unsigned patches, but just to forward them to darcs-devel.

On my development computer, I have in my .muttrc the following alias, which allows me to easily apply patches that I get via email directly to my darcs working directory:

macro pager A "<pipe-entry>(umask 022; darcs apply --no-test -v --repodir ~/darcs)"


Development by a small group of developers in one office

This section describes the development method used for the density functional theory code DFT++, which is available at http://dft.physics.cornell.edu/dft.

We have a number of workstations which all mount the same /home via NFS. We created a special ``dft'' user, with the central repository living in that user's home directory. The ssh public keys of authorized persons are added to the ``dft'' user's .ssh/allowed_keys, and we commit patches to this repository using darcs push. As in Section [*], we have the central repository set to run the test suite before the push goes through.

Note that no one ever runs as the dft user.

A subtlety that we ran into showed up in the running of the test suite. Since our test suite includes the running of MPI programs, it must be run in a directory that is mounted across our cluster. To achieve this, we set the $DARCS_TMPDIR environment variable to ~/tmp.

Note that even though there are only four active developers at the moment, the distributed nature of darcs still plays a large role. Each developer works on a feature until it is stable, a process that often takes quite a few patches, and only once it is stable pushes to the central repo.

David Roundy 2005-02-04