When working with multiple, unrelated (or loosly related) git repos,
there is often a need to locate all repos with uncommitted work and
perform some action on them (say, commit and push). Before this patch,
such tasks would require manually visiting all repositories, running
`git status` within each one and then decide what to do next.
This mundane task can now be automated by e.g. `git for-each-repo --dirty
status`, which will find all git repositories below the current directory
(even nested ones), check if they are dirty (as defined by `git diff --quiet
git diff --cached --quiet`), and for each dirty repo print the path to
the repo and then execute `git status` within the repo.
The command also honours the option '--clean' which restricts the set of
repos to those which '--dirty' would skip.
Finally, the command to execute within each repo is optional. If none is
given, git-for-each-repo will just print the path to each repo found.
Signed-off-by: Lars Hjemli hje...@gmail.com
---
.gitignore | 1 +
Documentation/git-for-each-repo.txt | 62 +++
Makefile| 1 +
builtin.h | 1 +
builtin/for-each-repo.c | 119
git.c | 1 +
t/t6400-for-each-repo.sh| 48 +++
7 files changed, 233 insertions(+)
create mode 100644 Documentation/git-for-each-repo.txt
create mode 100644 builtin/for-each-repo.c
create mode 100755 t/t6400-for-each-repo.sh
diff --git a/.gitignore b/.gitignore
index 63d4904..5036b84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,7 @@
/git-filter-branch
/git-fmt-merge-msg
/git-for-each-ref
+/git-for-each-repo
/git-format-patch
/git-fsck
/git-fsck-objects
diff --git a/Documentation/git-for-each-repo.txt
b/Documentation/git-for-each-repo.txt
new file mode 100644
index 000..be49e96
--- /dev/null
+++ b/Documentation/git-for-each-repo.txt
@@ -0,0 +1,62 @@
+git-for-each-repo(1)
+
+
+NAME
+
+git-for-each-repo - Execute a git command in multiple repositories
+
+SYNOPSIS
+
+[verse]
+'git for-each-repo' [--all|--clean|--dirty] [command]
+
+DESCRIPTION
+---
+The git-for-each-repo command is used to locate all git repositoris
+within the current directory tree, and optionally execute a git command
+in each of the found repos.
+
+OPTIONS
+---
+-a::
+--all::
+ Include both clean and dirty repositories (this is the default
+ behaviour of `git-for-each-repo`).
+
+-c::
+--clean::
+ Only include repositories with a clean worktree.
+
+-d::
+--dirty::
+ Only include repositories with a dirty worktree.
+
+EXAMPLES
+
+
+Various ways to exploit this command::
++
+
+$ git for-each-repo1
+$ git for-each-repo fetch 2
+$ git for-each-repo -d gui 3
+$ git for-each-repo -c push4
+
++
+1 Print the path to all repos found below the current directory.
+
+2 Fetch updates from default remote in all repos.
+
+3 Start linkgit:git-gui[1] in each repo containing uncommitted changes.
+
+4 Push the current branch in each repo with no uncommited changes.
+
+NOTES
+-
+
+For the purpose of `git-for-each-repo`, a dirty worktree is defined as a
+worktree with uncommitted changes.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index a786d4c..8c42c17 100644
--- a/Makefile
+++ b/Makefile
@@ -870,6 +870,7 @@ BUILTIN_OBJS += builtin/fetch-pack.o
BUILTIN_OBJS += builtin/fetch.o
BUILTIN_OBJS += builtin/fmt-merge-msg.o
BUILTIN_OBJS += builtin/for-each-ref.o
+BUILTIN_OBJS += builtin/for-each-repo.o
BUILTIN_OBJS += builtin/fsck.o
BUILTIN_OBJS += builtin/gc.o
BUILTIN_OBJS += builtin/grep.o
diff --git a/builtin.h b/builtin.h
index 7e7bbd6..02fc712 100644
--- a/builtin.h
+++ b/builtin.h
@@ -73,6 +73,7 @@ extern int cmd_fetch(int argc, const char **argv, const char
*prefix);
extern int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
+extern int cmd_for_each_repo(int argc, const char **argv, const char *prefix);
extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
extern int cmd_fsck(int argc, const char **argv, const char *prefix);
extern int cmd_gc(int argc, const char **argv, const char *prefix);
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
new file mode 100644
index 000..9bdeb4a
--- /dev/null
+++ b/builtin/for-each-repo.c
@@ -0,0 +1,119 @@
+/*
+ * git for-each-repo builtin command.
+ *
+ * Copyright (c) 2013 Lars Hjemli hje...@gmail.com
+ */
+#include cache.h
+#include color.h
+#include builtin.h
+#include run-command.h
+#include parse-options.h
+
+#define ALL 0
+#define DIRTY 1
+#define CLEAN 2
+
+static int match;
+
+static const char *