A fast CLI tool for managing multiple git repositories at once. Run status checks, pulls, builds, greps, and cross-repo consistency checks over every repo in a single command.
Full documentation: https://veltzer.github.io/rsmultigit/
- Batch operations — pull, push, fetch, diff, grep, clean, commit, and build across all repos at once
- Native git inspection — status, dirty and sync checks use libgit2 in-process, with no
gitsubprocess per repo - Consistency checks —
check sameverifies that shared files (.gitignore, CI workflows, lint configs, ...) are byte-identical across the fleet,check existsverifies that required files are present, and--diff,--copyand--fix-missingrepair drift interactively - Build orchestration — make, rsconstruct, cargo, bootstrap, with each repo's
.venvactivated automatically - Tooling passthrough —
uv lock/uv syncon Python projects,cargo build|check|clippy|fmt|test|nextest|doc|deny|fetch|update|clean|publishon Rust projects,ghcleanup, release/workflow inspection and metadata sync on GitHub repos - Parallel execution —
-j Nruns repos concurrently while keeping output in repo order - Selective output — only prints repos where something happened;
--verbose,--terse,--print-notand--no-headercontrol the rest - Shell completions — bash, zsh, fish, elvish, powershell, including dynamic completion of check names
cargo install rsmultigitEvery release ships binaries for Linux (x86_64, aarch64) and macOS (x86_64, aarch64). The asset names are:
| Platform | Asset |
|---|---|
| Linux x86_64 | rsmultigit-linux-x86_64 |
| Linux aarch64 | rsmultigit-linux-aarch64 |
| macOS x86_64 | rsmultigit-macos-x86_64 |
| macOS aarch64 | rsmultigit-macos-aarch64 |
gh release download --repo veltzer/rsmultigit --pattern rsmultigit-linux-x86_64 --output rsmultigit --clobber
chmod +x rsmultigit
sudo mv rsmultigit /usr/local/bin/Or without the GitHub CLI:
curl -Lo rsmultigit https://github.com/veltzer/rsmultigit/releases/latest/download/rsmultigit-linux-x86_64
chmod +x rsmultigit
sudo mv rsmultigit /usr/local/bin/cargo build --releasersmultigit reads ~/.config/rsmultigit/config.toml on every run. Create it
interactively (it asks where your repositories are and which build tool you
use, with tab completion and a menu):
rsmultigit setup interactiveor bootstrap it from the fully commented built-in example:
mkdir -p ~/.config/rsmultigit
rsmultigit setup config-sample > ~/.config/rsmultigit/config.tomlThe file names the repositories to operate on and, optionally, the consistency rules to enforce:
repos = ["~/git/*"] # shell-expanded globs; non-git matches are ignored
default_build_method = "rsconstruct" # what a bare `rsmultigit build` runs
crates_io_pass_entry = "keys/crates.io" # where `cargo release` finds the crates.io token
[[check]] # files that must be byte-identical
name = "gitignore"
select = "*"
path = ".gitignore"
[[exists]] # files that must be present
name = "readme-present"
select = "*"
path = "README.md"See the configuration docs for every field.
rsmultigit status # one-line summary of every repo that needs attention
rsmultigit -j 8 git pull # pull all repos, 8 at a time
rsmultigit git count dirty # count repos with uncommitted changes
rsmultigit git grep "TODO" # git grep across all repos
rsmultigit check same # verify shared files are identical everywhere
rsmultigit check same --diff # ... and show what differs
rsmultigit build # build every repo with the configured default method
rsmultigit run "git log -1" # run any shell command in every repo
rsmultigit complete bash >> ~/.bash_completionEverything that inspects or operates on the repos as git repositories;
rsmultigit git alone lists it. The reports come first:
| Command | Description |
|---|---|
git status (shortcut: status) |
One-line summary per repo needing attention (--verbose for git status -s) |
git dirty |
Show git diff --stat for repos with modifications |
git count dirty |
Count repositories with uncommitted changes |
git count untracked |
Count repositories with untracked files |
git count unsynchronized |
Count repositories ahead of or behind their upstream |
git count ahead / git count behind |
Count repositories with unpushed / unpulled commits |
git age |
Show the age of the last commit per repo |
git authors |
Show commit authors per repo |
git size |
Show the size of the .git directory per repo |
git last-tag |
Show the most recent tag per repo |
The rest each run the git command of the same name in every repo:
| Command | Description |
|---|---|
git pull [--quiet] |
Pull all repositories |
git push |
Push repositories that are ahead of their upstream |
git fetch |
Fetch from origin |
git commit -m <msg> |
Stage and commit all changes with a shared message |
git checkout <branch> |
Checkout a branch across all repositories |
git stash push / git stash pop |
Stash tracked changes, or pop the stash rsmultigit made; never touches hand-made stashes |
git reset hard / git reset mixed [--dry-run] |
Discard or unstage changes to tracked files; repos with nothing to reset are skipped |
git restore [--dry-run] |
git restore . (discards unstaged changes to tracked files) |
git clean hard [--dry-run] |
git clean -ffxd (removes untracked and ignored files) |
git clean soft [--dry-run] |
git clean -fd (removes untracked files only) |
git diff |
Show the diff of every repo |
git log [--count N] |
Show recent commits (default 10) |
git blame <file> |
git blame in every repo that has the file |
git grep [-l] <regexp> |
git grep across all repositories |
git config <key> |
Show a git config value across all repos |
git branch local / git branch remote / git branch github |
Show local, remote, or GitHub default branches |
git tag local / git tag remote |
List local or remote tags |
git tag has-local / git tag has-remote |
Count repos that have local or remote tags |
git remote |
Show remote URLs |
git remote-prune |
Prune stale remote-tracking branches (git remote prune origin) |
git gc |
Run git garbage collection |
git submodule-update |
git submodule update --init --recursive |
rsmultigit check alone lists these.
| Command | Description |
|---|---|
check same [--diff] [--copy] [--fix-missing] |
Verify the [[check]] files are byte-identical across the repos they select |
check exists |
Verify the [[exists]] files are present in every repo they select |
check all |
Run both; non-zero if either fails |
check list [exists] |
Print the rule names (for shell completion) |
| Command | Description |
|---|---|
run <cmd...> (alias exec) |
Run an arbitrary command in every repo (run make clean for make clean) |
| Command | Description |
|---|---|
build |
Build with the config file's default_build_method |
build make / build bootstrap |
Run make or python bootstrap.py |
build rsconstruct |
Run rsconstruct --quiet build on repos with rsconstruct.toml |
build cargo |
Run cargo build (debug and release) on repos with Cargo.toml |
cargo build [--release|--profile <name>] |
Run cargo build on repos with Cargo.toml: every profile (dev, then release) by default, or just the one named |
cargo check|clippy|test|nextest|doc [--release|--profile <name>] |
Run the matching cargo command on repos with Cargo.toml (clippy as CI: --all-targets -- -D warnings) |
cargo fmt [--check] |
Run cargo fmt --all on repos with Cargo.toml |
cargo deny|fetch|update|clean|publish |
Run cargo deny check, cargo fetch, cargo update, cargo clean or cargo publish on repos with Cargo.toml |
cargo release [--type patch|minor|major] |
Run cargo release on repos whose Cargo.toml has a publishable [package], crates.io token from pass(1) |
uv lock [--upgrade|--check] |
Run uv lock on repos with pyproject.toml |
uv sync|build|publish |
Run uv sync, uv build or uv publish on repos with pyproject.toml |
npm install|ci|update|outdated|test|publish |
Run the matching npm command on repos with package.json |
npm audit [--fix] |
Run npm audit (or npm audit fix) on repos with package.json |
gh clean-all [--keep N] |
Delete old deployments, releases and workflow runs on GitHub repos |
gh artifacts |
List the assets of the latest release (name, size, downloads) on GitHub repos |
gh last-workflow-state |
Print the conclusion of the most recent workflow run on GitHub repos |
gh open-site |
Open the GitHub Pages site of each repo in the browser |
gh sync-metadata [--dry-run] |
Sync GitHub description, topics and feature policy from config/project.lua, printing only what differs |
| Command | Description |
|---|---|
setup interactive [--repos-dir <DIR>] [--build <METHOD>|--no-build] [--overwrite] |
Interactively write a first config file: pick the repositories directory and the default build tool |
setup config-sample |
Print a sample config file to stdout |
list repos |
Print the path of every configured repo |
list dirty|untracked|unsynchronized|ahead|behind |
Print the paths of the repos in that state, one per line |
complete <shell> |
Generate shell completion scripts |
version |
Print detailed version information |
All global options work before or after the subcommand.
| Option | Description |
|---|---|
-v, --verbose |
Print all repos, even when no action is taken |
--terse |
Minimal output: repo names only, or failing rule names for the check commands |
--no-header |
Suppress the [repo] header line before per-repo output |
--no-output |
Suppress command output, keep the [repo] headers |
--print-not |
Invert selection: print repos that do NOT match |
--no-stop |
Report errors and continue instead of stopping at the first one; still exits non-zero if any repo failed |
--short-circuit |
Stop at the first failing rule (check same, check exists) |
-j, --jobs <N> |
Run N repos in parallel (default 1; 0 means all CPUs) |
--venv / --no-venv |
Activate each repo's .venv before running tools (default on) |
MIT