B<mr> is a Multiple Repository management tool. It can checkout, update, or
perform other actions on a set of repositories as if they were one combined
-respository. It supports any combination of subversion, git, cvs, mecurial and
-bzr repositories, and support for other revision control systems can easily be
-added.
+respository. It supports any combination of subversion, git, cvs, mecurial,
+bzr and darcs repositories, and support for other revision control systems can
+easily be added.
B<mr> cds into and operates on all registered repositories at or below your
working directory. Or, if you are in a subdirectory of a repository that
$ENV{MR_CONFIG}="$ENV{HOME}/.mrconfig";
my $config_overridden=0;
-my $directory=getcwd();
my $verbose=0;
my $stats=0;
my $no_recurse=0;
my %configfiles;
my %knownactions;
my %alias;
+my $directory=getcwd();
Getopt::Long::Configure("no_permute");
my $result=GetOptions(
"(Use mr help for man page.)\n");
}
+if (! defined $directory) {
+ die("mr: failed to determine working directory\n");
+}
# Make sure MR_CONFIG is an absolute path, but don't use abs_path since
# the config file might be a symlink to elsewhere, and the directory it's
else {
foreach my $repo (@repos) {
record($repo, action($action, @$repo));
- print "\n";
}
}
if (! @ok && ! @failed && ! @skipped) {
print "mr $action: $topdir$subdir\n";
}
else {
- print "mr $action: $topdir$subdir (in subdir $directory)\n";
+ my $s=$directory;
+ $s=~s/^\Q$topdir$subdir\E\/?//;
+ print "mr $action: $topdir$subdir (in subdir $s)\n";
}
my $command="set -e; ".$lib.
"my_action(){ $config{$topdir}{$subdir}{$action}\n }; my_action ".
waitpid($active[$i][0], 0);
print STDOUT $out[$i][0];
print STDERR $out[$i][1];
- print "\n";
record($active[$i][1], $? >> 8);
splice(@fhs, $i, 1);
splice(@active, $i, 1);
if ($ret == OK) {
push @ok, $dir;
+ print "\n";
}
elsif ($ret == FAILED) {
push @failed, $dir;
+ print "\n";
}
elsif ($ret == SKIPPED) {
push @skipped, $dir;
if [ -z "$1" ] || [ -z "$2" ]; then
error "mr: usage: hours_since action num"
fi
- for dir in .git .svn .bzr CVS .hg; do
+ for dir in .git .svn .bzr CVS .hg _darcs; do
if [ -e "$MR_REPO/$dir" ]; then
flagfile="$MR_REPO/$dir/.mr_last$1"
break
exit 1
fi
}
+ get_git_repo_type()
+ {
+ if [ -d "$1"/.git ] && [ -d "$1"/.git/refs/heads ] &&
+ [ -d "$1"/.git/objects ] && [ -f "$1"/.git/config ];
+ then
+ echo non-bare
+ elif [ -d "$1"/refs/heads ] && [ -d "$1"/refs/tags ] &&
+ [ -d "$1"/objects ] && [ -f "$1"/config ]; then
+ local bare
+ bare="$(GIT_CONFIG="$1"/config git-config --get core.bare)"
+ case "$bare" in
+ true) echo bare;;
+ false) echo fake-bare;;
+ *) return 255;;
+ esac
+ else
+ return 1
+ fi
+ }
+ is_git_repo() {
+ get_git_repo_type "$1" >/dev/null
+ }
update =
if [ -d "$MR_REPO"/.svn ]; then
svn update "$@"
- elif [ -d "$MR_REPO"/.git ]; then
- if [ -z "$@" ]; then
- git pull -t origin master
- else
- git pull "$@"
- fi
+ elif is_git_repo "$MR_REPO"; then
+ # all this is because of a bug in git-fetch, which requires GIT_DIR set
+ local git_dir_override; git_dir_override=.git
+ case "$(get_git_repo_type "$MR_REPO")" in
+ fake-bare) git_dir_override="$MR_REPO";;
+ esac
+ args="$@"
+ [ -z "$args" ] && args="-t origin master"
+ eval GIT_DIR="$git_dir_override" git pull "$args"
elif [ -d "$MR_REPO"/.bzr ]; then
bzr merge "$@"
elif [ -d "$MR_REPO"/CVS ]; then
cvs update "$@"
elif [ -d "$MR_REPO"/.hg ]; then
hg pull "$@" && hg update "$@"
+ elif [ -d "$MR_REPO"/_darcs ]; then
+ darcs pull -a "$@"
else
error "unknown repo type"
fi
status =
if [ -d "$MR_REPO"/.svn ]; then
svn status "$@"
- elif [ -d "$MR_REPO"/.git ]; then
+ elif is_git_repo "$MR_REPO"; then
git status "$@" || true
elif [ -d "$MR_REPO"/.bzr ]; then
bzr status "$@"
cvs status "$@"
elif [ -d "$MR_REPO"/.hg ]; then
hg status "$@"
+ elif [ -d "$MR_REPO"/_darcs ]; then
+ darcs whatsnew -ls "$@"
else
error "unknown repo type"
fi
commit =
if [ -d "$MR_REPO"/.svn ]; then
svn commit "$@"
- elif [ -d "$MR_REPO"/.git ]; then
+ elif is_git_repo "$MR_REPO"; then
+ case "$(get_git_repo_type "$MR_REPO")" in
+ bare) error "cannot commit to bare git repositories";;
+ fake-bare) error "commit does not work for fake bare git repositories (yet).";;
+ esac
git commit -a "$@" && git push --all
elif [ -d "$MR_REPO"/.bzr ]; then
bzr commit "$@" && bzr push
cvs commit "$@"
elif [ -d "$MR_REPO"/.hg ]; then
hg commit -m "$@" && hg push
+ elif [ -d "$MR_REPO"/_darcs ]; then
+ darcs commit -a -m "$@" && darcs push -a
else
error "unknown repo type"
fi
diff =
if [ -d "$MR_REPO"/.svn ]; then
svn diff "$@"
- elif [ -d "$MR_REPO"/.git ]; then
+ elif is_git_repo "$MR_REPO"; then
+ case "$(get_git_repo_type "$MR_REPO")" in
+ bare) error "cannot diff in bare git repositories";;
+ fake-bare) error "diff does not work for fake bare git repositories (yet).";;
+ esac
git diff "$@"
elif [ -d "$MR_REPO"/.bzr ]; then
bzr diff "$@"
cvs diff "$@"
elif [ -d "$MR_REPO"/.hg ]; then
hg diff "$@"
+ elif [ -d "$MR_REPO"/_darcs ]; then
+ darcs diff "$@"
else
error "unknown repo type"
fi
log =
if [ -d "$MR_REPO"/.svn ]; then
svn log"$@"
- elif [ -d "$MR_REPO"/.git ]; then
+ elif is_git_repo "$MR_REPO"; then
git log "$@"
elif [ -d "$MR_REPO"/.bzr ]; then
bzr log "$@"
cvs log "$@"
elif [ -d "$MR_REPO"/.hg ]; then
hg log "$@"
+ elif [ -d "$MR_REPO"/_darcs ]; then
+ darcs changes "$@"
else
error "unknown repo type"
fi
fi
echo "Registering svn url: $url in $MR_CONFIG"
mr -c "$MR_CONFIG" config "$(pwd)" checkout="svn co $url $basedir"
- elif [ -d .git ]; then
- url=$(LANG=C git-config --get remote.origin.url)
+ elif is_git_repo .; then
+ local repo_type; repo_type="$(get_git_repo_type .)"
+ local config;
+ case "$repo_type" in
+ non-bare) config=.git/config;;
+ bare|fake-bare) config=config;;
+ *) error "unknown git repository type: $repo_type"
+ esac
+ url="$(LANG=C GIT_CONFIG="$config" git-config --get remote.origin.url)"
if [ -z "$url" ]; then
error "cannot determine git url"
fi
- echo "Registering git url: $url in $MR_CONFIG"
+ case "$repo_type" in
+ bare|fake-bare)
+ # this seems like a bare repo as it has no
+ # worktree.
+ local work_tree
+ work_tree="$(git-config --get core.worktree)" || :
+ if [ ! -d "$work_tree" ]; then
+ error "git worktree $work_tree does not exist"
+ fi
+ suffix=" (with worktree $work_tree)"
+ mr -c "$MR_CONFIG" config "$(pwd)" \
+ lib="GIT_WORK_TREE=$work_tree; export GIT_WORK_TREE"
+ ;;
+ esac
+ echo "Registering git url: $url in $MR_CONFIG${suffix:-}"
mr -c "$MR_CONFIG" config "$(pwd)" checkout="git clone $url $basedir"
elif [ -d .bzr ]; then
url=$(cat .bzr/branch/parent)
echo "Registering mercurial repo url: $url in $MR_CONFIG"
mr -c "$MR_CONFIG" config "$(pwd)" \
checkout="hg clone $url $basedir"
+ elif [ -d _darcs ]; then
+ url=$(cat _darcs/prefs/defaultrepo)
+ echo "Registering darcs repository $url in $MR_CONFIG"
+ mr -c "$MR_CONFIG" config "$(pwd)" \
+ checkout="darcs get $url $basedir"
else
error "unable to register this repo type"
fi
T = echo "I pity the fool."
right = echo "Not found."
#}}}
+
+# vim:sw=8:sts=0:ts=8:noet