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

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:

  1. generate_ssh_key.sh – creates a fresh SSH key and drops a ready-to-paste stanza into ~/.ssh/config.
  2. checkout – rewrites any Git URL so git 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 in ssh_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

  1. Parses the incoming URL (SSH or HTTPS).
  2. Looks up a HostName match inside ~/.ssh/config.
  3. Rewrites the URL to git@<Host-alias>:repo/path.git.
  4. 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

  1. 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!