Safe, script-first tooling to manage multiple GitHub accounts on one machine with separate SSH keys, host aliases, and dry-run defaults.
- Audits and backs up existing
~/.sshstate before changes. - Generates separate Ed25519 keys per account.
- Adds keys to
ssh-agentand macOS keychain. - Optionally uploads keys through
ghafter explicit confirmation. - Writes a managed block in
~/.ssh/configwith account aliases. - Validates aliases using
ssh -T git@<alias>. - Updates existing repo remotes with a safe dry-run workflow.
scripts/setup.sh: Main idempotent setup flow.scripts/update-remotes.sh: Convert remotes to alias-based SSH URLs.scripts/backup-keys.sh: Back up SSH files.scripts/generate-key.sh: Standalone key creation helper.scripts/generate-gh-actions-key.sh: Optional CI key helper.examples/owner-map.conf.example: Owner-to-alias mapping example.examples/gitconfig-includeIf.example: Git identity routing example.docs/audit-and-verify.md: Manual audit and verification steps.tests/lint.sh: Shell lint script.
- macOS with OpenSSH
- Bash (macOS default Bash 3.2 is supported)
git- Optional:
gh(GitHub CLI) for key upload - Optional:
shellcheckfor lint checks
- Preview everything and make no changes:
scripts/setup.sh --dry-run- Set up or refresh SSH aliases/keys for personal + work:
scripts/setup.sh --apply- Update existing repo remotes to alias-based SSH hosts:
scripts/update-remotes.sh --root "$HOME/code" --map ~/.ssh/owner-map.conf --dry-run
scripts/update-remotes.sh --root "$HOME/code" --map ~/.ssh/owner-map.conf --apply- Only create a backup snapshot of current SSH files:
scripts/backup-keys.sh --apply- Only create one key manually:
scripts/generate-key.sh --email "you@example.com" --name "id_ed25519_example" --apply- It does not delete local SSH keys.
- It does not revoke/remove keys from GitHub automatically.
- It does not change git remotes (that is
scripts/update-remotes.sh). - It only generates a key when the target key filename does not already exist.
- It writes only a managed block in
~/.ssh/config; it does not wipe the file.
chmod +x scripts/*.sh tests/lint.sh
scripts/setup.sh --dry-run
scripts/setup.sh --apply--apply behavior summary:
- Backs up existing
~/.sshfiles first (with confirmation). - Reuses existing key files if present; otherwise generates new ones.
- Adds keys to
ssh-agent/keychain. - Optionally uploads public keys via
ghafter confirmation. - Adds/updates a managed alias block in
~/.ssh/config.
Interactive defaults:
- accounts:
personal,work - key names:
id_ed25519_personal,id_ed25519_work - aliases:
github-personal,github-work
Explicit example:
scripts/setup.sh --apply \
--accounts "personal,work" \
--email-personal "you@personal.email" \
--email-work "you@work.email"Non-interactive example:
scripts/setup.sh --apply --yes \
--accounts "personal,work" \
--email-personal "you@personal.email" \
--email-work "you@work.email" \
--key-personal "id_ed25519_personal" \
--key-work "id_ed25519_work" \
--alias-personal "github-personal" \
--alias-work "github-work"Dry-run by default:
scripts/update-remotes.sh --root "$HOME/code" --map examples/owner-map.conf.example --dry-runApply changes (with confirmation):
scripts/update-remotes.sh --root "$HOME/code" --map ~/.ssh/owner-map.conf --applyAudit:
ls -la ~/.ssh
ls -1 ~/.ssh/*.pub 2>/dev/null || echo "no .pub files found"
ssh-add -l || echo "no keys loaded"
gh ssh-key listBackup:
mkdir -p ~/ssh-backups
cp -v ~/.ssh/id_* ~/ssh-backups/ 2>/dev/null || echo "copied any id_* keys"
ls -la ~/ssh-backupsGenerate keys:
ssh-keygen -t ed25519 -C "you@personal.email" -f ~/.ssh/id_ed25519_personal
ssh-keygen -t ed25519 -C "you@work.email" -f ~/.ssh/id_ed25519_workAdd to agent/keychain:
eval "$(ssh-agent -s)"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_personal
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_work
ssh-add -lUpload with gh (optional):
gh auth login
gh ssh-key add ~/.ssh/id_ed25519_personal.pub --title "MacBook Personal $(date +%F)"
gh auth login
gh ssh-key add ~/.ssh/id_ed25519_work.pub --title "MacBook Work $(date +%F)"Use aliases in remotes:
git remote set-url origin git@github-personal:your-personal-username/repo.git
git remote set-url origin git@github-work:your-work-username/repo.gitValidate:
ssh -T git@github-personal
ssh -T git@github-work
ssh -vT git@github-personal 2>&1 | sed -n '1,200p'- Never delete keys silently.
- Keep backups until all fetch/push checks are successful.
update-remotes.shis dry-run by default and confirms before apply.setup.shprompts before risky operations unless--yesis used.
-
ssh -T git@github-personalauthenticates to the personal username. -
ssh -T git@github-workauthenticates to the work username. - Critical repositories can fetch and push.
-
gh ssh-key listreflects intended keys. - Backups exist under
~/ssh-backups/<timestamp>.
Only remove old keys after successful verification across all repos. Prefer staged cleanup and revoke old keys in GitHub first.