GIT MULTI-ACCOUNT
PERSONAL MANUAL
Managing two GitHub accounts on macOS without the headache. Authentication, authorship, and the full setup, in one place.
The Mental Model
Two things are configured independently for every git operation:
- Authentication — who is allowed to push, decided by the SSH key that loads based on the remote URL's host alias.
- Authorship — whose name appears on the commit, decided by
user.emailset inside the repo.
These two should always match, but git won't enforce that. The setup here makes them behave like one decision, so mistakes are hard to make.
The two SSH host aliases
Instead of using github.com directly, use one of these aliases as the host in remote URLs:
github.com-rehanamd— routes to REHANAMD's keygithub.com-1803— routes to rehanahmed1803's key
Both resolve to github.com, but each loads a different SSH key, telling GitHub which account is acting.
Daily Workflow
Cloning an existing repo
Decide which account owns the repo, then clone with the matching alias.
REHANAMD repo:
git clone git@github.com-rehanamd:REHANAMD/repo-name.git cd repo-name git config user.email "somanirehan8@gmail.com"
rehanahmed1803 repo:
git clone git@github.com-1803:rehanahmed1803/repo-name.git cd repo-name git config user.email "rehanamesomani@gmail.com"
user.name can be skipped — GitHub identifies commits by email only. But setting it makes git log cleaner, so it's a good habit.
Starting a new local project and pushing it
- Create the repo on github.com first (logged in as the right account). Don't initialize with a README.
- Then locally:
mkdir my-project && cd my-project git init git config user.email "somanirehan8@gmail.com" echo "# my-project" > README.md git add . git commit -m "initial commit" git branch -M main git remote add origin git@github.com-rehanamd:REHANAMD/my-project.git git push -u origin main
For an rehanahmed1803 project, swap the email and the remote URL:
git config user.email "rehanamesomani@gmail.com" git remote add origin git@github.com-1803:rehanahmed1803/my-project.git
Switching an existing repo to the right account
If a repo's remote was set up the old way (HTTPS or wrong alias), reconfigure it:
# Check current remote git remote -v # Switch to the right alias git remote set-url origin git@github.com-1803:rehanahmed1803/repo.git # Set the right author identity git config user.email "rehanamesomani@gmail.com" # Verify git remote -v git config --list | grep user
Routine commands (no surprises)
Once a repo is set up correctly, the everyday flow is normal git:
git status # see what changed git add . # stage everything git add file.cpp # stage one file git commit -m "message" # commit git push # push (origin and branch already tracked) git pull # fetch + merge git log --oneline -10 # last 10 commits, one line each git diff # unstaged changes git diff --staged # staged changes
Branching basics
git branch # list branches git branch new-feature # create branch git checkout new-feature # switch to it git checkout -b new-feature # create + switch in one command git merge feature-branch # merge into current branch git branch -d old-branch # delete a merged branch git push -u origin new-branch # push new branch and track it
Undoing things
git restore file.cpp # discard unstaged changes git restore --staged file.cpp # unstage a file (keep changes) git commit --amend -m "new message" # change last commit message git reset --soft HEAD~1 # undo last commit, keep changes staged git reset --hard HEAD~1 # NUKE last commit and changes
git reset --hard is irreversible. Use it only when you're sure. If something goes wrong, git reflog can sometimes recover lost commits within a few weeks.
The .gitignore Pattern
How gitignore actually works
A .gitignore file only prevents untracked files from being added. If a file is already tracked, gitignore is silently ignored for it. To untrack an already-tracked file:
git rm --cached path/to/file # untrack but keep on disk git rm -r --cached path/to/folder/ # untrack a folder
Then commit the change.
Recommended .gitignore for C++ projects
# Compiled binaries *.out *.exe *.o *.obj *.class # Build folder (preferred convention) bin/ build/ # IDE / editor noise .vscode/ .idea/ *.swp .DS_Store
The bin/ folder convention
Compile binaries into a dedicated folder so a single line in .gitignore ignores them all:
mkdir bin g++ source.cpp -o bin/source ./bin/source
Cleanup, Diagnostics, and Recovery
Verifying which account is in use
ssh -T git@github.com-rehanamd # expect: Hi REHANAMD! ssh -T git@github.com-1803 # expect: Hi rehanahmed1803! git remote -v # check remote URL git config --list | grep user # check current author identity
If a push fails with 403 or "Permission denied"
- Run
git remote -v. Confirm the URL uses the right alias (github.com-rehanamdorgithub.com-1803), not plaingithub.com. - Run the
ssh -Ttest for that alias. If it greets the wrong username, the SSH config is misconfigured. - Check for stale credentials cached in macOS Keychain:
security find-internet-password -s github.com security delete-internet-password -s github.com
Fixing wrong-author commits
If commits were already made with the wrong author email, two options:
- Leave them alone. If the repo isn't on the resume account, this has no practical impact. Recommended for personal/experimental repos.
- Rewrite history. Risky if anyone else has cloned the repo. Solo personal repos only, with a backup branch first.
# Always backup first git branch backup-before-rewrite # Rewrite (install via: brew install git-filter-repo) git filter-repo --commit-callback ' if commit.author_email == b"old@email.com": commit.author_email = b"new@email.com" commit.author_name = b"NewName" ' # Force push (destructive) git push --force-with-lease
Stashing work in progress
git stash # save changes, clean working tree git stash list # see saved stashes git stash pop # restore most recent and remove from stash git stash apply # restore but keep in stash git stash drop # delete most recent stash
Setup on a New Mac
Full one-time setup to repeat the multi-account configuration on a fresh machine. Total time: about 10 minutes.
-
Install git
bash
git --version
If macOS prompts to install Command Line Tools, accept. Otherwise:
brew install git -
Generate two SSH keys
bash
ssh-keygen -t ed25519 -C "somanirehan8@gmail.com" -f ~/.ssh/id_ed25519_rehanamd ssh-keygen -t ed25519 -C "rehanamesomani@gmail.com" -f ~/.ssh/id_ed25519_rehanahmed1803
Press Enter twice at each passphrase prompt (or set one if preferred).
-
Add public keys to GitHub
For REHANAMD — copy key, sign in as REHANAMD, Settings → SSH and GPG keys → New SSH key → paste:
bashpbcopy < ~/.ssh/id_ed25519_rehanamd.pub
For rehanahmed1803 — sign out, sign in as rehanahmed1803, repeat:
bashpbcopy < ~/.ssh/id_ed25519_rehanahmed1803.pub
-
Configure SSH host aliases
bash
nano ~/.ssh/config
Paste this into the file:
~/.ssh/configHost github.com-rehanamd HostName github.com User git IdentityFile ~/.ssh/id_ed25519_rehanamd IdentitiesOnly yes Host github.com-1803 HostName github.com User git IdentityFile ~/.ssh/id_ed25519_rehanahmed1803 IdentitiesOnly yes
Save (Ctrl+O, Enter, Ctrl+X). Then secure the file:
bashchmod 600 ~/.ssh/config
-
Test both keys
bash
ssh -T git@github.com-rehanamd # expect: Hi REHANAMD! ssh -T git@github.com-1803 # expect: Hi rehanahmed1803!
If prompted to confirm host authenticity, type
yes. -
Unset any global identity
bash
git config --global --unset user.name || true git config --global --unset user.email || true
This forces every repo to set its own identity, eliminating wrong-author mistakes.
-
Clean any cached HTTPS credentials
bash
security delete-internet-password -s github.com
Run repeatedly until it reports nothing to delete.
Quick-Reference Cheat Sheet
Remote URL formats
# REHANAMD git@github.com-rehanamd:REHANAMD/<repo>.git # rehanahmed1803 git@github.com-1803:rehanahmed1803/<repo>.git
Per-repo identity
# REHANAMD git config user.email "somanirehan8@gmail.com" git config user.name "REHANAMD" # rehanahmed1803 git config user.email "rehanamesomani@gmail.com" git config user.name "rehanahmed1803"
Most-used commands
git status git add . && git commit -m "msg" && git push git pull git checkout -b new-branch git log --oneline --graph --all -20 git stash / git stash pop git remote -v