Contents
- Basic
- Initial import of existing project without version control
- darcs remove
- Undeleting an accidentally removed file
- Tips easily excluding the _darcs directory when searching
- how to get a bunch of tar balls (different revisions of same software) into a darcs repo
- How to get darcs to not be so trigger-happy with its prompts
- Advanced
- GnuPG and darcs on SuSE 9.1
- About master and working repositories
- Making the most of decentralisation
- darcs and permissions (configure)
- darcs and autoconf/automake
- how to set up a shared writable repository without granting full ssh access or using an email gateway
- grouping patches with tags in their names
- How to keep track of who committed which patch
- Scripts
- Misc.
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 to 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'"
darcs remove
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.
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:
Use zsh if you are using other shells.
setopt extendedglob
grep -R ^_darcs -- The more general case would be <glob_to_include>~<glob_to_exclude>
With the bash shell
shopt -s extglob to turn on extended globbing syntax.
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:
darcs get --partial http://darcs.complete.org/tla-load-dirs
(Yes, that is the correct URL; the tool started life as an Arch tool, and this repo provides both tla_load_dirs and darcs_load_dirs)
The manual method:
you got different versions of the software in tarballs, now to get them into a darcs repo, follow these steps:
- untar first version of tarball into vc/sw
- darcs init, add and record
- mv _darcs into a different dir (/tmp)
- rm -rf vc/sw/*
- mv _darcs back to vc/sw
- untar second version of tarball into vc/sw
- darcs record
- 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
A question came up in the IRC channel early one day on how to configure or trick darcs into not using "hot" prompts -- that is, prompts which are line-fed, not character fed. In still other words, prompts where the user has to hit ENTER to submit his response.
For most of the day, no answer came, and after searching the wiki, the author declared that it wasn't really possible. However, the answer came through later in the evening: simply 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
When working on a project, even a one-person project, you should not work in the repository itself, but in a copy thereof. This will allow you to quickly switch to older versions (by using unpull and pull) whenever you need to. -- JuliuszChroboczek
- Does anyone care to elaborate on the first point (don't work in the repository). The manual claims that "every copy of your source is a full repository".
I'm working on a project hello-world. With CVS (or Arch, for that matter), I'd set up a repository /var/cvs/ with a module hello-world/, and check out a working dir ~/hello-world/. With that setup, I can easily switch my working dir to an earlier version (or a different branch) whenever I need to.
With darcs, I might be tempted to just set up a single repository ~/hello-world/. If I do that, there is no way I can go backwards in time without actually losing my changes.
Instead, I set up a "master" repository /var/repos/hello-world/, and use a clone ~/hello-world/ as my working dir. Where I'd use cvs commit, I do darcs record followed with darcs push. In this manner, I get the same level of comfort as with cvs: I can go backwards in time (darcs unpull), go forwards in time (darcs pull), or even rm -r the working dir and get a new copy if I've made a mess of things.
You could also do a darcs get ~/hello-world --patch "Some Name" to check out the "old" version. But a backup is always good.
The one thing missing is easily switching between branches: there's no easy way to unpull exactly the changes that are in /var/repos/hello-world/ but not in /var/repos/hello-world-stable/, a comment which more properly belongs in the WishList.
Somebody noted:
- If you use the "get method" above to get to an older version, you can just cd between the different branches, and also do a recursive diff to see the total change between two of them.
Of course, this creates a new copy rather than changing the current copy in place, which, while sometimes useful, is a different thing altogether. I've usually got one Emacs with 135 files open, a Lisp listener (interactive development environment), and a buch of xterms all set up in the working directory. Switching to the new directory would require restarting all of the above in the new directory.
Please see http://lists.osuosl.org/pipermail/darcs-users/2004-July/002351.html for more details. -- JuliuszChroboczek
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 <em>convenient</em>? 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.
darcs and autoconf/automake
If you use autoconf/automake be careful! The default autogen.sh script generated by autoconf/automake can mess up your darcs repository. By default this script looks for all the configure.in files it can find, starting in the current directory, and runs autoconf on them. This means that it will find the _darcs/current/configure.in and will autoconf it, thus corrupting your repository...
The fix is simple, look for a line in autogen.sh looking like:
for coin in `find $srcdir -path $srcdir/CVS -prune -o -name configure.in -print`
and replace it with:
for coin in `find $srcdir -path $srcdir/_darcs -prune -o -name configure.in -print`
When darcs gets wider acceptance I hope this will be included in the default automake/autoconf distrib. -- StephanePopinet
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 AppleScript 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"
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""" %<"
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 the official method
- Download the darcs's Windows binary and the customized sftp.zip
- Put the darcs.exe and the sftp.exe in $HOME/bin
Download and install Putty, pscp, sftp, etc. (Don't you already have this?
) 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"
Re-start your Cygwin shell or source ~/.bashrc
Now darcs should work fine.
--- 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
2. 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.
3. Rebuild
postmap /etc/postfix/canonical
Execute the command in order to rebuild the indexed file after changing the text file.
4. 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).
