>_ZSH-GIT-REPO-CACHE
Every git repo on disk, instantly searchable. Crawls the root filesystem to locate every git repository and caches results for instant retrieval. Uses fd when available, falls back to find. Integrates with fzf for interactive selection.
Overview
The plugin builds three plain-text caches under $HOME — one path per line, sorted and deduped — and exposes 8 autoload functions that read or rebuild them. The flow is three stages:
[ SCAN ] ──> [ CACHE ] ──> [ QUERY ] │ │ │ fd / find ~/.zsh-git- fzf / list @ / repo-cache output + cd
Scan. regenAllGitRepos runs sudo fd '\.git$' / --type d --threads=8 --hidden --no-ignore (or sudo find / -name .git -type d -prune when fd is absent), strips the trailing /.git, removes the macOS /System/Volumes/Data and /System/Volumes/Update/mnt1 mirror prefixes (only when $ZPWR_OS_TYPE == darwin), then sort | uniq into the master cache.
Bisect. regenAllGitReposDirty walks the master list once, runs git diff-index --quiet HEAD + git ls-files --exclude-standard --others on each repo, and writes dirty paths to one cache and clean paths to another via two concurrent file descriptors (exec 3> / exec 4>) — both caches in a single pass.
Query. Search functions either live-walk the master list (always fresh) or read the pre-bisected dirty/clean caches (cheap). In default mode they pipe through fzf, echo the resolved cd "...", and eval it; in list mode they emit raw paths to stdout.
Requirements
zsh | required — the plugin host (works on zsh 5.x) |
git | required — dirty/clean probing via git diff-index / git ls-files |
perl | required — trailing-/.git strip and macOS Volumes-mirror strip passes |
sudo | required for a full-disk crawl — the scan runs sudo to read root-owned and restricted dirs |
fd | optional — accelerated 8-thread crawl; falls back to find when missing |
fzf | optional — interactive picker for the non-list query modes |
zpwr | optional — enables the 10 gitrepos* verbs; the functions work standalone without it |
Install
# Zinit
zinit light MenkeTechnologies/zsh-git-repo-cache
# Oh My Zsh
git clone https://github.com/MenkeTechnologies/zsh-git-repo-cache \
"${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-git-repo-cache"
# then: plugins+=(zsh-git-repo-cache)
# Manual
git clone https://github.com/MenkeTechnologies/zsh-git-repo-cache
source zsh-git-repo-cache/zsh-git-repo-cache.plugin.zsh
Data nodes
ZPWR_ALL_GIT_DIRS | ~/.zsh-git-repo-cache — all repos |
ZPWR_ALL_GIT_DIRS_DIRTY | ~/.zsh-git-repo-cache-dirty — dirty repos |
ZPWR_ALL_GIT_DIRS_CLEAN | ~/.zsh-git-repo-cache-clean — clean repos |
Functions
zsh-git-repo-regenAllGitRepos | scorched-earth rescan of / — rebuilds the master cache |
zsh-git-repo-regenAllGitReposDirty | bisect master into dirty + clean caches in one pass (regenerates master first if it is missing/empty) |
zsh-git-repo-searchAllGitRepos | query all indexed repos (reads the master cache) |
zsh-git-repo-searchDirtyGitRepos | live-walk: only repos with uncommitted changes or untracked files |
zsh-git-repo-searchCleanGitRepos | live-walk: only clean working trees (no staged diff, no untracked) |
zsh-git-repo-searchDirtyGitReposCache | read the dirty cache — regenerates it if missing/empty |
zsh-git-repo-searchCleanGitReposCache | read the clean cache — regenerates it if missing/empty |
zsh-git-repo-searchGitCommon | shared tail — captures the inner goThere output, echoes the cd "...", then evals it |
Invocation contract
Every search* function reads exactly two positional arguments — no flags, no getopts. The ZPWR_VERBS list entries encode the same two slots (... n list means $1=n, $2=list).
$1 = regen | Force a rebuild before querying. Any other value (e.g. n) skips the forced rebuild — the cache is still auto-rebuilt when the file is missing or empty. |
$2 = list | Emit raw paths to stdout. Any other value (or none) runs the fzf picker, echoes the resolved cd "...", and evals it. |
Usage
# fzf-pick any repo on the machine and cd into it (default mode) zsh-git-repo-searchAllGitRepos # force a fresh rescan of / first, then fzf-pick zsh-git-repo-searchAllGitRepos regen # list dirty repos to stdout — live walk, no fzf, no cd zsh-git-repo-searchDirtyGitRepos n list # count repos with uncommitted work on this host zsh-git-repo-searchDirtyGitRepos n list | wc -l # read the pre-bisected caches instead of live-walking zsh-git-repo-searchDirtyGitReposCache n list zsh-git-repo-searchCleanGitReposCache n list # rebuild the caches explicitly zsh-git-repo-regenAllGitRepos # master cache zsh-git-repo-regenAllGitReposDirty # dirty + clean caches
zpwr verbs
When running inside zpwr:
gitreposlist list all repos gitreposcleanlist list clean repos gitreposdirtylist list dirty repos gitreposcleancachelist list clean repos (cached) gitreposdirtycachelist list dirty repos (cached) gitrepos search all repos in fzf gitreposclean search clean repos in fzf gitreposdirty search dirty repos in fzf gitreposcleancache search clean repos in fzf (cached) gitreposdirtycache search dirty repos in fzf (cached)
Configuration
Every variable below is defaulted by the plugin only when unset, so a pre-existing zpwr environment keeps its own values:
ZPWR_ALL_GIT_DIRS | master cache path — default ~/.zsh-git-repo-cache |
ZPWR_ALL_GIT_DIRS_DIRTY | dirty cache path — default ~/.zsh-git-repo-cache-dirty |
ZPWR_ALL_GIT_DIRS_CLEAN | clean cache path — default ~/.zsh-git-repo-cache-clean |
ZPWR_TEMPFILE3 | scratch buffer for the inline perl edits — default $TMPDIR/.zsh-git-repo-temp |
ZPWR_FZF | fzf invocation name — default fzf (override for a custom wrapper) |
Two more variables are read but never written by this plugin — the caller (typically zpwr) supplies them:
FZF_SEARCH_GIT_OPTS | extra fzf flags appended verbatim: eval "$ZPWR_FZF $FZF_SEARCH_GIT_OPTS" |
ZPWR_OS_TYPE | when == darwin, the scan strips the macOS /System/Volumes mirror prefixes |
Troubleshooting
| Cache is empty / stale | Run zsh-git-repo-regenAllGitRepos (master) then zsh-git-repo-regenAllGitReposDirty (dirty + clean). Search functions also auto-regenerate when a cache file is missing or empty. |
| Scan asks for a sudo password | Expected — the crawl runs sudo to read root-owned and restricted directories under /. |
| Slow scan | Install fd; the plugin prefers it (--threads=8 --hidden --no-ignore) and falls back to find only when fd is absent. |
| Duplicate repos on macOS | Ensure ZPWR_OS_TYPE=darwin so the /System/Volumes/Data and /System/Volumes/Update/mnt1 mirror prefixes are stripped before sort | uniq. |
gitrepos* verbs missing | The verbs register only inside zpwr (guarded by (( ${+ZPWR_VERBS} ))). Call the zsh-git-repo-* functions directly for a standalone install. |
Sibling plugins
Part of the MenkeTechnologies zsh plugin family — the MenkeTechnologiesMeta umbrella:
- zsh-better-npm-completion — cache-aware
npm installcompletion - zsh-cargo-completion — live
cargo add/cargo installcompletion - zsh-cpan-completion — live MetaCPAN
cpan/cpanmcompletion - zsh-dotnet-completion — dotnet CLI completion
- zsh-expand — spacebar expansion (11,683 tests)
- zsh-gem-completion — ruby
gem installremote completion - zsh-git-acp — 159 git aliases + add/commit/push keybindings
- zsh-learn — MySQL-backed learning collection / quiz
- zsh-more-completions — 33,175-file mega completion corpus
- zsh-nginx — nginx commands + service-wrapper aliases
- zsh-pip-description-completion — pip remote completion with descriptions
- zsh-sed-sub — in-place sed substitution on the command line
- zsh-sudo — ESC ESC to prepend sudo
- zsh-xcode-completions — xcodebuild / xcrun / swift completion