No description
  • Go 84.2%
  • Shell 15.8%
Find a file
j 55593bc88c
All checks were successful
Build-Test-Publish / build (push) Successful in 23s
Share one ssh connection per host for fetches
2026-08-15 15:08:40 +12:00
.gitea/workflows Rewrite whatsdirty as a Go program 2026-08-15 11:52:04 +12:00
.gitignore Rewrite whatsdirty as a Go program 2026-08-15 11:52:04 +12:00
build.sh Extract Go toolchain bootstrap into shared ensure_go.sh 2026-08-15 12:45:31 +12:00
complete.go Rewrite whatsdirty as a Go program 2026-08-15 11:52:04 +12:00
ensure_go.sh Extract Go toolchain bootstrap into shared ensure_go.sh 2026-08-15 12:45:31 +12:00
git.go Share one ssh connection per host for fetches 2026-08-15 15:08:40 +12:00
go.mod Rewrite whatsdirty as a Go program 2026-08-15 11:52:04 +12:00
gp.go Rewrite whatsdirty as a Go program 2026-08-15 11:52:04 +12:00
install.sh Cross-platform portability: support macOS bash 3.2 and zsh 2026-06-13 21:17:08 +12:00
main.go Rewrite whatsdirty as a Go program 2026-08-15 11:52:04 +12:00
publish.sh Extract Go toolchain bootstrap into shared ensure_go.sh 2026-08-15 12:45:31 +12:00
README.md Share one ssh connection per host for fetches 2026-08-15 15:08:40 +12:00
report.go Split network and local git work with separate concurrency limits 2026-08-15 13:52:17 +12:00
scan.go Share one ssh connection per host for fetches 2026-08-15 15:08:40 +12:00
setup_script.sh Cross-platform portability: support macOS bash 3.2 and zsh 2026-06-13 21:17:08 +12:00
test.sh Extract Go toolchain bootstrap into shared ensure_go.sh 2026-08-15 12:45:31 +12:00
whatsdirty_test.go Share one ssh connection per host for fetches 2026-08-15 15:08:40 +12:00

whatsdirty

Simple tool to ease committing and pushing code changes across lots of repos.

Scans every git repository under a directory, fetches them (throttled per server), rebases the ones that are behind, and reports what is dirty, unpushed or stuck. Anything worth pushing is handed to gp, which commits, pushes and waits for CI.

whatsdirty <directory>    # scan, then hand dirty/unpushed repos to `gp -y`
whatsdirty -a <directory> # ask before including each repo
wd                        # shortcut for `whatsdirty -y`

The directory is remembered in ~/.config/whatsdirty.conf, so later runs need no argument.

Variable Default Effect
WHATSDIRTY_MAX_PER_SERVER 8 Concurrent fetches against any one host. Different servers are fetched in parallel.
WHATSDIRTY_SKIP_DIRS node_modules,vendor,target,.venv,__pycache__ Directories not descended into when looking for repos. Set it empty to scan everything.
WHATSDIRTY_SSH_MULTIPLEX on Share one ssh connection per host across all fetches. Set to 0 to disable. Ignored if you set your own GIT_SSH_COMMAND.

Connection sharing is where most of the scan time went: against a forge across the internet, the ssh handshake costs several times the git work it wraps. Note that sshd's MaxSessions (default 10) caps how many fetches can share one connection — which is why WHATSDIRTY_MAX_PER_SERVER defaults to 8. Raising it past that needs MaxSessions raised on the server, or multiplexing turned off; otherwise the server starts refusing sessions. A fetch that fails is retried once on its own connection, so a refusal recovers by itself.

Anything under a _deps directory is always skipped: build trees vendor whole checkouts there.

Ctrl-C cancels immediately, killing every in-flight git. If it interrupts a rebase, it names the repos left mid-flight — git rebase --abort restores them.

Building

Go, no dependencies outside the standard library.

./build.sh   # -> output/whatsdirty
./test.sh    # vet, unit tests, and CLI checks against a sandbox
./publish.sh # cross-build and publish linux+macos / amd64+arm64

test.sh runs against a throwaway HOME and repositories it creates itself. Don't point a scan at a directory you care about while testing: a real run saves over your saved directory and ends by committing and pushing every dirty repo it finds.