Skip to content

Repository files navigation

gclean

cireleaselicense

Interactive multi-repo git cleaner. Scans a directory of git repos, shows which ones drifted off master/main or have uncommitted changes, then lets you pick the clean ones to reset back to the default branch — fetch, checkout, fast-forward — all in parallel, with live per-repo progress.

demo

Install

brew install yanptrv/tap/gclean

or with Go:

go install github.com/yanptrv/gclean@latest

or grab a binary from releases.

Usage

gclean # scan repos in the current directory
gclean ~/work # scan a specific directory
gclean -y # non-interactive: update every clean repo

Run it inside a git repo and it skips the picker entirely — if the repo is clean it resets it to the default branch immediately; if it's dirty it tells you and exits.

What counts as what

on master/mainoff master/main
cleanselectable (gets a pull)listed + selectable
dirtylisted as FYIlisted, never touched

Dirty repos are never modified. Updates use merge --ff-only, so a diverged local default branch fails loudly instead of silently merging.

Repos whose default branch is behind the last-fetched origin ref show a ↓N marker in the listing and picker. Note this reflects your last fetch/pull/push of that branch, not the remote's live state — a repo without the marker may still pull new commits.

Authentication

gclean shells out to your real git, so it works with whatever auth your repos already use — SSH keys/agent or HTTPS credential helpers. It never prompts: interactive prompts can't work with 8 parallel fetches, so they're disabled and surface as ✗ failed instead. New SSH host keys are auto-accepted (accept-new); changed host keys still fail hard. If a repo fails with a permission error, set up ssh-add --apple-use-keychain (SSH) or gh auth setup-git (HTTPS) once and rerun.

Keys

keyaction
/, k/jmove cursor (wraps around)
199toggle row by number — multi-digit numbers buffer for 200ms
spacetoggle row under cursor
atoggle all
iinvert selection
escclear selection
enterconfirm and update
q / ctrl+cquit without touching anything

Exit codes

codemeaning
0everything updated, or nothing to do
1a repo failed to update, or the single target repo is dirty

How it works

  • repos are scanned concurrently (git status is the slow part; scans run on all cores) and sorted by most recent commit
  • the default branch is resolved from origin/HEAD, falling back to master/main
  • updates run up to 8 repos in parallel: fetch origincheckout <default>merge --ff-only origin/<default>, each with a live status row
  • built with bubbletea

Development

make build # build ./gclean
make test# run tests
make lint # go vet
make install # install to ~/.local/bin

Releasing

Releases are automated with goreleaser: push a v* tag and CI builds darwin/linux binaries for amd64/arm64, creates the GitHub release, and updates the Homebrew formula in yanptrv/homebrew-tap.

One-time setup: create the homebrew-tap repo and add a HOMEBREW_TAP_TOKEN repo secret (a fine-grained PAT with write access to the tap repo).

License

MIT

About

Interactive multi-repo git cleaner

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages