One-Key-per-Repo: A Simple Workflow for Managing Multiple Git Accounts

Ever juggled code across personal, work, and side-project accounts only to push with the wrong credentials? In this post you’ll build a two-script toolkit that solves the problem:
generate_ssh_key.sh
– creates a fresh SSH key and drops a ready-to-paste stanza into~/.ssh/config
.checkout
– rewrites any Git URL sogit clone
automatically uses the right key for that host.
Along the way you’ll:
- Organize your scripts in a dedicated directory
- Add that directory to
PATH
- Test the flow end-to-end
Why bother with per-repo keys?
- Security – revoke a single key without touching other repos.
- Separation of concerns – clean audit trails for each Git hosting account.
- Convenience – eliminate
GIT_SSH_COMMAND
hacks or accidental pushes with the wrong identity.
Project layout
~/Development/personal/innovate-hub/tools/scripts/
│
├── generate_ssh_key.sh # script 1
└── checkout # script 2 (no .sh for nicer UX)
Make sure the directory exists:
mkdir -p ~/Development/personal/innovate-hub/tools/scripts
Script 1 – generate_ssh_key.sh
#!/usr/bin/env bash
# Usage: generate_ssh_key.sh <key-name>
set -euo pipefail
if [[ -z "${1-}" ]]; then
echo "Usage: $0 <key_name>"; exit 1
fi
KEY_NAME="$1"
SSH_DIR="$HOME/.ssh"
KEY_PATH="$SSH_DIR/id_rsa_${KEY_NAME}"
if [[ -f "$KEY_PATH" ]]; then
echo "Key ${KEY_NAME} already exists at ${KEY_PATH}"; exit 1
fi
mkdir -p "$SSH_DIR" && chmod 700 "$SSH_DIR"
ssh-keygen -t rsa -b 4096 -f "${KEY_PATH}" -N "" -C "${KEY_NAME}@$(hostname)"
cat <<EOF
# ─── Add this to ~/.ssh/config ────────────────────────────────────────────────
Host ${KEY_NAME}
HostName github.com # or gitlab.com, bitbucket.org, etc.
User git
IdentityFile ${KEY_PATH}
IdentitiesOnly yes
# ──────────────────────────────────────────────────────────────────────────────
Public key (paste into your Git provider):
$(cat "${KEY_PATH}.pub")
EOF
What it does
- Bails if no key name is provided.
- Generates
id_rsa_<key>
with a 4096-bit key size. - Prints a ready-made
Host
block so you never mistype paths inssh_config
.
Script 2 – checkout
#!/usr/bin/env bash
# Usage: checkout <git-url>
# Example: checkout https://github.com/kiarash/my-repo.git
# checkout git@gitlab.com:kiarash/secret.git
set -euo pipefail
URL="${1-}"
[[ -z "$URL" ]] && { echo "Usage: $0 <git-url>"; exit 1; }
CONFIG="$HOME/.ssh/config"
# Extract hostname and repo path
if [[ "$URL" =~ ^git@([^:]+):(.+)$ ]]; then
HOST="${BASH_REMATCH[1]}"
PATH_PART="${BASH_REMATCH[2]}"
elif [[ "$URL" =~ ^https?://([^/]+)/(.+)$ ]]; then
HOST="${BASH_REMATCH[1]}"
PATH_PART="${BASH_REMATCH[2]}"
else
echo "Unrecognised URL: $URL"; exit 1
fi
# Find matching Host alias in ~/.ssh/config
ALIAS=$(awk -v h="$HOST" '
$1=="Host" {host=$2}
$1=="HostName" && $2==h {print host}
' "$CONFIG")
[[ -z "$ALIAS" ]] && { echo "No Host entry for ${HOST}"; exit 1; }
NEW_URL="git@${ALIAS}:${PATH_PART}"
echo "Cloning with ${NEW_URL}"
git clone "${NEW_URL}"
What it does
- Parses the incoming URL (SSH or HTTPS).
- Looks up a
HostName
match inside~/.ssh/config
. - Rewrites the URL to
git@<Host-alias>:repo/path.git
. - Runs
git clone
so the correct key is automatically selected.
Make the scripts executable
chmod +x ~/Development/personal/innovate-hub/tools/scripts/{generate_ssh_key.sh,checkout}
Add the scripts directory to PATH
Edit ~/.zshrc
(or ~/.profile
if you prefer it shell-agnostic):
export PATH="$PATH:$HOME/Development/personal/innovate-hub/tools/scripts"
Then reload:
source ~/.zshrc # or source ~/.profile
Confirm:
which checkout
# → /home/kevin/Development/personal/innovate-hub/tools/scripts/checkout
Putting it all together
- Work as usual – all future
git pull/push
operations in that repo use the linked key.
Clone using the smart checkout:
cd ~/code
checkout https://github.com/kiarash/my-repo.git
The script maps github-personal
, rewrites the URL, and clones with the right key.
Generate a key per account or repo:
generate_ssh_key.sh github-personal
Paste the public key into GitHub and add the printed block to ~/.ssh/config
.
Troubleshooting
Symptom | Fix |
---|---|
No Host entry for github.com |
Double-check the HostName field in your ~/.ssh/config . |
Permission denied (publickey) | Ensure you added the public key to your Git provider and that your private key file permissions are 600 . |
checkout not found |
Re-source your shell config or verify the PATH export. |
Happy cloning – and no more mismatched keys!