Switch between multiple GitHub accounts (personal / work) with one command. gha use <name> updates:
- git: global
user.name,user.email, and commit signing (on/off per account) - ssh: which key
git@github.comuses, via a managed config file — so clone/push/pull just work - gh: the active GitHub CLI account (
gh auth switch)
From source:
cargo install --path .Or grab a prebuilt binary (macOS arm64/x86_64, Linux x86_64/arm64) from the
releases page.
Once installed, gha upgrade keeps it current.
gha add personal # interactive; offers to generate an ed25519 key
gha add work
gha use personal # switch everything to the personal account
gha use work # ...and backNon-interactive:
gha add work \
--git-name "Anes" \
--git-email anes@work.com \
--github-user anes-work \
--ssh-key ~/.ssh/id_ed25519_work \
--signing-format ssh| Command | What it does |
|---|---|
gha init |
Create ~/.config/gha/ and hook gha into ~/.ssh/config (idempotent; also runs on first use) |
gha add [name] |
Add an account; can generate a new SSH key and print the public key to paste into GitHub |
gha list |
List accounts, * marks the active one |
gha use <name> |
Switch the active account (--force to skip the key-exists check) |
gha current |
Print the active account, one line; exits 1 if none (shell-prompt friendly) |
gha status |
Verify actual git/ssh/gh state matches the active account; exits 1 on mismatch |
gha doctor |
Status + environment checks + live ssh -T git@github.com test, and verifies each account's SSH signing key is registered on GitHub as a signing key (auth keys alone leave commits "Unverified") |
gha edit <name> |
Edit fields (--rename to rename); offers to re-apply if the account is active |
gha remove <name> |
Remove an account (--yes to skip confirmation); never deletes key files |
gha link add <dir> <account> |
Pin a directory: every repo under it uses that account |
gha link remove <dir> |
Unpin a directory |
gha link list |
List linked directories |
gha upgrade |
Download and install the latest release (--check to only report) |
If your accounts are directory-shaped (everything under ~/Workspace/work is
work), pin the directory instead of switching manually:
gha link add ~/Workspace/work workEvery git repo under that directory now commits as work and pushes with
work's SSH key, no matter which account is active. Under the hood this uses
git conditional includes: ~/.gitconfig gets an
[includeIf "gitdir:~/Workspace/work/"] entry pointing at a managed fragment
(~/.config/gha/git/work.gitconfig) that sets user.name, user.email,
signing on/off, and core.sshCommand -i <work key>. Fragments are refreshed
automatically when you gha edit the account. Nested links work — the
innermost directory wins.
Scope: links cover everything git does — clone, push, pull, commit
identity, signing. The gh CLI is the exception: its auth is global and has
no per-directory mechanism, so gh pr/gh api keep using the active account
until you run gha use <name> or gh auth switch.
Caveats (git gitdir semantics): linked worktrees and submodules match by the
location of the main repo / superproject, not the checkout; symlinked paths
match as you type them (git does not resolve symlinks when matching), and
gha link add warns when that applies.
-
Accounts live in
~/.config/gha/config.toml(human-editable TOML). -
~/.ssh/configgets a single line added at the top, once:Include ~/.config/gha/ssh_config. -
On
gha use, gha rewrites only its own~/.config/gha/ssh_config:Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_gha_personal IdentitiesOnly yes AddKeysToAgent yes UseKeychain yesIdentitiesOnly yesis the important part — it stops ssh-agent from offering another account's key. -
Git config is applied via
git config --global; switching to a non-signing account explicitly setscommit.gpgsign falseso signing can't linger. -
gh auth switchfailures are warnings, never errors —gha usestill completes.
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --checkReleasing: bump version in Cargo.toml, tag the commit v<version>, push the tag.