Skip to content

yanptrv/gclean

Repository files navigation

gclean

ci release license

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/main off master/main
clean selectable (gets a pull) listed + selectable
dirty listed as FYI listed, 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

key action
/, k/j move cursor (wraps around)
199 toggle row by number — multi-digit numbers buffer for 200ms
space toggle row under cursor
a toggle all
i invert selection
esc clear selection
enter confirm and update
q / ctrl+c quit without touching anything

Exit codes

code meaning
0 everything updated, or nothing to do
1 a 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

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors