Guide

The developer checklist before you wipe or switch Macs

Time Machine does not know which branch you never pushed. Run these checks over every repository, then over the files Git never saw, before you erase anything.

Time Machine does not know which branch you never pushed. Run these checks over every repository, then over the files Git never saw, before you erase anything.

Time Machine does not know which branch you never pushed. Run these checks over every repository, then over the files Git never saw, before you erase anything.

What is only on this Mac

A fresh macOS install or a new machine is cheap to set up and expensive to get wrong once. The things that hurt are not the ones you remember, they are the ones that exist in exactly one place:

  • Uncommitted changes in a repository you have not opened for a month.

  • A branch you committed to and never pushed.

  • A branch whose remote branch was deleted after a merge, with newer local commits on top.

  • Stashes, which live only in the checkout that made them.

  • Repositories with no remote at all: the experiment, the script folder, the git init you did to get diffs.

  • Files Git never tracked: .env, private keys, local databases, certificates.

The checklist below goes through each.

One shell loop for every repository

First, find every repository. Most developers keep them under a handful of folders. This finds .git directories up to four levels deep under the usual places and prints the repository path:

find ~/Developer ~/Code ~/Projects ~/Documents/GitHub -maxdepth 5 -type d -name .git 2>/dev/null \ | sed 's#/\.git$##'

Add your own folders to that list. Then run the checks in each one. Save this as sweep.sh or paste it as is:

for repo in $(find ~/Developer ~/Code ~/Projects ~/Documents/GitHub -maxdepth 5 -type d -name .git 2>/dev/null | sed 's#/\.git$##'); do cd "$repo" || continue dirty=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ') unpushed=$(git log --branches --not --remotes --oneline 2>/dev/null | wc -l | tr -d ' ') stashes=$(git stash list 2>/dev/null | wc -l | tr -d ' ') remotes=$(git remote 2>/dev/null | wc -l | tr -d ' ') if [ "$dirty" != 0 ] || [ "$unpushed" != 0 ] || [ "$stashes" != 0 ] || [ "$remotes" = 0 ]; then echo "$repo: $dirty changed, $unpushed unpushed commits, $stashes stashes, $remotes remotes" fi done

Each line is a repository that still has something only on this Mac. The four counts come from:

  • git status --porcelain lists modified, staged, and untracked files, one per line.

  • git log --branches --not --remotes lists commits reachable from any local branch but from no remote-tracking branch. This catches unpushed commits on every branch at once, not only the one checked out.

  • git stash list is the stash stack.

  • git remote with no output means there is nowhere to push to.

Stashes, local-only branches, repos with no remote

The loop tells you where to look. In each flagged repository, see what exactly is local:

git status --short git log --branches --not --remotes --format='%h %D %s' git stash list --date=local git for-each-ref --format='%(refname:short) %(upstream:short) %(upstream:track)' refs/heads

The last command prints every local branch with its upstream and how far ahead it is. A branch with an empty upstream column was never pushed. One marked [gone] had an upstream that no longer exists: if it also shows commits in the --not --remotes log, those commits exist nowhere else.

Then act, repository by repository, with normal Git:

  • Commit or stash the dirty files, or discard them on purpose with git checkout -- . after reading the diff.

  • Push every branch that matters: git push -u origin <branch>. For a repository with no remote, create one and push, or decide out loud that it can go.

  • Stashes do not push. Apply the ones you want and commit them, or write them off: git stash show -p stash@{0} shows what one holds.

Run the loop again until it prints nothing.

Not in Git: keys, .env files, local data

Git is only half of it. Walk this list before you erase:

  • SSH and GPG keys. ls ~/.ssh and gpg --list-secret-keys. Generate new ones on the new Mac and add them to GitHub, servers, and so on, or move the private keys deliberately over an encrypted channel. Never leave them in a plain backup.

  • .env and credential files inside projects. They are usually ignored by Git, so a clone will not bring them back. find ~/Developer -name '.env*' -not -path '*/node_modules/*' lists them. Copy the values into a password manager or a vault, not into another loose file.

  • Local databases and data. Postgres and MySQL data directories, SQLite files in project folders, Docker volumes (docker volume ls). Dump what you need: pg_dumpall, mysqldump, or a copy of the SQLite file.

  • Certificates and signing identities. Apple developer certificates live in the Keychain. Xcode > Settings > Accounts > Manage Certificates can export them, and Keychain Access can export a .p12.

  • Tool configuration. ~/.zshrc, ~/.gitconfig, ~/.config, editor settings, and the global ignore file. A dotfiles repository is the easy answer.

  • Licenses and tokens in ~/.npmrc, ~/.netrc, ~/.pypirc, and the like.

A Time Machine backup covers all of this as files, but it does not tell you what was important. The point of the list is to know.

Doing this in Room Service

Room Service’s Git Sweep does the loop above for you and shows the result per project. It finds repositories under the folders developers actually use, up to four levels deep, and for each one reports uncommitted changes, conflicted and untracked files, branches ahead of their upstream, branches with no upstream, branches whose upstream is gone, stash entries with the date of the oldest, and repositories with no remote. Projects carrying local-only work are marked in the list, and Home and the menu bar count them.

The sweep is read-only by design. It reads HEAD, remotes, and the stash log from .git, runs git with --no-optional-locks and core.fsmonitor disabled, and never commits, pushes, or drops a stash. The only action on a finding is Open in Terminal.

From the terminal, roomservice sweep ~/Code prints the same report, and --exit-code exits with status 2 when anything is still local, so a wipe script can refuse to continue:

roomservice sweep ~/Code --exit-code >/dev/null [ $? -eq 2 ] && echo "push before you go"

Project Health, in the same workspace, lists credential files such as .env and .pem inside each project, so the second half of the checklist is visible too. roomservice sweep and the git_sweep MCP tool are free. The Projects workspace with the per-project detail is Pro.

Related

Frequently Asked Questions

How do I find unpushed commits across all my repositories?

Do stashes get pushed?

How do I find Git repos that have no remote?

Will a Time Machine backup keep my unpushed branches?

Does Room Service push or commit for me?

Can I run the check from a script before wiping?

More guides