Find the git repositories on a machine that exist nowhere else.
A laptop accumulates repositories. Some are yours, most are not — vendored
dependencies, clones you made to read someone else's code, checkouts of things
you had forgotten. Of the ones that are yours, some are safely on a forge and
some only look that way. stray sorts that out and tells you what you would
lose if the disk died tonight.
A repository with a remote configured is not necessarily backed up.
$ git push
Everything up-to-dateThat message is about your local branches. It says nothing about
refs/remotes/* entries that have no local counterpart — branches you once
fetched, or that a git clone --mirror brought along, which now live only in
this copy. A plain git push never sends them. Neither does git push --all.
stray counts those separately, and treats a repository that has them as at
risk even when every branch you can see is pushed:
$ stray risk inventory.json
/Users/you/src/parser 3 orphan refs
/Users/you/work/scheduler remote gone, 2 unpushed
/Users/you/tmp/spike no remoteIt also checks whether the remote is still there at all — through the GitHub and
GitLab APIs, not git ls-remote. Over SSH an auth failure and a deleted
repository produce the same error, so ls-remote will report a perfectly
healthy repository as gone the moment your credentials expire. The APIs
distinguish 404 from 403.
$ go install github.com/robintemme/stray/cmd/stray@lateststray check shells out to gh and
glab and uses whatever credentials they
already hold. Everything else runs offline.
$ stray scan ~/ -o inventory.json
$ stray check inventory.json -o inventory.json
$ stray report inventory.json -o report.htmlExample summary (numbers are illustrative):
412 repositories under /Users/you
31 yours
9 at risk (gone remote, unpushed commits, or orphaned refs)
347 vendored dependencies
28 foreign clones
7 directories with code but no repository
report writes a single self-contained HTML page: what is at risk and why, last
commit per year, language mix.
Whatever matches -me, checked against remote URLs and commit author lines:
$ stray scan ~/ -me yourhandle -me yourcompany.exampleWith no -me, stray derives it from git config user.email. Everything else
is either vendored — it sits inside a dependency tree such as go/src,
node_modules or vendor — or foreign, someone else's repository you
cloned. Neither is your problem to back up.
$ stray scan ~/ -exclude /Volumes/timemachine -exclude .sparsebundleAnything matching an -exclude substring, by path or by remote URL, is recorded
as a name and a byte count and nothing more. Nothing below it is opened. Useful
for mounted backups, disk images, and network shares you would rather not have
a tool walk through.
-skip adds directory basenames to the built-in list of caches and build output
that is never descended into.
Sizes and modification times come from stat. The only file stray ever opens
inside a repository is .git/config, to learn the remote URLs; history comes
from git itself. It never reads your source, and it sends nothing anywhere —
check talks to the forges about repository names only.
MIT