All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
7 mr - a Multiple Repository management tool
11 B<mr> [options] checkout
13 B<mr> [options] update
15 B<mr> [options] status
17 B<mr> [options] commit [-m "message"]
23 B<mr> [options] register [repository]
25 B<mr> [options] config section ["parameter=[value]" ...]
27 B<mr> [options] action [params ...]
31 B<mr> is a Multiple Repository management tool. It can checkout, update, or
32 perform other actions on a set of repositories as if they were one combined
33 respository. It supports any combination of subversion, git, cvs, mecurial,
34 bzr and darcs repositories, and support for other revision control systems can
37 B<mr> cds into and operates on all registered repositories at or below your
38 working directory. Or, if you are in a subdirectory of a repository that
39 contains no other registered repositories, it will stay in that directory,
40 and work on only that repository,
42 These predefined commands should be fairly familiar to users of any revision
47 =item checkout (or co)
49 Checks out any repositories that are not already checked out.
53 Updates each repository from its configured remote repository.
55 If a repository isn't checked out yet, it will first check it out.
59 Displays a status report for each repository, showing what
60 uncommitted changes are present in the repository.
64 Commits changes to each repository. (By default, changes are pushed to the
65 remote repository too, when using distributed systems like git.)
67 The optional -m parameter allows specifying a commit message.
71 Show a diff of uncommitted changes.
79 These commands are also available:
85 List the repositories that mr will act on.
89 Register an existing repository in a mrconfig file. By default, the
90 repository in the current directory is registered, or you can specify a
91 directory to register.
93 The mrconfig file that is modified is chosen by either the -c option, or by
94 looking for the closest known one at or below the current directory.
98 Adds, modifies, removes, or prints a value from a mrconfig file. The next
99 parameter is the name of the section the value is in. To add or modify
100 values, use one or more instances of "parameter=value". Use "parameter=" to
101 remove a parameter. Use just "parameter" to get the value of a parameter.
103 For example, to add (or edit) a repository in src/foo:
105 mr config src/foo checkout="svn co svn://example.com/foo/trunk foo"
107 To show the command that mr uses to update the repository in src/foo:
109 mr config src/foo update
111 To see the built-in library of shell functions contained in mr:
113 mr config DEFAULT lib
115 The ~/.mrconfig file is used by default. To use a different config file,
124 Actions can be abbreviated to any unambiguous subsctring, so
125 "mr st" is equivilant to "mr status", and "mr up" is equivilant to "mr
128 Additional parameters can be passed to most commands, and are passed on
129 unchanged to the underlying revision control system. This is mostly useful
130 if the repositories mr will act on all use the same revision control
139 Specifies the topmost directory that B<mr> should work in. The default is
140 the current working directory.
144 Use the specified mrconfig file. The default is B<~/.mrconfig>
152 Expand the statistics line displayed at the end to include information
153 about exactly which repositories failed and were skipped, if any.
157 Just operate on the repository for the current directory, do not
158 recurse into deeper repositories.
162 Run the specified number of jobs in parallel. This can greatly speed up
163 operations such as updates. It is not recommended for interactive
170 B<mr> is configured by .mrconfig files. It starts by reading the .mrconfig
171 file in your home directory, and this can in turn chain load .mrconfig files
174 Here is an example .mrconfig file:
177 checkout = svn co svn://svn.example.com/src/trunk src
181 checkout = git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git &&
183 git checkout -b mybranch origin/master
185 The .mrconfig file uses a variant of the INI file format. Lines starting with
186 "#" are comments. Values can be continued to the following line by
187 indenting the line with whitespace.
189 The "DEFAULT" section allows setting default values for the sections that
192 The "ALIAS" section allows adding aliases for actions. Each parameter
193 is an alias, and its value is the action to use.
195 All other sections add repositories. The section header specifies the
196 directory where the repository is located. This is relative to the directory
197 that contains the mrconfig file, but you can also choose to use absolute
200 Within a section, each parameter defines a shell command to run to handle a
201 given action. mr contains default handlers for "update", "status",
202 "commit", and other standard actions. Normally you only need to specify what
203 to do for "checkout".
205 Note that these shell commands are run in a "set -e" shell
206 environment, where any additional parameters you pass are available in
207 "$@". The "checkout" command is run in the parent of the repository
208 directory, since the repository isn't checked out yet. All other commands
209 are run inside the repository, though not necessarily at the top of it.
211 The "MR_REPO" environment variable is set to the path to the top of the
212 repository. (For the "register" action, "MR_REPO" is instead set to the
213 basename of the directory that should be created when checking the
216 The "MR_CONFIG" environment variable is set to the .mrconfig file
217 that defines the repo being acted on, or, if the repo is not yet in a config
218 file, the .mrconfig file that should be modified to register the repo.
220 A few parameters have special meanings:
226 If the "skip" parameter is set and its command returns true, then B<mr>
227 will skip acting on that repository. The command is passed the action
230 Here are two examples. The first skips the repo unless
231 mr is run by joey. The second uses the hours_since function
232 (included in mr's built-in library) to skip updating the repo unless it's
233 been at least 12 hours since the last update.
235 skip = test $(whoami) != joey
236 skip = [ "$1" = update ] && ! hours_since "$1" 12
240 The "order" parameter can be used to override the default ordering of
241 repositories. The default order value is 10. Use smaller values to make
242 repositories be processed earlier, and larger values to make repositories
245 Note that if a repository is located in a subdirectory of another
246 repository, ordering it to be processed earlier is not recommended.
250 If the "chain" parameter is set and its command returns true, then B<mr>
251 will try to load a .mrconfig file from the root of the repository. (You
252 should avoid chaining from repositories with untrusted committers.)
256 If the "include" parameter is set, its command is ran, and should output
257 additional mrconfig file content. The content is included as if it were
258 part of the including file.
260 Unlike all other parameters, this parameter does not need to be placed
265 The "lib" parameter can specify some shell code that will be run before each
266 command, this can be a useful way to define shell functions for other commands
271 When looking for a command to run for a given action, mr first looks for
272 a parameter with the same name as the action. If that is not found, it
273 looks for a parameter named "rcs_action" (substituting in the name of the
274 revision control system and the action). The name of the revision control
275 system is itself determined by running each defined "rcs_test" action,
278 Internally, mr has settings for "git_update", "svn_update", etc. To change
279 the action that is performed for a given revision control system, you can
280 override these rcs specific actions. To add a new revision control system,
281 you can just add rcs specific actions for it.
285 Copyright 2007 Joey Hess <joey@kitenet.net>
287 Licensed under the GNU GPL version 2 or higher.
289 http://kitenet.net/~joey/code/mr/
298 use Cwd qw(getcwd abs_path);
308 print STDERR "mr: interrupted\n";
312 $ENV{MR_CONFIG}="$ENV{HOME}/.mrconfig";
313 my $config_overridden=0;
322 my $directory=getcwd();
324 Getopt::Long::Configure("no_permute");
325 my $result=GetOptions(
326 "d|directory=s" => sub { $directory=abs_path($_[1]) },
327 "c|config=s" => sub { $ENV{MR_CONFIG}=$_[1]; $config_overridden=1 },
328 "v|verbose" => \$verbose,
329 "s|stats" => \$stats,
330 "n|no-recurse" => \$no_recurse,
331 "j|jobs=i" => \$jobs,
333 if (! $result || @ARGV < 1) {
334 die("Usage: mr [-d directory] action [params ...]\n".
335 "(Use mr help for man page.)\n");
338 if (! defined $directory) {
339 die("mr: failed to determine working directory\n");
342 # Make sure MR_CONFIG is an absolute path, but don't use abs_path since
343 # the config file might be a symlink to elsewhere, and the directory it's
345 if ($ENV{MR_CONFIG} !~ /^\//) {
346 $ENV{MR_CONFIG}=getcwd()."/".$ENV{MR_CONFIG};
348 # Try to set MR_PATH to the path to the program.
350 use FindBin qw($Bin $Script);
351 $ENV{MR_PATH}=$Bin."/".$Script;
355 loadconfig($ENV{MR_CONFIG});
357 #print Dumper(\%config);
359 # alias expansion and command stemming
360 my $action=shift @ARGV;
361 if (exists $alias{$action}) {
362 $action=$alias{$action};
364 if (! exists $knownactions{$action}) {
365 my @matches = grep { /^\Q$action\E/ }
366 keys %knownactions, keys %alias;
370 elsif (@matches == 0) {
371 die "mr: unknown action \"$action\" (known actions: ".
372 join(", ", sort keys %knownactions).")\n";
375 die "mr: ambiguous action \"$action\" (matches: ".
376 join(", ", @matches).")\n";
380 # commands that do not operate on all repos
381 if ($action eq 'help') {
382 exec($config{''}{DEFAULT}{$action}) || die "exec: $!";
384 elsif ($action eq 'config') {
386 die "mr config: not enough parameters\n";
389 if ($section=~/^\//) {
390 # try to convert to a path relative to the config file
391 my ($dir)=$ENV{MR_CONFIG}=~/^(.*\/)[^\/]+$/;
393 $dir.="/" unless $dir=~/\/$/;
394 if ($section=~/^\Q$dir\E(.*)/) {
400 if (/^([^=]+)=(.*)$/) {
401 $changefields{$1}=$2;
405 foreach my $topdir (sort keys %config) {
406 if (exists $config{$topdir}{$section} &&
407 exists $config{$topdir}{$section}{$_}) {
408 print $config{$topdir}{$section}{$_}."\n";
410 last if $section eq 'DEFAULT';
414 die "mr $action: $section $_ not set\n";
418 modifyconfig($ENV{MR_CONFIG}, $section, %changefields) if %changefields;
421 elsif ($action eq 'register') {
422 if (! $config_overridden) {
423 # Find the closest known mrconfig file to the current
425 $directory.="/" unless $directory=~/\/$/;
426 foreach my $topdir (reverse sort keys %config) {
427 next unless length $topdir;
428 if ($directory=~/^\Q$topdir\E/) {
429 $ENV{MR_CONFIG}=$configfiles{$topdir};
436 my $subdir=shift @ARGV;
437 if (! chdir($subdir)) {
438 print STDERR "mr $action: failed to chdir to $subdir: $!\n";
442 $ENV{MR_REPO}=getcwd();
443 my $command=findcommand("register", $ENV{MR_REPO}, $directory, 'DEFAULT');
444 if (! defined $command) {
445 die "mr $action: unknown repository type\n";
448 $ENV{MR_REPO}=~s/.*\/(.*)/$1/;
449 $command="set -e; ".$config{$directory}{DEFAULT}{lib}."\n".
450 "my_action(){ $command\n }; my_action ".
451 join(" ", map { s/\//\/\//g; s/"/\"/g; '"'.$_.'"' } @ARGV);
452 print "mr $action: running >>$command<<\n" if $verbose;
453 exec($command) || die "exec: $!";
456 # an ordered list of repos
458 foreach my $topdir (sort keys %config) {
459 foreach my $subdir (sort keys %{$config{$topdir}}) {
463 order => $config{$topdir}{$subdir}{order},
468 $a->{order} <=> $b->{order}
470 $a->{topdir} cmp $b->{topdir}
472 $a->{subdir} cmp $b->{subdir}
475 # work out what repos to act on
478 foreach my $repo (@list) {
479 my $topdir=$repo->{topdir};
480 my $subdir=$repo->{subdir};
482 next if $subdir eq 'DEFAULT';
483 my $dir=($subdir =~/^\//) ? $subdir : $topdir.$subdir;
485 $dir.="/" unless $dir=~/\/$/;
486 $d.="/" unless $d=~/\/$/;
487 next if $no_recurse && $d ne $dir;
488 next if $dir ne $d && $dir !~ /^\Q$d\E/;
489 push @repos, [$dir, $topdir, $subdir];
492 # fallback to find a leaf repo
493 foreach my $repo (reverse @list) {
494 my $topdir=$repo->{topdir};
495 my $subdir=$repo->{subdir};
497 next if $subdir eq 'DEFAULT';
498 my $dir=($subdir =~/^\//) ? $subdir : $topdir.$subdir;
500 $dir.="/" unless $dir=~/\/$/;
501 $d.="/" unless $d=~/\/$/;
502 if ($d=~/^\Q$dir\E/) {
503 push @repos, [$dir, $topdir, $subdir];
510 # run the action on each repository and print stats
511 my (@ok, @failed, @skipped);
516 foreach my $repo (@repos) {
517 record($repo, action($action, @$repo));
520 if (! @ok && ! @failed && ! @skipped) {
521 die "mr $action: no repositories found to work on\n";
523 print "mr $action: finished (".join("; ",
524 showstat($#ok+1, "ok", "ok"),
525 showstat($#failed+1, "failed", "failed"),
526 showstat($#skipped+1, "skipped", "skipped"),
530 print "mr $action: (skipped: ".join(" ", @skipped).")\n";
533 print STDERR "mr $action: (failed: ".join(" ", @failed).")\n";
539 elsif (! @ok && @skipped) {
545 my ($action, $dir, $topdir, $subdir) = @_;
548 foreach my $rcs_test (
550 length $a <=> length $b
553 } grep { /_test$/ } keys %{$config{$topdir}{$subdir}}) {
554 my ($rcs)=$rcs_test=~/(.*)_test/;
555 $test="my_$rcs_test() {\n$config{$topdir}{$subdir}{$rcs_test}\n}\n".$test;
556 $test.="if my_$rcs_test; then echo $rcs; fi\n";
558 $test=$config{$topdir}{$subdir}{lib}."\n".$test
559 if exists $config{$topdir}{$subdir}{lib};
561 print "mr $action: running rcs test >>$test<<\n" if $verbose;
572 sub findcommand { #{{{
573 my ($action, $dir, $topdir, $subdir) = @_;
575 if (exists $config{$topdir}{$subdir}{$action}) {
576 return $config{$topdir}{$subdir}{$action};
579 my $rcs=rcs_test(@_);
582 exists $config{$topdir}{$subdir}{$rcs."_".$action}) {
583 return $config{$topdir}{$subdir}{$rcs."_".$action};
591 my ($action, $dir, $topdir, $subdir) = @_;
593 $ENV{MR_CONFIG}=$configfiles{$topdir};
594 my $lib=exists $config{$topdir}{$subdir}{lib} ?
595 $config{$topdir}{$subdir}{lib}."\n" : "";
597 if ($action eq 'checkout') {
599 print "mr $action: $dir already exists, skipping checkout\n" if $verbose;
603 $dir=~s/^(.*)\/[^\/]+\/?$/$1/;
606 print "mr $action: creating parent directory $dir\n" if $verbose;
607 system("mkdir", "-p", $dir);
610 elsif ($action =~ /update/) {
612 return action("checkout", $dir, $topdir, $subdir);
618 my $skiptest=findcommand("skip", $dir, $topdir, $subdir);
619 my $command=findcommand($action, $dir, $topdir, $subdir);
621 if (defined $skiptest) {
622 my $test="set -e;".$lib.
623 "my_action(){ $skiptest\n }; my_action '$action'";
624 print "mr $action: running skip test >>$test<<\n" if $verbose;
625 my $ret=system($test);
627 if (($? & 127) == 2) {
628 print STDERR "mr $action: interrupted\n";
632 print STDERR "mr $action: skip test received signal ".($? & 127)."\n";
636 if ($ret >> 8 == 0) {
637 print "mr $action: $dir skipped per config file\n" if $verbose;
642 if (! $nochdir && ! chdir($dir)) {
643 print STDERR "mr $action: failed to chdir to $dir: $!\n";
646 elsif (! defined $command) {
647 my $rcs=rcs_test(@_);
648 if (! defined $rcs) {
649 print STDERR "mr $action: unknown repository type and no defined $action command for $topdir$subdir\n";
653 print STDERR "mr $action: no defined $action command for $rcs repository $topdir$subdir, skipping\n";
659 print "mr $action: $topdir$subdir\n";
663 $s=~s/^\Q$topdir$subdir\E\/?//;
664 print "mr $action: $topdir$subdir (in subdir $s)\n";
666 $command="set -e; ".$lib.
667 "my_action(){ $command\n }; my_action ".
668 join(" ", map { s/\//\/\//g; s/"/\"/g; '"'.$_.'"' } @ARGV);
669 print "mr $action: running >>$command<<\n" if $verbose;
670 my $ret=system($command);
672 if (($? & 127) == 2) {
673 print STDERR "mr $action: interrupted\n";
677 print STDERR "mr $action: received signal ".($? & 127)."\n";
680 print STDERR "mr $action: failed ($ret)\n" if $verbose;
681 if ($ret >> 8 != 0) {
682 print STDERR "mr $action: command failed\n";
685 print STDERR "mr $action: command died ($ret)\n";
690 if ($action eq 'checkout' && ! -d $dir) {
691 print STDERR "mr $action: $dir missing after checkout\n";;
700 # run actions on multiple repos, in parallel
707 while (@fhs or @repos) {
708 while ($running < $jobs && @repos) {
710 my $repo = shift @repos;
711 pipe(my $outfh, CHILD_STDOUT);
712 pipe(my $errfh, CHILD_STDERR);
714 unless ($pid = fork) {
715 die "mr $action: cannot fork: $!" unless defined $pid;
716 open(STDOUT, ">&CHILD_STDOUT") || die "mr $action cannot reopen stdout: $!";
717 open(STDERR, ">&CHILD_STDERR") || die "mr $action cannot reopen stderr: $!";
722 exit action($action, @$repo);
726 push @active, [$pid, $repo];
727 push @fhs, [$outfh, $errfh];
730 my ($rin, $rout) = ('','');
732 foreach my $fh (@fhs) {
733 next unless defined $fh;
734 vec($rin, fileno($fh->[0]), 1) = 1 if defined $fh->[0];
735 vec($rin, fileno($fh->[1]), 1) = 1 if defined $fh->[1];
737 $nfound = select($rout=$rin, undef, undef, 1);
738 foreach my $channel (0, 1) {
739 foreach my $i (0..$#fhs) {
740 next unless defined $fhs[$i];
741 my $fh = $fhs[$i][$channel];
742 next unless defined $fh;
743 if (vec($rout, fileno($fh), 1) == 1) {
745 if (sysread($fh, $r, 1024) == 0) {
747 $fhs[$i][$channel] = undef;
748 if (! defined $fhs[$i][0] &&
749 ! defined $fhs[$i][1]) {
750 waitpid($active[$i][0], 0);
751 print STDOUT $out[$i][0];
752 print STDERR $out[$i][1];
753 record($active[$i][1], $? >> 8);
755 splice(@active, $i, 1);
760 $out[$i][$channel] .= $r;
768 my $dir=shift()->[0];
775 elsif ($ret == FAILED) {
779 elsif ($ret == SKIPPED) {
782 elsif ($ret == ABORT) {
786 die "unknown exit status $ret";
795 return "$count ".($count > 1 ? $plural : $singular);
801 sub loadconfig { #{{{
808 if (ref $f eq 'GLOB') {
817 my $absf=abs_path($f);
818 if ($loaded{$absf}) {
823 ($dir)=$f=~/^(.*\/)[^\/]+$/;
824 if (! defined $dir) {
827 $dir=abs_path($dir)."/";
829 if (! exists $configfiles{$dir}) {
830 $configfiles{$dir}=$f;
833 # copy in defaults from first parent
835 while ($parent=~s/^(.*\/)[^\/]+\/?$/$1/) {
836 if ($parent eq '/') {
839 if (exists $config{$parent} &&
840 exists $config{$parent}{DEFAULT}) {
841 $config{$dir}{DEFAULT}={ %{$config{$parent}{DEFAULT}} };
846 print "mr: loading config $f\n" if $verbose;
847 open($in, "<", $f) || die "mr: open $f: $!\n";
858 next if /^\s*\#/ || /^\s*$/;
859 if (/^\[([^\]]*)\]\s*$/) {
862 elsif (/^(\w+)\s*=\s*(.*)/) {
867 while (@lines && $lines[0]=~/^\s(.+)/) {
874 if ($parameter eq "include") {
875 print "mr: including output of \"$value\"\n" if $verbose;
876 unshift @lines, `$value`;
880 if (! defined $section) {
881 die "$f line $.: parameter ($parameter) not in section\n";
883 if ($section ne 'ALIAS' &&
884 ! exists $config{$dir}{$section} &&
885 exists $config{$dir}{DEFAULT}) {
887 $config{$dir}{$section}={ %{$config{$dir}{DEFAULT}} };
889 if ($section eq 'ALIAS') {
890 $alias{$parameter}=$value;
892 elsif ($parameter eq 'lib') {
893 $config{$dir}{$section}{lib}.=$value."\n";
896 $config{$dir}{$section}{$parameter}=$value;
897 if ($parameter =~ /.*_(.*)/) {
901 $knownactions{$parameter}=1;
903 if ($parameter eq 'chain' &&
904 length $dir && $section ne "DEFAULT" &&
905 -e $dir.$section."/.mrconfig") {
906 my $ret=system($value);
908 if (($? & 127) == 2) {
909 print STDERR "mr $action: chain test interrupted\n";
913 print STDERR "mr $action: chain test received signal ".($? & 127)."\n";
917 push @toload, $dir.$section."/.mrconfig";
923 die "$f line $line: parse error\n";
932 sub modifyconfig { #{{{
934 # the section to modify or add
935 my $targetsection=shift;
936 # fields to change in the section
937 # To remove a field, set its value to "".
944 open(my $in, "<", $f) || die "mr: open $f: $!\n";
949 my $formatfield=sub {
951 my @value=split(/\n/, shift);
953 return "$field = ".shift(@value)."\n".
954 join("", map { "\t$_\n" } @value);
958 while ($out[$#out] =~ /^\s*$/) {
959 unshift @blanks, pop @out;
961 foreach my $field (sort keys %changefields) {
962 if (length $changefields{$field}) {
963 push @out, "$field = $changefields{$field}\n";
964 delete $changefields{$field};
974 if (/^\s*\#/ || /^\s*$/) {
977 elsif (/^\[([^\]]*)\]\s*$/) {
978 if (defined $section &&
979 $section eq $targetsection) {
987 elsif (/^(\w+)\s*=\s(.*)/) {
992 while (@lines && $lines[0]=~/^\s(.+)/) {
998 if ($section eq $targetsection) {
999 if (exists $changefields{$parameter}) {
1000 if (length $changefields{$parameter}) {
1001 $value=$changefields{$parameter};
1003 delete $changefields{$parameter};
1007 push @out, $formatfield->($parameter, $value);
1011 if (defined $section &&
1012 $section eq $targetsection) {
1015 elsif (%changefields) {
1016 push @out, "\n[$targetsection]\n";
1017 foreach my $field (sort keys %changefields) {
1018 if (length $changefields{$field}) {
1019 push @out, $formatfield->($field, $changefields{$field});
1024 open(my $out, ">", $f) || die "mr: write $f: $!\n";
1029 # Finally, some useful actions that mr knows about by default.
1030 # These can be overridden in ~/.mrconfig.
1046 echo "mr (warning): $@" >&2
1052 if [ -z "$1" ] || [ -z "$2" ]; then
1053 error "mr: usage: hours_since action num"
1055 for dir in .git .svn .bzr CVS .hg _darcs; do
1056 if [ -e "$MR_REPO/$dir" ]; then
1057 flagfile="$MR_REPO/$dir/.mr_last$1"
1061 if [ -z "$flagfile" ]; then
1062 error "cannot determine flag filename"
1064 delta=$(perl -wle 'print -f shift() ? int((-M _) * 24) : 9999' "$flagfile")
1065 if [ "$delta" -lt "$2" ]; then
1073 svn_test = test -d "$MR_REPO"/.svn
1074 git_test = test -d "$MR_REPO"/.git
1075 bzr_test = test -d "$MR_REPO"/.bzr
1076 cvs_test = test -d "$MR_REPO"/CVS
1077 hg_test = test -d "$MR_REPO"/.hg
1078 darcs_test = test -d "$MR_REPO"/_darcs
1080 test -d "$MR_REPO"/refs/heads && test -d "$MR_REPO"/refs/tags &&
1081 test -d "$MR_REPO"/objects && test -f "$MR_REPO"/config &&
1082 test "$(GIT_CONFIG="$MR_REPO"/config git-config --get core.bare)" = true
1084 svn_update = svn update "$@"
1085 git_update = if [ "$@" ]; then git pull "$@"; else git pull -t origin master; fi
1086 bzr_update = bzr merge "$@"
1087 cvs_update = cvs update "$@"
1088 hg_update = hg pull "$@" && hg update "$@"
1089 darcs_update = darcs pull -a "$@"
1091 svn_status = svn status "$@"
1092 git_status = git status "$@" || true
1093 bzr_status = bzr status "$@"
1094 cvs_status = cvs status "$@"
1095 hg_status = hg status "$@"
1096 darcs_status = darcs whatsnew -ls "$@"
1098 svn_commit = svn commit "$@"
1099 git_commit = git commit -a "$@" && git push --all
1100 bzr_commit = bzr commit "$@" && bzr push
1101 cvs_commit = cvs commit "$@"
1102 hg_commit = hg commit -m "$@" && hg push
1103 darcs_commit = darcs commit -a -m "$@" && darcs push -a
1105 svn_diff = svn diff "$@"
1106 git_diff = git diff "$@"
1107 bzr_diff = bzr diff "$@"
1108 cvs_diff = cvs diff "$@"
1109 hg_diff = hg diff "$@"
1110 darcs_diff = darcs diff "$@"
1112 svn_log = svn log "$@"
1113 git_log = git log "$@"
1114 bzr_log = bzr log "$@"
1115 cvs_log = cvs log "$@"
1116 hg_log = hg log "$@"
1117 darcs_log = darcs changes "$@"
1118 git_bare_log = git log "$@"
1121 url=$(LANG=C svn info . | grep -i ^URL: | cut -d ' ' -f 2)
1122 if [ -z "$url" ]; then
1123 error "cannot determine svn url"
1125 echo "Registering svn url: $url in $MR_CONFIG"
1126 mr -c "$MR_CONFIG" config "`pwd`" checkout="svn co '$url' '$MR_REPO'"
1128 url="$(LANG=C git-config --get remote.origin.url)" || true
1129 if [ -z "$url" ]; then
1130 error "cannot determine git url"
1132 echo "Registering git url: $url in $MR_CONFIG"
1133 mr -c "$MR_CONFIG" config "`pwd`" checkout="git clone '$url' '$MR_REPO'"
1135 url=$(cat .bzr/branch/parent)
1136 if [ -z "$url" ]; then
1137 error "cannot determine bzr url"
1139 echo "Registering bzr url: $url in $MR_CONFIG"
1140 mr -c "$MR_CONFIG" config "`pwd`" checkout="bzr clone '$url' '$MR_REPO'"
1142 repo=$(cat CVS/Repository)
1143 root=$(cat CVS/Root)
1144 if [ -z "$root" ]; then
1145 error "cannot determine cvs root"
1147 echo "Registering cvs repository $repo at root $root"
1148 mr -c "$MR_CONFIG" config "`pwd`" checkout="cvs -d '$root' co -d '$MR_REPO' '$repo'"
1150 url=$(hg showconfig paths.default)
1151 echo "Registering mercurial repo url: $url in $MR_CONFIG"
1152 mr -c "$MR_CONFIG" config "`pwd`" checkout="hg clone '$url' '$MR_REPO'"
1154 url=$(cat _darcs/prefs/defaultrepo)
1155 echo "Registering darcs repository $url in $MR_CONFIG"
1156 mr -c "$MR_CONFIG" config "`pwd`" checkout="darcs get '$url'p '$MR_REPO'"
1158 url="$(LANG=C GIT_CONFIG=config git-config --get remote.origin.url)" || true
1159 if [ -z "$url" ]; then
1160 error "cannot determine git url"
1162 echo "Registering git url: $url in $MR_CONFIG"
1163 mr -c "$MR_CONFIG" config "`pwd`" checkout="git clone --bare '$url' '$MR_REPO'"
1166 if [ ! -e "$MR_PATH" ]; then
1167 error "cannot find program path"
1169 (pod2man -c mr "$MR_PATH" | man -l -) || error "pod2man or man failed"
1173 ed = echo "A horse is a horse, of course, of course.."
1174 T = echo "I pity the fool."
1175 right = echo "Not found."
1178 # vim:sw=8:sts=0:ts=8:noet