How to Use Multiple GitHub Accounts on One Machine
A complete walkthrough of the git-multiple-accounts script - SSH keys, per-identity commits, automatic signing, and a smart clone wrapper so you never push to the wrong account.
If you have a personal GitHub account and a work one (or a client one, or a side-project one), you have probably run into this problem: you clone a work repo, make a commit, push it, and GitHub shows it as coming from your personal account. Or worse - a commit shows Unknown because git had no identity configured at all.
This guide fixes that permanently. After running the setup script and following the steps below, every commit you make will automatically use the right name, email, and verified signature for whichever account it belongs to - with zero manual switching, ever.
What Problem This Solves
Git has one global identity by default: one name, one email, one SSH key. When you have two GitHub accounts, that single identity cannot represent both. The common workarounds - manually running git config user.email in each repo, or keeping a notepad of which key belongs to which account - are error-prone and tedious.
This setup replaces all of that with three things:
- Named SSH keys: each account gets its own key file with a clear name (
id_ed25519_personal,id_ed25519_work). - SSH aliases: each key gets a named host alias in
~/.ssh/configso git knows which key to use for which account. - Automatic identity detection: a global
pre-commithook reads the remote URL, matches the SSH alias, and sets the correct name and email in that repo before the commit lands. You only see this once per repo. After that it's silent.
Before You Start
You need:
- A terminal: on Linux, open Terminal from your applications menu. On macOS, open Terminal from Applications > Utilities.
- Your GitHub accounts open in a browser: you'll need to paste SSH keys into each account's settings page during setup. Have them ready.
- An internet connection.
You do not need Git pre-installed. Phase 1 of the script checks whether Git is already on your machine. If it is, it upgrades it. If it is not, it installs it for you automatically - on Linux via apt-get, on macOS via Homebrew (which it will also install if missing). You can run this script on a completely fresh machine.
If you already ran the dev-setup.sh script from this site, Git is already installed and your first account may already be configured. The multi-account script detects existing profiles and lets you keep, rename, or build on them - nothing gets overwritten without your confirmation.
How to Run the Script
curl -fsSL https://shogo-portfolio-ebon.vercel.app/scripts/git-multiple-accounts.sh | bash
To inspect it before running:
curl -o git-multiple-accounts.sh https://shogo-portfolio-ebon.vercel.app/scripts/git-multiple-accounts.sh
cat git-multiple-accounts.sh
bash git-multiple-accounts.sh
The script runs six phases. Each one pauses and asks whether to run it or skip it. You can skip any phase you don't need.
Walking Through the Script Phase by Phase
Phase 1 - Git check
The script checks whether git is installed and up to date. If it's missing, it installs it. If it's already there, it upgrades it quietly.
Nothing interactive here - just run it.
Phase 2 - Identity setup (the most important phase)
This is where you configure your accounts. The script:
- Detects any existing profiles from a previous run and shows them to you.
- Lets you rename existing profiles if you want.
- Asks how many new accounts you want to add.
- Collects a short alias, full name, GitHub username, and email address for each new account.
- Generates a unique SSH key for each account.
- Adds each key's SSH config block to
~/.ssh/config. - Displays the public key and walks you step by step through adding it to GitHub.
- Tests the connection before moving on.
- Writes a per-profile gitconfig file (
~/.gitconfig-personal,~/.gitconfig-work, etc.). - Asks which profile should be the global default.
What to enter when prompted:
- Alias: a short label for this account. Use something like
personal,work,client, orgym. No spaces. This becomes the SSH host alias (github-personal) and the gitconfig filename (~/.gitconfig-personal). - Full name: the name that appears on your commits. This is what GitHub shows next to your commits.
- GitHub username: your exact GitHub username (e.g.
Olorunshogo, not the email). The script uses this only to label things clearly - it's not used for authentication. - Email: the email address registered on that GitHub account. This must match GitHub's record or your commits won't link to that account's profile correctly.
Adding the SSH key to GitHub:
When the script displays your public key, it looks like a long block of text starting with ssh-ed25519. Copy the entire thing - the easiest way is to triple-click to select the whole line, then copy.
The script walks you through adding it twice to GitHub - once as an authentication key, once as a signing key. Both use the same key.
Authentication Key (allows pushing and pulling):
- Go to
github.com/settings/keyswhile logged in as that account. - Click "New SSH key".
- Give it a title like
laptop - personal. - Set the type to "Authentication Key".
- Paste the public key and click "Add SSH key".
Signing Key (makes commits show "Verified" on GitHub):
- Click "New SSH key" again on the same page.
- Use the same title, or append
signingto it. - Set the type to "Signing Key".
- Paste the same public key again and click "Add SSH key".
Once both are added, type done in the terminal and press Enter. The script tests the connection automatically.
Choosing the global default:
At the end of Phase 2, the script asks which profile should be the default for any repo that has no identity set yet. Pick your most-used account. This sets the global user.name and user.email in ~/.gitconfig. Any repo that slips through the automatic detection system will still commit under a known identity.
Phase 3 - Hook system and shell helpers
This phase installs two things:
Global git hooks (written to ~/.git-hooks/):
pre-commit: fires before every commit in every repo on your machine. It checks whether the current repo has a local identity set. If not, it reads the remote URL, extracts the SSH alias, looks it up in~/.gitidentities, and setsuser.name,user.email, and the signing key for that repo. This runs once per repo and never prompts again.pre-push: fires before every push. It prints one line:Pushing to origin as: Your Name <email>. Nothing else. Just so you always know which identity is pushing without having to think about it.
Shell functions (added to ~/.bashrc or ~/.zshrc):
gclone: a smartgit clonereplacement (see below).gitprofile: lists your configured profiles, or switches identity for the current shell session.
After this phase runs, restart your terminal for gclone and gitprofile to become available.
Phase 4 - Git globals
Applies a full set of sensible git settings:
pull.rebase = true Never creates accidental merge commits on pull
rebase.autoStash = true Stashes uncommitted work before rebase, restores after
push.default = current Pushes the current branch without having to specify it
push.autoSetupRemote = true Sets upstream tracking automatically on first push
fetch.prune = true Removes stale remote-tracking branches automatically
rerere.enabled = true Remembers how you resolved a conflict and replays it
merge.conflictstyle = diff3 Shows the original code alongside both conflicting versions
Also adds aliases:
git lg Visual branch graph with one commit per line
git ll Compact log with relative dates
git st Short status with branch name
git co Shorthand for checkout
git br Branches sorted by most recent activity
git undo Undoes the last commit but keeps the changes
git wip Stages everything and commits with message "wip"
git whoami Prints the name and email configured for the current repo
Phase 5 - Global config files
Writes ~/.vscode/settings.json, ~/.prettierrc, ~/.solhint.json, ~/.lintstagedrc.json, and ~/.gitignore_global. These are the same config files from the dev-setup.sh script. If you already ran that script, you can skip this phase.
Phase 6 - Summary
Prints a full summary of every profile configured, which one is the global default, and the quick-reference usage guide.
How to Clone a Repo After Setup
Instead of git clone, use gclone:
gclone https://github.com/musathedev/my-repo.git
A numbered menu appears:
Clone as which identity?
[1] Musa The Dev <musa@email.com> (github-personal)
[2] Moses Bamtefa <moses@work.com> (github-work)
Choose [1-2]:
Pick a number. The script rewrites the URL from https://github.com/musathedev/my-repo.git to github-personal:musathedev/my-repo.git, using the SSH alias instead of the HTTPS URL. That alias is now permanently baked into .git/config for that repo. Every future git push from that repo automatically uses the right SSH key. You never choose again.
gclone works with both https://github.com/ and git@github.com: URLs. For non-GitHub hosts it clones as-is and lets the pre-commit hook handle identity on first commit.
How Identity Gets Set on First Commit
When you commit in a repo that was cloned with gclone, the pre-commit hook sees the SSH alias in the remote URL and automatically sets:
git config --local user.namegit config --local user.emailgit config --local user.signingkeygit config --local commit.gpgsign true
You see this once:
Identity set: Musa The Dev <musa@email.com> (github-personal)
After that the hook exits silently on every subsequent commit in that repo. The local config is permanent.
What if the hook cannot detect the identity? If the repo was cloned over HTTPS without gclone, the hook has no SSH alias to read. In that case it shows the same numbered list and asks you to pick once. Same result - identity set locally, never asks again.
Switching Identity Manually
For repos that existed before you ran this setup, or when you need to temporarily override:
gitprofile personal # activates personal identity for the current shell session
gitprofile # lists all profiles and shows which is currently active
Note: gitprofile sets environment variables (GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, etc.) for the current terminal session only. It does not change ~/.gitconfig. Close the terminal and those variables are gone. For a permanent per-repo change, use git config --local user.name "..." instead.
Checking Who Will Commit
At any point you can run:
git whoami
This prints the name and email that git will use for the next commit in the current repo. Use this before committing if you are ever unsure.
Managing Profiles Later
All your identities live in one file: ~/.gitidentities. Each line is:
github-personal|Musa The Dev|musa@email.com
github-work|Moses Bamtefa|moses@work.com
To add a profile manually, append a line in that format. To remove one, delete its line. The hook system, gclone, and gitprofile all read from this file.
To rename a profile, change the alias part of its line and update the matching files:
~/.gitconfig-<old-alias>: rename to~/.gitconfig-<new-alias>~/.ssh/id_ed25519_<old-alias>: rename both the key and the.pubfile~/.ssh/config: update theHost github-<old-alias>block
Re-running the script on the same machine handles all of this interactively.
Verifying Signed Commits on GitHub
After pushing a commit, open it on GitHub. Next to the commit message you should see a green "Verified" badge. Click it to see which key signed the commit.
If the badge shows "Unverified":
- The signing key was not added to GitHub as a Signing Key (only as Auth Key). Go to
github.com/settings/keysand add it again with type "Signing Key". - Or the commit was made before this setup was complete. Old commits cannot be retroactively signed.
What Gets Created on Your Machine
After running the full setup, these files exist:
~/.gitidentities identity map (one line per account)
~/.gitconfig-personal per-profile gitconfig (name, email, signing key)
~/.gitconfig-work per-profile gitconfig
~/.ssh/id_ed25519_personal private SSH key (never share this)
~/.ssh/id_ed25519_personal.pub public SSH key (this goes on GitHub)
~/.ssh/id_ed25519_work
~/.ssh/id_ed25519_work.pub
~/.ssh/config SSH alias config blocks
~/.git-hooks/pre-commit global pre-commit hook
~/.git-hooks/pre-push global pre-push hook
And in your shell RC (~/.bashrc or ~/.zshrc):
gclone() # smart clone wrapper
gitprofile() # manual identity switcher
Troubleshooting
gclone: command not found
The shell function was not sourced yet. Restart your terminal. If it still doesn't work, check that the function was added:
grep -n "gclone" ~/.bashrc # Linux
grep -n "gclone" ~/.zshrc # macOS
If it's missing, re-run Phase 3.
Permission denied (publickey) when pushing
The SSH key is not registered on that GitHub account, or the wrong key is being used. Test the specific alias:
ssh -T git@github-personal
You should see: Hi <username>! You've successfully authenticated...
If not, go to github.com/settings/keys, check whether the key for that account is listed, and add it if missing.
The pre-commit hook is not firing
Check that the global hooks path is set:
git config --global core.hooksPath
It should print ~/.git-hooks or the full path. If it's empty, run:
git config --global core.hooksPath "$HOME/.git-hooks"
I committed to the wrong account
If you haven't pushed yet, you can amend the commit after switching identity:
gitprofile personal
git commit --amend --reset-author --no-edit
If you have pushed, the commit is on the remote. You can force-push a corrected commit if the branch allows it, but this rewrites history - coordinate with anyone else on the branch first.
My commit shows "Unverified" but I did everything
Make sure you added the SSH key as a Signing Key (not just Authentication Key) on that GitHub account. These are two separate entries in GitHub's key settings.