HintsAndTips

Basic

Initial import of existing project without version control

If you have a very large project, you may not want to import the entire project in one record, as that will create a very large patch file. Darcs' performance has improved greatly, so for most projects the initial commit will not be a problem. If your codebase is larger than 50MB or so, you may want to start your repository out by adding a few directories at a time. Large repositories are quite managable as long as individual patches are small.

Before adding a huge directory to darcs, use "darcs add --dry-run -r .". That way, if you see a bunch of files that you want to be 'boring', you can update _darcs/prefs/boring before you actually add the files to darcs management. This is especially useful because there is currently no "darcs remove -r" to undo the action, and trying 'darcs revert -a' in this case may delete the files! If you do botch an import by adding way too many files, the easiest thing to do is to remove the _darcs directory try again (but you may want to first backup _darcs/prefs/boring if you modified it).

Here is a handy bash alias to quickly import an existing project. This can even be used to produce quick patches and easily produce unified diffs.

alias darcsify="darcs init && darcs add \$(darcs whatsnew -ls | awk '/^a\ / {print \$2}') && darcs record -a -m'Initial import'"

Undeleting an accidentally removed file

When you need to undelete a file you accidentally deleted you can call

darcs revert -a [file or dir]

The -a is to answer yes to all the patches since obviously a half restored file wouldn't do you much good.

Tips easily excluding the _darcs directory when searching

With the zsh shell:

  1. Use zsh if you are using other shells.
  2. setopt extendedglob
    
  3. grep -R ^_darcs
    

    -- The more general case would be <glob_to_include>~<glob_to_exclude> With the bash shell

  4. shopt -s extglob
    
    to turn on extended globbing syntax.
  5. grep -R string !(_darcs)
    

    to cause the shell to skip the glob that matches _darcs. You might also wish to use an alias or script to make this even easier. Here are a couple options:

An alias for your .bash_profile

alias dgrep="find . -path '*/_darcs' -prune -o -print0 | xargs -0 egrep"

then you can just use dgrep string.

A script for your ~/bin directory, which includes a customizeable "prune" list, to ignore other things as well:

an rgrep script
#!/usr/bin/perl -w
# originally by Michael Schwern
# Like grep -r except...
# * you can leave off the directory and it will use . instead of waiting like
# a dumbshit for STDIN
# * It handles paths with spaces and quotes.
# * it will not traverse into these directories or files.
my @Prunes = (qw(.svn CVS blib *~ *.bak _darcs), '#*');
my @Args = @ARGV;
my $Dir;
if( grep(!/^-/, @Args) <= 1 ) {
    $Dir = '.';
}
else {
    $Dir = pop @Args;
}
@Args = map { "'$_'" }
        map { s/'/'"'"'/g; $_ } @Args;
# Escape spaces and quotes
$Dir =~ s{([ '"])}{\\$1}g;
my $prunes = join ' -o ', map { "-name '$_' -prune" } @Prunes;
exec "find $Dir $prunes -o -type f -print0 | ".
     "xargs -0 grep @Args";

how to get a bunch of tar balls (different revisions of same software) into a darcs repo

The best way is to use darcs_load_dirs. This program is designed specifically for this purpose. It will not only handle changes, adds, and removes, but also has a way to prompt the operator to help with renames.

Get it with:

The manual method:

you got different versions of the software in tarballs, now to get them into a darcs repo, follow these steps:

  1. untar first version of tarball into vc/sw
  2. darcs init, add and record
  3. mv _darcs into a different dir (/tmp)
  4. rm -rf vc/sw/*
  5. mv _darcs back to vc/sw
  6. untar second version of tarball into vc/sw
  7. darcs record
  8. go to step 3 another version of this idea suggested was moving _darcs to another dir and a ln -s everytime instead of a rm and mv (steps 4 & 5)

How to get darcs to not be so trigger-happy with its prompts

To make darcs wait for the user to hit ENTER to submit their response, wrap your normal darcs command, options and all, inside a pipeline surrounded by cat. For example, to record changes interactively, but without the hot prompts:

cat | darcs record | cat

Now the user will be required to type ENTER to submit his selections for all prompts, including the yes/no prompts.

Advanced

GnuPG and darcs on SuSE 9.1

If running the command:

darcs send --sign

on SuSE Linux 9.1 Professional gives you the following message:

darcs failed: Error running external program 'gpg'

and you have a passphrase protected key, check to see if:

use-agent

is enabled in your ~/.gnupg/gpg.conf. If it is, either install GnuPG-Agent or disable it in your config file with

no-use-agent

I have it disabled on my setup since there seems to be no available package of GnuPG-Agent available for SuSE 9.1 --NimrodAbing

About master and working repositories

Even when working alone on a project, you should not work in the repository itself, but in a copy thereof. This will allow you to quickly switch to older versions whenever you need to.

For instance, it is a good practice to have a "threshold" repository between the repository in which you actually work and the "external" repository that the world can see (if such a repository exists).

work in progress -----> threshold -----> world visible

Thus, while working in the "work in progress" repository, you can go backwards in time (darcs unpull), forwards in time (darcs pull), or even rm -r the working dir and get a new copy if you've messed up everything.

Moreover, you can have different "work in progress" branches in parallel, and just cd between them, and also do a recursive diff to see the total change between two of them.

Making the most of decentralisation

Everybody pulls, or how to deal with not having a central push depot.

Say you are all working on an article and you don't want to go through the trouble of setting up a central push depot, dealing with umasks and all of that boring stuff. What you really want is a lightweight solution where everybody pulls from each other. This is possible in darcs, but the question here is how do we make it convenient? Here are some tricks I use to make my life easier:

  • Create a central pull depot. Arbitrarily designate one of you to be the pull master. The pull master's job is to pull from everybody else and push changes into to pull depot (unless the pull depot is just the pull master's working directory). Everybody else pulls from the pull master (this is useful when not everybody is comfortable with darcs yet)

  • Make use of --no-set-default flag. Darcs has a handy feature where it remembers the last repository you pull/push from, so that if you do darcs pull /tmp/foo once, the next time you do darcs pull, it remembers that it should do it from /tmp/foo. The only problem is that this is not so handy if you are pulling from multiple locations:

    darcs push /some/really/incredibly/long/path/pull_depot
    darcs pull /home/alice/repo
    darcs pull /home/bob/repo
    darcs push -- WRONG! this will will push into /home/bob/repo
    

    In order to make this work better -- in order not to forget your pull depot path is to do it like this:

    darcs push /some/really/incredibly/long/path/pull_depot
    darcs pull --no-set-default /home/alice/repo
    darcs pull --no-set-default /home/bob/repo
    darcs push
    

    By using the --no-set-default flag, you tell darcs not to remember the path you just provided.

  • If pulling from everybody else also involves some very long, hard-to-remember path, the pull master could also have a separate repository for each person she is pulling from:

    mkdir my_project
    cd my_project
    darcs get /some/really/incredibly/long/path/pull_depot pull_depot
    darcs get /some/really/long/path/alice/repo alice
    darcs get /another/really/long/path/bob/repo bob
    ...
    cd alice
    darcs pull
    cd ..
    cd bob
    darcs pull
    cd ..
    cd pull_depot
    darcs pull --no-set-default ../alice
    darcs pull --no-set-default ../bob
    darcs push
    

    The reason this works for me is that my partners' really long paths are harder to remember and less convenient to type than the relative path of my pull depot. So I ask darcs to remember the hard stuff, and let it forget the easy stuff. Keep in mind that none of these are strictly neccesary. They are just tricks I use to make things more convenient for me; and they may not be applicable for your needs.

darcs and permissions (configure)

Ideally, when somebody darcs get's your code, they should just be able to do ./configure; make; make install, but one minor annoyance is that darcs doesn't keep track of file permissions. Here is what I do to get my Makefile to chmod u+x configure for the user.

My configure script produces a preferences file called config.mk. If this file exists, I include it into my Makefile:

config_file:=config/config.mk
ifneq '$(wildcard $(config_file))' ''
include $(config_file)
endif

If the file does not exist, then the following target is run. It performs the chmod for me. Note that the target must be called from all relevant targets, for instance, install

$(config_file):
        chmod u+x configure
        @echo >&2 "Please run ./configure to setup the build system."
        @exit 1
install: $(config_file)

Notes:

  • this is half copied from the darcs Makefile
  • might be GNU Makefile specific
  • autoconf's configure seems to produce a file called config.status. You could use that instead.

how to set up a shared writable repository without granting full ssh access or using an email gateway

Set up your repo and a group which can write to it. Something like the following, also arrange for their umask to be 002, I don't know how:

addgroup projectgroup
chgrp -R projectgroup /repos/project
chmod -R g+w /repos/project
find /repos/project -type d -exec chmod g+s {} \;

(Signed email users, you might need to restore your allowed_keys permissions after this.) Next install scponly:

Debian : apt-get install scponly
Arch Linux: pacman -S scponly
Gentoo : emerge scponly

And for each committer:

adduser --home /repos/project --no-create-home --shell /usr/bin/scponly --ingroup projectgroup username

This user will be able to push (and scp/sftp/rsync) as allowed by unix file permissions, with /repos/project as their login directory, but won't be able to execute anything. You could also use scpjailer to restrict them to the repo dir, which would be even better; I haven't tried this. Use your own judgement on how far to trust this.. --SimonMichael

grouping patches with tags in their names

darcs can in many contexts work on whole groups of patches based on their names, by means of regular expressions. You can make use of this by putting tags in the patchnames.

For example reset pointer to zero after it is freed <bugfix> <file hash>. Patches concerning the file hash code can than be listed with darcs changes -p '<file hash>' and all bugfixes can be pushed with darcs push -p '<bugfix>'. All bugfixes for the file hash can be pulled with darcs pull -p '<bugfix>.*<file hash>'. Note that the tags must always be in alphabetical order (or some other well defined order) for multi-tag regexps to work.

See SpontaneousBranches.

How to keep track of who committed which patch

When having a central branch where a select group of people can commit to (using shell access), it is often desirable to know who committed a certain patch (e.g. when the author of the patch didn't have commit access).

A first solution is by using 'darcs send' to commit to the central branch. The procmail script can then log to a file the e-mail address of the sender of the patch.

If you still prefer darcs push, you can create a wrapper around darcs on the server where the repository resides. You'll have to rename your darcs binary to darcs.bin, and create an executable script called darcs looking like this:

DARCS=/usr/bin/darcs
LOG=~/darcs.log
PARAMS=$*
NPARAMS=${PARAMS/#apply/apply -v}
if test "$PARAMS" != "$NPARAMS"; then
        ( echo "********** Apply by $USER ***********" ; echo ; \
        exec $DARCS $NPARAMS | grep -v -E "^(We |Will|diff|Applying|Finished)" ; \
        echo ) >> $LOG
else
        exec $DARCS $PARAMS
fi

This will intercept darcs apply calls, change them into darcs apply -v, and log the output, together with the executing user to the given log file. -- RemkoTroncon

Scripts

Script to improve 'darcs annotate' output

darcs-reannotate. A small Python program that converts the output of "darcs annotate" into a more readable format.

Script to apply darcs patches from Mac OS X's Mail.app

I've writen a little Apple{{{}}}Script that lets you apply darcs patches created via darcs send without leaving Mail.app. Find it here. ---JoseAntonioOrtegaRuiz (link updated by TomCounsell 15 Feb 2007)

darcs send with Mac OS X's Mail.app

You can configure darcs to use Mail.app to send patches.

Save this AppleScript as ~/bin/send-mail.applescript:

(* 
Running:
osascript send-mail.applescript <to> <cc> <subject> <body> <attachment> 
*)
on run argv

    tell application "Mail"

        set displayForManualSend to false

        set toVar to item 1 of argv
        set ccVar to item 2 of argv
        set subjectVar to item 3 of argv
        set bodyVar to item 4 of argv
        set attachVar to item 5 of argv

        set composeMessage to make new outgoing message
        tell composeMessage
            make new to recipient with properties {address:toVar}
            if length of ccVar > 0 then
                make new cc recipient with properties {address:ccVar}
            end if
            set the subject to subjectVar
            set the content to bodyVar

            tell content
                make new attachment with properties {file name:attachVar} at after last paragraph
            end tell

            set visible to displayForManualSend
        end tell

        if not displayForManualSend then
            send composeMessage
        end if

    end tell

end run

And add this to to ~/.darcs/defaults:

send sendmail-command osascript ~/bin/send-mail.applescript "%t" "%c" "%s" "%b" "%a"

-- BjornBringert

darcs send with GMail SMTP

Python script - simple sendmail replacement that uses SMTP protocol for delivery. Tested with GMail, but should work for other services as well. Edit script to configure your smtp server, login/pass. Then execute darcs (windows variant):

darcs send -v --sendmail-command="c:\path\to\python sendmail.py """%t""" %<"

See also http://wiki.darcs.net/Msmtp

Script to provide sums of the additions and deletions in darcs whatsnew -s

This AWK script provides a sum of the additions and deletions in the output of darcs whatsnew -s. The output is like that on the LKML (presumably from git):

darcs whatsnew -s 2> /dev/null | awk 'BEGIN { pr = 0; a = 0; d = 0; } /^M/ { f += 1; d -= $3; a += $4; pr = 1; } END { if (pr == 1) { print f, "files changed", a, "insertions(+)", d, "deletions(-)"; } else { print "Are you sure this is a darcs repository?"; } }'

If you would like to change or extend the script for your own needs but you are not familiar with AWK, Greg Goebel has written a great tutorial.

Misc.

  • Before pulling a patch, make sure all local changes are recorded. That way if you get a conflict, you are guaranteed to be able to go back without having to untangle the conflict by hand. After you pull you can always unrecord again if you didn't really want to make a patch at that point. --GaneshSittampalam
  • The _darcs directory can be moved out of tree and replaced with a symlink pointing to it. This is mainly useful for situations such as preventing accidental deletion of a repository of /etc across operating system reinstalls or importing a new version of a tree from a project that doesn't itself use darcs. --JonathanConway

Another Cygwin configuration

Here is how I got Cygwin to run

-- a little different than http://wiki.darcs.net/WindowsConfiguration

  1. Download the darcs's Windows binary and the customized sftp.zip
  2. Put the darcs.exe and the sftp.exe in $HOME/bin
  3. Download and install Putty, pscp, sftp, etc. (Don't you already have this? :) )
  4. Put this in your ~/.bashrc:

    export PATH=$PATH:$HOME/bin
    # the -i is in case you are using a private key
    export DARCS_SCP="`cygpath -d /cygdrive/c/utils/pscp.exe` -i c:\utils\keys\private.key"
    export DARCS_SFTP="`cygpath -d $HOME/bin/sftp.exe` -i c:\utils\keys\private.key"
    
  5. Re-start your Cygwin shell or source ~/.bashrc Now darcs should work fine.

  6. --- MikeHostetler

Configuring MacOS X to darcs send

The postfix mail server is bundled with MacOS X. On MacOS X 10.4 it is launched on demand, so using darcs send will just work (via the sendmail compatibility interface to postfix). However there are high chances that your email will be rejected by the recipient's mail server because by default, if your user name is username and your computer name is compname the sender address will be <username@compname.local> and compname.local is not a valid sender domain. To make your emails acceptable you have to rewrite the sender address. To do that :

  1. Add the following line to /etc/postfix/main.cf
canonical_maps = hash:/etc/postfix/canonical
  1. Add the following line to /etc/postfix/canonical
username bla@example.com

where username is your username and bla@example.com is your valid email address.

  1. Rebuild
postmap /etc/postfix/canonical

Execute the command in order to rebuild the indexed file after changing the text file.

  1. Run (On 10.4 you don't need to do this, postfix is launched on demand).
sudo postfix start

to start Postfix.

sudo postfix stop

to stop Postfix.

Note that bounced messages will also be reported to bla@example.com. Tested with MacOS 10.4.3, postfix 2.1.5, darcs 1.0.4.

-- DanielBünzli -- AlbertoSantini

Use command line auto completion

You can enable very useful auto completion functionality by following the instructions in ShellCompletion.

The functionality differs depending on your shell. However I have found the bash support to be excellent. It supports autocompletion of darcs commands (get, push, etc.), options and repositories (by recording the repositories you have previously used).

-- MartynLoughran

Tips for older versions of darcs

darcs remove (before version 2.4)

First of all, don't forget that if you do rm -rf directory_in_question darcs will automatically detect the remove.

Still, if you want to recursively darcs remove a directory without actually getting rid of it in your darcs directory

darcs show files | grep directory_in_question | xargs darcs remove

If you accidentally 'darcs remove' a file you can do a 'darcs add' to the same file and it will essentially undo the erroneous remove.

In darcs 2.4 and later, you can simply do darcs remove --recursive.