Select private key to use with Git

Viewed 108578

I have 2 Git servers that require 2 different SSH keys.

git clone user1@server1:blahblahblah uses ~/.ssh/id_rsa, but I need to specify which key to use depending on the server I am connecting to.

What Git command-line parameter does this job? (I am running Linux.)

9 Answers

You can set --global or --local configuration, global will update ~/.gitconfig file, local will update configuration in the repository .git/config and override the global (~/.gitconfig) configuration

git config --local --add core.sshCommand 'ssh -i ~/.ssh/my_key'

Windows user here, I just ran into this issue and have a slightly different solution then I have read here so far. The problem I faced is that I simply wanted to clone a repo using a specific private ssh key and not have to globally configure my git config or add specific git bash settings, as I do my work in PowerShell. Essentially I just want to have some private keys sitting in my .ssh folder and I reference them in specific repos as required.

The following command works for this:

git clone -c core.sshCommand="ssh -i ~/.ssh/<PRIVATE KEY NAME>" <CLONE URL>

Essentially what this does is upon the initialization of the git repo it sets the core.sshCommand option before running the clone. So the specific ssh key you wish to use for this repo is set ONLY for this repo. This may not be an ideal solution for all cases but for what I want it is.

Another option is to write a small script to make core.sshCommand a bit smarter - check if the current working directory has a specific SSH key configured and if so use it, otherwise - rely on the standard SSH key resolution.

Here is my first version:

#!/bin/bash
key="$(git config ssh.key)"
if [ -n "$key" ]; then
        ssh -o IdentitiesOnly=yes -i "$key" "$@"
else
        ssh "$@"
fi

Then set it up as the global git SSH command:

chmod 755 ~/.local/bin/git-ssh-command
git config --global core.sshCommand ~/.local/bin/git-ssh-command

(~/.local/bin is the current standard for "place user scripts here" on SystemD operating systems)

After you set this up, you can configure any repository to use a specific SSH key by setting the configuration option ssh.key:

git config --local ssh.key ~/.ssh/my-non-default-private-key

Additional Optional Tricks

  • Set the global ssh.key to have a "default fallback to non-default SSH key" or something.
  • As git executes core.sshCommand in the root directory of the repository, your custom git-ssh-command can look at that and have some heuristics about directory names. This can be done in the else section so heuristics only kick in if there is no specific key in ssh.key.
  • You can add git remote -v check to add heuristics based on the the remotes, like in Eike's script
  • If you want to look at the repository remotes but have multiple remotes that need different keys, you can add remote="$1:$(sed "s,.* ,,;s,',,g"<<<"$2")" at the beginning of the script to resolve the remote being operated on - and check against that ($remote would look like the middle column in git remote -v output).

Update:

Here's a version of the custom SSH command that looks at the remote URL and does some heuristics - in my case, I have several different identities with the same public git hosting service (one for work, one for personal, etc) and I can select the correct identity by looking at the remote URL (examining the Gitlab group or the Github organization, etc):

#!/bin/bash
while ! [[ "$1" =~ "git@" ]]; do shift; done # git may send ssh options
if [[ "$2" =~ ^git-lfs-authenticate.* ]]; then # reconstruct url for git-lfs
        remote="$1:$(awk '{print$2}'<<<"$2")"
else # reconstruct url for standard git commands
        remote="$1:$(sed "s,.* ,,;s,',,g"<<<"$2")"
fi
echo "Detected $remote from $@" >&2
key="$(git config ssh.key)"
if [ -n "$key" ]; then # use specified SSH key, if set
        ssh -o IdentitiesOnly=yes -i "$key" "$@"
elif [[ "$remote" == git@gitlab.com:my-company* ]]; then # use company id
        ssh -o IdentitiesOnly=yes -i ~/.ssh/company-id "$@"
elif [[ "$remote" =~ git@bitbucket.org:.*other-org.* ]]; then # bitbucket has weird urls
        ssh -o IdentitiesOnly=yes -i ~/.ssh/custom-org-key "$@"
else # otherwise use whatever the agent has (my personal key)
        ssh "$@"
fi

The other answers inspired me to write a little script that chooses the ssh key depending on command line options or (if present) the values of git remote -v. Hope it helps!

To actually answer the question: Use gat.

See also https://bitbucket.org/eikerobert/gat/src/master/

#!/bin/bash

usegat=false

for VAR in "$@"
do
    if [ "$VAR" != "${VAR/git@bitbucket.org:myaccount/}" ]; then
        usegat=true
    fi
done

if [ $usegat=false ]; then
   /usr/bin/git rev-parse --is-inside-work-tree >/dev/null 2>&1
   isinsidegitrepo=$?
    #echo $isinsidegitrepo
   if [ $isinsidegitrepo = 0 ]; then
       remote=`/usr/bin/git remote -v`
       if [ "$remote" != "${remote/git@bitbucket.org:myaccount/}" ]; then
           usegat=true
       fi
   fi
fi


if [ $usegat = true ]; then
    # echo "TRUE"
    /usr/bin/git -c core.sshCommand="/usr/bin/ssh -i /home/myaccount/.ssh/mykey" "$@"
else
     #echo "FALSE"
    /usr/bin/git "$@"
fi
Related