- A CLI that walks directories, finds Git repositories, and prints a status summary as a table or JSON.
- Also includes a powerful Python-based expression language for filtering repos and operating on them in batch.
uv tool install .To pick up local code changes when the version hasn't been bumped:
uv tool install --force --reinstall .For development (editable install):
uv tool install -e --force .gitoverit [OPTIONS] [DIRS...]
If no directory is given, the current directory is used. Run with -h for the option list.
-f, --fetch Run `git fetch --all` for each repo before inspection.
--pull-safe Fetch first, then run `git pull --ff-only` only for
repos that are behind, not ahead, and otherwise clean.
-o, --format {table,json} Output format. Default: table.
-d, --dirty-only Hide repos with no uncommitted changes.
-s, --sort {mtime,author,none}
Sort by latest worktree mtime (default), committer
identity, or disable sorting.
-r, --reverse Reverse the active sort order.
-j, --jobs N Worker count. Omit for auto-detect; 0 for sequential.
-a, --table-algo {cell,char}
Column-width algorithm for the table renderer.
-c, --columns SPEC Add/remove/reset columns. See "Columns" below.
-w, --where EXPR Filter rows by an expression. See `--help-where`.
-p, --print EXPR Evaluate EXPR per repo and print the result, one
per line. Replaces table/JSON output.
-0, --print0 With --print, separate results with NUL bytes
instead of newlines.
--errors Print error tracebacks to stderr after output.
--no-progress Suppress the progress bar even on a TTY.
--help-where Show full reference for --where / --print.
--columns takes a comma-separated spec. A bare name adds a column,
-name removes one, and a single - clears all columns first so the
remainder of the spec defines the full set.
Available columns: dir, status, branch_remote, branch, remote,
url, mtime, ident.
# Drop the URL column
gitoverit ~/projects -c -url
# Show only dir and status
gitoverit ~/projects -c -,dir,status# Scan the current directory
gitoverit .
# Scan multiple roots
gitoverit ~/projects ~/work
# Sequential mode
gitoverit ~/projects -j 0
# 4 workers
gitoverit ~/projects -j 4
# Dirty repos only, sorted by author
gitoverit ~/projects -d -s author
# Fetch first, then output JSON
gitoverit ~/projects -f -o json
# Safely fast-forward repos that are behind upstream
gitoverit ~/projects --pull-safe
# Repos on a non-main branch with unpushed commits
gitoverit ~/projects -w 'branch != "main" and ahead > 0'
# Print absolute paths of dirty repos, NUL-delimited (xargs-friendly)
gitoverit ~/projects -w dirty -p path -0 | xargs -0 -n1 echo--where and --print share an expression language (sandboxed via
simpleeval). Variables include path, dir, status, branch,
remote, url, ident, mtime, dirty, ahead, behind,
modified, untracked, and deleted. String variables expose .rx()
and .rxi() for regex matching.
Run gitoverit --help-where for the full reference and more examples.
Push every repo that's ahead of its tracking branch, clean, and not behind:
gitoverit ~/projects -f -w 'ahead and not behind and not dirty' -p path -0 \
| xargs -0 -I{} git -C {} pushPull every repo that's behind its tracking branch, clean, and not ahead:
gitoverit ~/projects -f -w 'behind and not ahead and not dirty' -p path -0 \
| xargs -0 -I{} git -C {} pull--pull-safe only pulls repos that are in a state where pulling is unlikely
to create merge conflicts. To pull more aggressively, use the -p + xargs
recipe above.
List repos that have diverged (commits in both directions) so you can resolve them by hand:
gitoverit ~/projects -f -w 'ahead and behind'List repos with no upstream tracking branch:
gitoverit ~/projects -w 'remote == "-"'Find repos hosted under a specific GitHub org (substring match on the remote URL):
gitoverit ~/projects -w '"acme/" in url'Print <dir> <branch> for every repo not on main or master, useful
for piping into other tooling:
gitoverit ~/projects -w 'branch != "main" and branch != "master"' \
-p 'dir + " " + branch'Repositories are analyzed in a ThreadPoolExecutor; threads are a good
fit because per-repo work is dominated by git subprocess I/O. Discovery
streams into the pool so workers start immediately.
The default worker count is cpu_count - 1, capped at 8. Override with
-j N, or use -j 0 to run on the main thread (useful for debugging).
When stdout is a TTY, a Rich progress bar is shown: an indeterminate
"Discovery" phase followed by a determinate "Statusing" bar. Pass
--no-progress to suppress it. When stdout is not a TTY, no progress
output is emitted.
To implement a custom progress reporter, see HookProtocol in
src/gitoverit/progress.py.
I don't consider this project "vibe coded." I used AI assistance to help with planning, rubberducking, and writing some of the code. I myself know and have reviewed the code.
