Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

ssh has the -i option to tell which private key file to use when authenticating:

-i identity_file

    Selects a file from which the identity (private key) for RSA or DSA authentication is read.  The default is ~/.ssh/identity for protocol version 1, and ~/.ssh/id_rsa and ~/.ssh/id_dsa for protocol version 2.  Identity files may also be specified on a per-host basis in the configuration file.  It is possible to have multiple -i options (and multiple identities specified in configuration files).

Is there a similar way to tell git which private key file to use on a system with multiple private keys in the ~/.ssh directory?

share|improve this question
    
See this question in StackOverflow as well. – Flimm May 8 '15 at 9:46
    
Also related serverfault.com/questions/194567/… – Machavity Jun 28 at 14:51

10 Answers 10

up vote 262 down vote accepted

In ~/.ssh/config, add:

host github.com
 HostName github.com
 IdentityFile ~/.ssh/id_rsa_github
 User git

Now you can do git clone git@github.com:username/repo.git.

NOTE: Verify that the permissions on IdentityFile are 400.SSH will reject, in a not clearly explicit manner, SSH keys that are too readable. It will just look like a credential rejection. The solution, in this case, is:

chmod 400 ~/.ssh/id_rsa_github
share|improve this answer
9  
What if you need to connect to the same host with different keys? – Valentin Klinghammer Nov 30 '12 at 11:24
4  
@Quelltextfabrik - you can add another section with a different Host: nerderati.com/2011/03/… – Ben Challenor Dec 4 '12 at 14:17
    
I'm using this trick in my github-keygen tool that I built to manage SSH keys and settings for Github. – dolmen Sep 20 '13 at 10:10
    
@Cliff Nop, in my manpage: "HostName: Specifies the real host name to log into. This can be used to specify nicknames or abbreviations for hosts." My ssh version is openssh-6.7p1. – Grissiom Jan 7 '15 at 2:17
    
@Grissiom That's exactly what it says. But you seem to understand the meaning backwards. Host (or Match) is required. To create a host nickname you place the nickname in the Host line and the real hostname in the HostName line. Examples: saltycrane.com/blog/2008/11/… – Cliff Jan 8 '15 at 3:55

From Git version 2.3.0, you can use the environment variable GIT_SSH_COMMAND like this:

GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example" git clone example

Note that -i can sometimes be overridden by your config file, in which case, you should give SSH an empty config file, like this:

GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example -F /dev/null" git clone example
share|improve this answer
    
I had to export the shell variable to an environment variable to make this work, i.e. export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example", then git clone example – Abdull Dec 1 '15 at 13:46
4  
@Abdull In Bash, doing the assignment on the same line as the command exports the environment variable for just that command. Try it: example=hello /usr/bin/env | grep example. – Flimm Jan 8 at 9:50

Write a script that calls ssh with the arguments you want, and put the filename of the script in $GIT_SSH. Or just put your configuration in ~/.ssh/config.

share|improve this answer
3  
That's a handy trick – Bryan Agee May 30 '12 at 17:13
1  
Another explanation of how to do this. – Sithsu May 12 '14 at 19:44
1  
~/.ssh/config Is the way to go. – hek2mgl May 8 '15 at 13:56
    
I work on a machine (A) from which I git push to a server (B) that only accepts ssh key authentication. While my ~/.ssh/config setup on (A) works perfectly fine when I work directly on that machine, it does not when I login from some other location (C). Using $GIT_SSH and a script solved this problem. Thanks! – bsumirak Dec 3 '15 at 17:28

There is no direct way to tell git which private key to use, because it relies on ssh for repository authentication. However, there are still a few ways to achieve your goal:

Option 1: ssh-agent

You can use ssh-agent to temporarily authorize your private key.

For example:

$ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch user@host'

Option 2: GIT_SSH_COMMAND

Pass the ssh arguments by using the GIT_SSH_COMMAND environment variable (Git 2.3.0+).

For example:

$ GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \
                                                                git clone user@host

You can type this all on one line — leave out the \.

Option 3: GIT_SSH

Pass the ssh arguments by using the GIT_SSH environment variable.

For example:

$ echo 'ssh -i ~/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $*' > ssh
$ chmod +x ssh
$ GIT_TRACE=1 GIT_SSH='./ssh' git clone user@host

Note: The above lines are shell (terminal) command lines which you should paste into your terminal. They will create a file named ssh, make it executable, and (indirectly) execute it.

Option 4: ~/.ssh/config

Use the ~/.ssh/config file as suggested in other answers in order to specify the location of your private key.

share|improve this answer
    
// , What if your identity in ssh-agent is forwarded, though, as in this question? superuser.com/questions/971732/… – Nathan Basanese Sep 11 '15 at 18:06
1  
I've allowed me to reformat this post: IMO this is by far the most comprehensive answer. In its original design, a quick scan suggested the post where describing a single complicated solution to the problem, so I missed it. – Alberto Jan 21 at 10:01

After my struggle with $GIT_SSH I would like to share what worked for me.

Through my examples I will assume you have your private key located at/home/user/.ssh/jenkins

Error to avoid: GIT_SSH value includes options

$ export GIT_SSH="ssh -i /home/user/.ssh/jenkins"

or whatever similar will fails, as git will try to execute the value as a file. For that reason, you have to create a script.

Working example of $GIT_SSH script /home/user/gssh.sh

The script will be invoked as follows:

$ $GIT_SSH [username@]host [-p <port>] <command>

Sample script working could look like:

#!/bin/sh
ssh -i /home/user/.ssh/jenkins $*

Note the $* at the end, it is important part of it.

Even safer alternative, which would prevent any possible conflict with anything in your default config file (plus explicitly mentioning the port to use) would be:

#!/bin/sh
ssh -i /home/user/.ssh/jenkins -F /dev/null -p 22 $*

Assuming the script is in /home/user/gssh.sh, you shall then:

$ export GIT_SSH=/home/user/gssh.sh

and all shall work.

share|improve this answer
    
Thanks... this one did exactly what I needed it to! – Jimbo Nov 5 '15 at 16:19
    
Thanks. Just note: use "$@" instead of $* for pass-thru arguments, as the former behaves correctly when arguments contain whitespace. – Piotr Findeisen Mar 31 at 7:39
    
@PiotrFindeisen Thanks for your note. However, I do not understand it completely - in zsh it helps me to keep strings with space in one piece, but in bash not. Can you tell me more or point to some explanation? I do not want to add some modification blindly. – Jan Vlcinsky Mar 31 at 10:33

If you do not want to have to specify environment variables every time you run git, do not want another wrapper script, do not/can not run ssh-agent(1), nor want to download another package just for this, use the git-remote-ext(1) external transport:

$ git clone 'ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git'
Cloning into 'repository'
(...)
$ cd repository
$ git remote -v
origin  ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git (fetch)
origin  ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git (push)

I consider this solution superior because:

  • It is repository/remote specific
  • Avoid wrapper script bloat
  • Do not need the SSH agent -- useful if you want unattended clones/push/pulls (e.g. in cron)
  • Definitely, no external tool needed
share|improve this answer
    
// , Excellent solution. I wonder, though, if this would allow one to specify an identity passed through using agent forwarding. Most of my keys are not local to the servers I am using them on. I asked about this here: superuser.com/questions/971732/… – Nathan Basanese Sep 11 '15 at 18:09
    
The answer deals only with a way of specifying arbitrary command lines to be used as git repositories. IMHO, you should try to sort out your issue using ssh alone first (e.g. "ssh host" should connect using the right key). I will try to provide more info on your other question, though. – flaviovs Sep 14 '15 at 16:34
    
Re my last comment, for some reason I cannot comment in your other question -- and do not have a concrete answer. Well, you might want to checkout serverfault.com/questions/599560/… and the answer from user kasperd. – flaviovs Sep 14 '15 at 17:51
    
This answer was exactly what I needed to force Chef's git resource to use repository-specific deployment keys to clone/fetch from private Github repositories. The additional advantage of this method over the environment/script based ones is that since the key-path is encoded in the working-repo's config, it will use the same key on both initial clone and subsequent fetches/pushes. – Adam Franco Nov 19 '15 at 16:20
    
WOW! This is just great, didn't know about this. Thanks for the answer, quite helpful as well in puppet environments, to prevent the extra hassle to manage .ssh/config etc. +1! – gf_ Jun 10 at 18:36

You can just use ssh-ident instead of creating your own wrapper.

You can read more at: https://github.com/ccontavalli/ssh-ident

It loads ssh keys on demand when first needed, once, even with multiple login sessions, xterms or NFS shared homes.

With a tiny config file, it can automatically load different keys and keep them separated in different agents (for agent forwarding) depending on what you need to do.

share|improve this answer

My solution was this:

create a script:

#!/bin/bash
KEY=dafault_key_to_be_used
PORT=10022 #default port...
for i in $@;do
   case $i in
    --port=*)
        PORT="${i:7}";;
    --key=*)KEY="${i:6}";;
   esac
done
export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/${KEY} -p ${PORT}"
echo Command: $GIT_SSH_COMMAND

then when you have to change the var run:

. ./thescript.sh [--port=] [--key=]

Don't forget the extra dot!! this makes the script set the environments vars!! --key and --port are optional.

share|improve this answer

Use custom host config in ~/.ssh/config, like this:

Host gitlab-as-thuc  
    HostName git.thuc.com
    User git
    IdentityFile ~/.ssh/id_rsa.thuc
    IdentitiesOnly yes

then use your custom hostname like this:

git remote add thuc git@gitlab-as-thuc:your-repo.git  

For more detail please read here: http://itblog.study.land/how-to-specify-different-ssh-keys-for-git-push-for-a-given-domain/

share|improve this answer
1  
This is the answer I was looking for, as I have separate GitHub accounts for home and work. I just had to set Host work.github.com HostName github.com IdentityFile ~/.ssh/work, and then replace "github.com" by "work.github.com" whenever I clone a work repository. It still connects to "github.com", but using a non-default key pair. – Mikkel May 25 at 17:06

Generally, you want to use ~/.ssh/config for this. Simply pair server addresses with the keys you want to use for them as follows:

Host github.com
  IdentityFile ~/.ssh/id_rsa.github
Host heroku.com
  IdentityFile ~/.ssh/id_rsa.heroku
Host *
  IdentityFile ~/.ssh/id_rsa

Host * denotes any server, so I use it to set ~/.ssh/id_rsa as the default key to use.

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .