When working with Git repositories over SSH, authentication typically relies on default SSH key pairs (like ~/.ssh/id_rsa
or ~/.ssh/id_ed25519
) or keys managed by an SSH agent.
However, situations arise where it’s necessary to explicitly instruct Git to use a specific, non-default private key file for operations such as git clone
, git pull
, or git push
. This is common when managing multiple identities (e.g., personal and work accounts for the same Git hosting service) or when keys are stored in custom locations.
This guide details several established methods for directing Git to utilize a designated SSH private key, bypassing the standard key discovery process.
Why Specify a Key? Understanding Default Behavior
By default, when Git connects to a remote via SSH, the underlying SSH client attempts authentication using a sequence of methods:
- It may check the SSH agent (if running) for loaded keys.
- It typically looks for default key files in the user’s
~/.ssh/
directory (e.g.,id_rsa
,id_ed25519
,id_dsa
). - It consults the SSH configuration file (
~/.ssh/config
) for host-specific settings, which might include anIdentityFile
directive.
If the required private key isn’t loaded in the agent, doesn’t match a default filename, or isn’t correctly specified in the SSH config for the target host, authentication fails, often resulting in a Permission denied (publickey)
error. Explicitly specifying the key tells SSH exactly which identity to use for the connection.
Read: How to configure SSH-key based authentication on Ubuntu 20.10
Methods for Specifying SSH Keys
Several approaches allow you to control which SSH key Git employs:
1. Using the SSH Configuration File (`~/.ssh/config`)
This is often considered the most robust and flexible method, especially for managing multiple keys or hosts permanently. The ~/.ssh/config
file allows you to define connection parameters per host or host alias.
Direct Host Configuration
You can define settings directly for a specific hostname:
# ~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_personal_key
IdentitiesOnly yes
In this example, any SSH connection to github.com
(including Git operations) will attempt to use the key specified by IdentityFile
.
Using Host Aliases for Multiple Identities
To manage different keys for the *same* hostname (e.g., personal and work accounts on GitHub), define aliases using the `Host` directive:
# ~/.ssh/config
# Personal GitHub account
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/personal_key
IdentitiesOnly yes
AddKeysToAgent yes # Optional: Add key to agent on first use
# Work GitHub account
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/work_key
IdentitiesOnly yes
To use these aliases with Git, modify your remote URL to use the alias instead of the actual hostname:
# Clone using the 'github-work' alias and associated key
git clone git@github-work:CompanyName/ProjectRepo.git
# Or, update an existing remote's URL
git remote set-url origin git@github-work:CompanyName/ProjectRepo.git
Key Directives Explained:
Host
: The alias or pattern to match. This is what you use in SSH commands or Git URLs (e.g., `git@github-work:…`).HostName
: The actual server hostname or IP address to connect to.User
: The remote username (often `git` for services like GitHub/GitLab).IdentityFile
: The path to the specific private key file to use.IdentitiesOnly yes
: Crucial setting. Instructs SSH to *only* try the key specified inIdentityFile
and keys in the agent, preventing it from trying default key files (like `~/.ssh/id_rsa`) which might lead to using the wrong identity.AddKeysToAgent yes
: If the key has a passphrase, this attempts to add it to a running SSH agent after the first successful authentication, avoiding repeated passphrase prompts.
Permissions: Ensure your ~/.ssh/config
file has restricted permissions: chmod 600 ~/.ssh/config
.
Read: How to Resolve Git ‘Permission denied (publickey)’ SSH Authentication Errors
2. Using the `GIT_SSH_COMMAND` Environment Variable
Available since Git 2.3.0, this environment variable lets you specify the exact SSH command Git should use, including options like `-i` to point to a key file. This is useful for temporary overrides or scripting.
# Run a single git command using a specific key
GIT_SSH_COMMAND='ssh -i /path/to/private_key -o IdentitiesOnly=yes' git clone user@host:repo.git
# Set the variable for the current shell session
export GIT_SSH_COMMAND='ssh -i /path/to/private_key -o IdentitiesOnly=yes'
git pull
git push
# Unset it later if needed: unset GIT_SSH_COMMAND
Again, including -o IdentitiesOnly=yes
is recommended to ensure only the specified key is attempted.
Windows CMD Quoting: When using `set` in Windows Command Prompt, use the `set “VARIABLE=value”` syntax:
set "GIT_SSH_COMMAND=ssh -i C:\path\to\private_key -o IdentitiesOnly=yes"
3. Using the `core.sshCommand` Git Configuration Setting
Introduced in Git 2.10.0, this allows setting the equivalent of `GIT_SSH_COMMAND` directly within the Git configuration, either per-repository or globally.
Per-Repository Configuration
Configure the setting within a specific cloned repository:
cd /path/to/your/repo
git config core.sshCommand 'ssh -i /path/to/private_key -o IdentitiesOnly=yes'
# Now subsequent commands in this repo use the specified key
git pull
git fetch
This adds the setting to the repository’s .git/config
file.
Configuration During Clone
You can set the configuration temporarily for the `clone` command using the `-c` flag, and then optionally make it permanent within the newly cloned repository:
# Clone using the specified key
git -c core.sshCommand="ssh -i /path/to/private_key -o IdentitiesOnly=yes" clone user@host:repo.git new-repo-dir
# Optionally, make it permanent for this repo
cd new-repo-dir
git config core.sshCommand 'ssh -i /path/to/private_key -o IdentitiesOnly=yes'
A combined approach for cloning *and* setting the config permanently in one go:
git clone -c "core.sshCommand=ssh -i /path/to/private_key -o IdentitiesOnly=yes" user@host:repo.git
Ignoring User SSH Config
Sometimes, you might want Git to use the specified command and key while completely ignoring the user’s `~/.ssh/config`. The `-F /dev/null` option (or equivalent on non-Unix systems) can achieve this:
git config core.sshCommand "ssh -i /path/to/private_key -F /dev/null -o IdentitiesOnly=yes"
4. Using a Wrapper Script via `GIT_SSH` Environment Variable
This older method involves creating a small shell script that invokes `ssh` with the desired key, and then telling Git to use this script via the `GIT_SSH` environment variable.
- Create a wrapper script (e.g.,
~/ssh_wrapper_for_git.sh
):#!/bin/bash # ~/ssh_wrapper_for_git.sh ssh -i /path/to/private_key -o IdentitiesOnly=yes "$@"
- Make the script executable:
chmod +x ~/ssh_wrapper_for_git.sh
- Set the `GIT_SSH` variable and run Git:
export GIT_SSH=~/ssh_wrapper_for_git.sh git clone user@host:repo.git # Unset later: unset GIT_SSH
Or for a single command:
GIT_SSH=~/ssh_wrapper_for_git.sh git clone user@host:repo.git
Temporary Wrapper: A variation creates a temporary wrapper script on the fly, useful within other scripts:
SSH_KEY=/path/to/private_key
TMP_SSH_WRAPPER=$(mktemp /tmp/.git_ssh.XXXXXX)
trap 'rm -f "$TMP_SSH_WRAPPER"' EXIT # Ensure cleanup
echo "#!/bin/sh" > "$TMP_SSH_WRAPPER"
echo "ssh -i \"$SSH_KEY\" -o IdentitiesOnly=yes \"$@\"" >> "$TMP_SSH_WRAPPER"
chmod +x "$TMP_SSH_WRAPPER"
GIT_SSH="$TMP_SSH_WRAPPER" git clone user@host:repo.git
# Script removed automatically on exit via trap
5. Using `ssh-agent` Temporarily or Selectively
The `ssh-agent` can be invoked specifically for a single command, loading only the desired key.
# Start agent, add key, run git, agent terminates afterwards
ssh-agent bash -c 'ssh-add /path/to/private_key; git clone user@host:repo.git'
Agent Cleanup for Scripts: If using `ssh-agent` within scheduled tasks or scripts, ensure the agent process is terminated afterward. Appending `&& ssh-agent -k` to the command executed by `bash -c` can help kill the specific agent instance.
ssh-agent bash -c 'ssh-add /path/to/key; git pull && ssh-agent -k'
Alternatively, if you have multiple keys loaded in your main running agent, you can temporarily clear all keys and add back only the one you need:
# Warning: Removes all currently loaded keys from agent
ssh-add -D
# Add only the specific key needed
ssh-add /path/to/specific_private_key
# Perform Git operations
git push
# Optionally, re-add other keys afterwards if needed
ssh-add /path/to/other_private_key
This is more of a manual workaround than a configuration.
Read: How to install Git on Ubuntu 18.04
6. Using GitHub CLI (`gh`)
For interacting specifically with GitHub, the official GitHub CLI tool (`gh`) provides its own authentication mechanism that can simplify things, especially if managing multiple GitHub accounts.
# Install gh (e.g., via Homebrew on macOS)
brew install gh
# Login interactively (will handle authentication setup)
gh auth login
# Clone repositories using gh
gh repo clone OWNER/REPO
Once authenticated via `gh auth login`, subsequent `gh` commands (and often standard `git` commands interacting with GitHub) may work without needing explicit SSH key specification, as `gh` can act as a credential helper.
Verification and Considerations
- Verify SSH Connection: Use `ssh -vT git@hostname` (replace `hostname` with the actual host or alias from your `~/.ssh/config`) to see detailed connection attempts and which keys are being offered.
- Check Agent Keys: Use `ssh-add -l` to see which keys are currently loaded into your SSH agent.
- `IdentitiesOnly yes`: This option is highly recommended in most methods (`~/.ssh/config`, `GIT_SSH_COMMAND`, `core.sshCommand`) to prevent ambiguity and ensure the specified key is prioritized and tried exclusively (alongside any agent keys).
- Key Permissions: Ensure your private key files have strict permissions (e.g., `chmod 600 /path/to/private_key`). Incorrect permissions can prevent SSH from using the key.
- URL Matching: When using `~/.ssh/config` with host aliases, ensure the Git remote URL precisely matches the `Host` alias entry (e.g., `git@github-work:…` matches `Host github-work`).
- Submodules: If your repository uses submodules hosted on the same service but potentially requiring the same specific key, you might need to ensure the submodule URLs also align with your SSH configuration or use Git config’s `url..insteadOf` to rewrite submodule URLs automatically. Example: `git config url.git@gitserv:.insteadOf https://remote.server.com` (adapting the alias and URL).
- Windows Path Specifics: When specifying paths on Windows for `IdentityFile` or `-i`, ensure correct formatting (e.g., `C:/Users/user/.ssh/key` or using appropriate quoting). Also, be aware of potential conflicts between Git’s bundled SSH and Windows’ native OpenSSH; explicitly setting the path in `core.sshCommand` might be necessary (e.g., `’C:/Windows/System32/OpenSSH/ssh.exe -i …’`).
Conclusion
Directing Git to use a specific SSH private key is achievable through several methods, each suited to different scenarios. Configuring the `~/.ssh/config` file offers a persistent and flexible solution, especially for managing multiple identities or hosts. Using the `GIT_SSH_COMMAND` environment variable or the `core.sshCommand` Git setting provides effective ways to override behavior temporarily or on a per-repository basis. Understanding these options allows for precise control over SSH authentication in various Git workflows.
Frequently Asked Questions (FAQ)
- Why is `IdentitiesOnly yes` important?
- Without it, SSH might try default key files (like `~/.ssh/id_rsa`) *before* trying the key specified via `IdentityFile` or `-i`. If a default key exists and is accepted by the server (even if for a different account), the connection might succeed using the wrong identity. `IdentitiesOnly yes` forces SSH to primarily consider the explicitly specified key and any keys loaded in the agent.
- How do I handle multiple accounts for the *same* Git hosting service (e.g., two GitHub accounts)?
- The recommended method is using host aliases in your `~/.ssh/config` file. Define different `Host` aliases (e.g., `github-personal`, `github-work`), both pointing to the same `HostName` (e.g., `github.com`), but each specifying a different `IdentityFile`. Then, use the appropriate alias in your Git remote URLs.
- Does `ssh-agent bash -c ‘ssh-add …’` add the key permanently?
- No. The `ssh-agent` started by that command runs only for the duration of the command specified within `bash -c ‘…’`. Once the `git` command finishes, the agent typically terminates, and the key is forgotten by that specific agent instance. It does not affect your main, persistent SSH agent if you have one running.
- What’s the difference between `GIT_SSH_COMMAND` and `core.sshCommand`?
- `GIT_SSH_COMMAND` is an environment variable, affecting Git processes run within that environment. `core.sshCommand` is a Git configuration setting stored either globally (`~/.gitconfig`) or locally within a repository (`.git/config`). The environment variable typically overrides the configuration setting if both are present.
- Can I use the `-i` flag directly with `git clone`?
- No, `git` itself does not have a built-in `-i` flag to specify an SSH key file directly like the `ssh` command does. You must use one of the methods described above (SSH config, environment variables, Git config) to influence the underlying SSH command that Git invokes.
- What if my private key requires a passphrase?
- Methods using `GIT_SSH_COMMAND`, `core.sshCommand`, or a wrapper script will typically prompt for the passphrase interactively if needed. Using `ssh-agent` (either the temporary one or adding the key to your main agent with `ssh-add`) is the standard way to enter the passphrase once and have the agent manage it for subsequent connections.
If you like the content, we would appreciate your support by buying us a coffee. Thank you so much for your visit and support.