Skip to content

Email-Keyed Git Identity

 2 min Selecting a preferred SSH key from Git’s effective email address, with organization-specific identity set by the remote URL.
Published

Jun 28, 2025

My SSH keys are named after email addresses: c@anthonyrisinger.com, c@snap.gs, one file per identity in ~/.ssh. Git’s effective user.email selects the preferred key for an SSH connection as well as the author address for a commit.

The key-selection logic began as a compact core.sshCommand. Expanded with quoted arguments and a regular-file check, its shell body is:

email=$(git config user.email)
id=$HOME/.ssh/$email
if [[ -n $email && -f $id ]]; then
    set -- -o IdentitiesOnly=yes -i "$id" "$@"
fi
exec ssh "$@"

git config user.email resolves conditional includes before returning the value. If a matching key exists, set -- prepends the SSH options without changing the original argument boundaries. Otherwise the script passes through to ordinary SSH behavior. The nonempty-email and -f checks prevent ~/.ssh/ itself from being mistaken for a key.

When wrapping this body in bash -c, supply a value for $0 after the command string. The host and arguments Git appends then reach $@ instead of the first one being consumed as the script name.

IdentitiesOnly=yes excludes extra identities offered only by an SSH agent. Other IdentityFile entries from SSH configuration remain eligible, so this selects a preferred key rather than enforcing one-key authentication. An exclusive-key policy also needs control of the SSH configuration.

Let the remote choose the email

Conditional includes keyed on the remote URL let identity follow a clone wherever it lives on disk. These patterns include the separator before the organization name:

[includeIf "hasconfig:remote.*.url:**:snap-gs/**"]
    path = snap-gs/config
[includeIf "hasconfig:remote.*.url:**/snap-gs/**"]
    path = snap-gs/config

The first handles scp-style SSH URLs such as git@github.com:snap-gs/repo. The second handles slash-separated URLs, including HTTPS and ssh://. Without the colon in the first pattern, an organization named other-snap-gs could match too.

Each organization-specific file contains the identity:

[user]
    email = c@snap.gs

That one value controls commit authorship and supplies the keyfile name. Two email identities that share a key can use a symlink between their keyfiles.

The URL-based hasconfig form requires Git 2.36 or newer. It replaced the earlier directory-based includes in my dotfiles. The examples above include the argument quoting, file checks, and organization delimiters missing from the original compact form.