I keep a lot of repositories spread across organizations. When I need a
local copy of everything (backup, audit, offline work, whatever), I end
up writing one-off scripts that are boring, fragile, and always missing
the one repo I forgot about. So I wrote a tool to make this boring task
repeatable: gitgrab.
https://github.com/scottbrown/gitgrab
gitgrab does one thing: it grabs every repository from a GitHub
organization and puts them in a directory on disk. It talks to the
GitHub API, so it sees both public and private repos. When you run it
again, it doesn’t re-clone; it updates what you already have.
How it updates existing repos
This is the part I care about the most. If a repo already exists locally,
gitgrab checks your current branch:
- If you’re on the default branch (main/master), it runs
git pull. - If you’re on anything else, it runs
git fetch. - If it can’t figure out the branch, it falls back to
git fetch.
In other words, if you’re hacking on a feature branch, it won’t clobber your work. It just updates the remotes and leaves your branch alone.
Usage
Set a token and point it at a directory:
export GITHUB_TOKEN=your_github_token_here
gitgrab -o myorg ./repos
By default it uses SSH URLs. If you want HTTP instead:
gitgrab -o myorg -m http ./repos
SSH is my default because it doesn’t smear a token into your process list, and it works for public and private repos. HTTP is still handy if you’re on a fresh machine without SSH keys.
Why I built it
I want a clean, predictable way to mirror an org locally without
thinking too hard. gitgrab gives me a list of repos from the API, then
clones or updates each one and prints a simple progress line as it goes.
It’s boring on purpose, which is what I want from tooling like this.
If you run it once a week, you always have a fresh offline mirror. If you run it once a day, it’s a quick sync before you travel. Either way, it’s one command and done.