How to tell git which private key to use?

1,146,696

Solution 1

In ~/.ssh/config, add:

Host github.com
 HostName github.com
 IdentityFile ~/.ssh/id_rsa_github

If the config file is new, you might need to do chmod 600 ~/.ssh/config

Now you can do git clone [email protected]:{ORG_NAME}/{REPO_NAME}.git

  • Where {ORG_NAME} is your GitHub user account (or organization account)'s GitHub URI name.
    • Note that there is a colon : after github.com instead of the slash / - as this is not a URI.
  • And {REPO_NAME} is your GitHub repo's URI name
  • For example, for the Linux kernel this would be git clone [email protected]:torvalds/linux.git).

NOTE: On Linux and macOS, verify that the permissions on your 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

Solution 2

Environment variable GIT_SSH_COMMAND

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 [email protected]:example/example.git

Configuration core.sshCommand

Since Git version 2.10.0, you can configure this per repo or globally, using the core.sshCommand setting. There's no more need to use the environment variable. Here's how you clone a repo and set this configuration at the same time:

git clone -c "core.sshCommand=ssh -i ~/.ssh/id_rsa_example -F /dev/null" [email protected]:example/example.git
cd example/
git pull
git push

If the repo already exists, run:

git config core.sshCommand "ssh -i ~/.ssh/id_rsa_example -F /dev/null"

The configuration is saved in .git/config

Solution 3

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 — ignore $ and leave out the \.

Option 3: GIT_SSH

Pass the ssh arguments by using the GIT_SSH environment variable to specify alternate ssh binary.

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.

Note: GIT_SSH is available since v0.99.4 (2005).

Option 4: ~/.ssh/config

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

Host github.com
  User git
  Hostname github.com
  IdentityFile ~/.ssh/id_rsa

Solution 4

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

Host gitlab-as-thuc  
    HostName github.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  

Solution 5

If you need to connect to the same host with different keys then you can achieve it by:

  1. Configure the ~/.ssh/config with different Hosts but same HostNames.
  2. Clone your repo using the appropriate host.

Example:

~/.ssh/config

Host work
  HostName bitbucket.org
  IdentityFile ~/.ssh/id_rsa_work
  User git
    
Host personal
  HostName bitbucket.org
  IdentityFile ~/.ssh/id_rsa_personal
  User git

Then instead cloning your repos like:

git clone git@bitbucket.org:username/my-work-project.git
git clone git@bitbucket.org:username/my-personal-project.git

you must do

git clone git@work:username/my-work-project.git
git clone git@personal:username/my-personal-project.git
Share:
1,146,696

Related videos on Youtube

jrdioko
Author by

jrdioko

Updated on September 17, 2022

Comments

  • jrdioko
    jrdioko over 1 year

    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?

  • Valentin Klinghammer
    Valentin Klinghammer over 11 years
    What if you need to connect to the same host with different keys?
  • dolmen
    dolmen over 10 years
    I'm using this trick in my github-keygen tool that I built to manage SSH keys and settings for Github.
  • Sithsu
    Sithsu about 10 years
    Another explanation of how to do this.
  • Grissiom
    Grissiom over 9 years
    @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.
  • Cliff
    Cliff over 9 years
    @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/…
  • hek2mgl
    hek2mgl about 9 years
    ~/.ssh/config Is the way to go.
  • Nathan Basanese
    Nathan Basanese over 8 years
    // , What if your identity in ssh-agent is forwarded, though, as in this question? superuser.com/questions/971732/…
  • Nathan Basanese
    Nathan Basanese over 8 years
    // , 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/…
  • flaviovs
    flaviovs over 8 years
    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
    flaviovs over 8 years
    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.
  • Adam Franco
    Adam Franco over 8 years
    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.
  • Abdull
    Abdull over 8 years
    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
  • bsumirak
    bsumirak over 8 years
    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!
  • Flimm
    Flimm over 8 years
    @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.
  • Alexis Winters
    Alexis Winters over 8 years
    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.
  • elysch
    elysch about 8 years
    If the config file is new, don't forget to do chmod 600 ~/.ssh/config
  • Piotr Findeisen
    Piotr Findeisen about 8 years
    Thanks. Just note: use "$@" instead of $* for pass-thru arguments, as the former behaves correctly when arguments contain whitespace.
  • Jan Vlcinsky
    Jan Vlcinsky about 8 years
    @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.
  • Mikkel
    Mikkel about 8 years
    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.
  • gxx
    gxx almost 8 years
    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!
  • Nullpointer
    Nullpointer over 7 years
    User git perfact
  • cr8ivecodesmith
    cr8ivecodesmith over 7 years
    Excellent answer! If you're using github, I made a quick guide about it: mattlebrun.com/use-different-git-ssh-key-per-project.html
  • eckes
    eckes over 7 years
    things have become even better: as of Git 2.10, you can store the command in your Git configuration: stackoverflow.com/a/38474220/520162
  • lessthanideal
    lessthanideal over 7 years
    Note you might not need "username" in your git path. e.g. my user on our local gitlab with permission for our shared project is Alice, I'm logged onto Linux as Bob. I created the ssh keys as Bob and put the public key on gitlab associated with Alice. Now I can clone like this from Linux, logged in as Bob, without mentioning "Alice" anywhere,
  • Daniele Testa
    Daniele Testa over 7 years
    This solution does not work together with the --recursive flag. The submodules are not fetched using the specified key and therefor fails if they require auth.
  • flaviovs
    flaviovs over 7 years
    Each submodule is an entirely different repository, with their own set of remotes. They're glued together by Git for your convenience, but in no way remotes for a submodule are tied to the ones in the parent repository. I'm afraid that you must set the remote using the ext transport in each submodule for recursion in the parent to work.
  • Noitidart
    Noitidart about 7 years
    For me I had to remove the ` -F /dev/null` i dont know why , otherwise it would tell me: git config core.sshCommand "ssh -i ~/.ssh/toptal_i nterview_3_rsa -f /dev/null" PS C:\Users\Mercurius\Desktop\timekeep> git push -u origin master ssh: Could not resolve hostname /dev/null: Name or service not known
  • Flimm
    Flimm about 7 years
    @Noitidart /dev/null is only a valid filename in UNIX-like operating systems, it doesn't work on Windows.
  • Noitidart
    Noitidart about 7 years
    Thanks very much @Flimm, so it is safe to do your command without the -F too? Also I don't understand in the second part, since 2.10.0 you mention we can configure it globally, but the second part only shows the local method no?
  • weeJimmy
    weeJimmy about 7 years
    The core.sshCommand config setting was just the thing I needed, because it lets me use a certain key by default in most circumstances, but then specify a different key with a core.sshCommand in a repository/.git/config file for a specific repo. Thank you!
  • Mark
    Mark almost 7 years
    If you need multiple keys, the -i parameter can be repeated, and ssh will try each key in turn. git config core.sshcommand "ssh -i /path/to/keyA -i /path/to/keyB". This lets git use different keys with different remote hosts.
  • Laure
    Laure almost 7 years
    OMG why wouldn't it just tell me that the rights are wrong... It said its wrong first (warned) and then I've changed it. It didn't tell me next time saying me just that permission is denied.
  • Daniel Dewhurst
    Daniel Dewhurst over 6 years
    $ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch user@host' worked for me when nothing else would. Kudos.
  • Carl Smotricz
    Carl Smotricz over 6 years
    The URL for details ("itblog.study.land/...") doesn't work any more :(
  • Greg Dubicki
    Greg Dubicki over 6 years
    I had to use ~/.ssh/config method, env vars didn't work for me...
  • luator
    luator over 6 years
    For git versions < 2.3, you can use GIT_SSH (see other answers).
  • Dominik
    Dominik over 6 years
    GIT_SSH is available since v0.99.4 (August 2005), so basically since Git exists (April 2005).
  • VasyaNovikov
    VasyaNovikov over 6 years
    @ValentinKlinghammer the answer from @Flimm has the solution for this question. It is to use core.sshCommand git configuration. superuser.com/a/912281/162466
  • Sprachprofi
    Sprachprofi about 6 years
    You saved my life! Been struggling with different work and private Github & Heroku credentials for hours!!
  • Gomino
    Gomino about 6 years
    If you encounter the following error fatal: transport 'ext' not allowed, you have to whitelist the ext protocol via the export GIT_ALLOW_PROTOCOL=ext. Basically, the git-remote-ext remote helper (which supports "ext::ssh example.com %S foo/repo" URLs) allows arbitrary command execution. This normally isn't ever a concern because user always sees and trusts the URL they pass to git. However git submodules, through the .gitmodules file, allow an attacker to request the client to fetch arbitrary git URLs. hackerone.com/reports/104465
  • Scott - Слава Україні
    Scott - Слава Україні almost 6 years
    Did you notice that the question is about “a system with multiple private keys in the ~/.ssh directory”?
  • Cerin
    Cerin almost 6 years
    What is "git.example.com"? How would you use this with github or bitbucket, neither of which have a git.* subdomain?
  • Cerin
    Cerin almost 6 years
    This doesn't work when trying it with bitbucket, git clone 'ext::ssh -i /home/myuser/.ssh/id_rsa_customkey git.bitbucket.org %S repo/project.git' => Permission denied (publickey). fatal: Could not read from remote repository.
  • Cerin
    Cerin almost 6 years
    You should remove the first half of your answer. No one's interested in a solution that doesn't work, and it's wasted reading that obfuscates the correct answer at the bottom, which works wonderfully.
  • flaviovs
    flaviovs almost 6 years
    git.example.com is a placeholder host name. You must be able to ssh to the actual host for this to work, so I suggest you try ssh first using the specified key and get to the command line, double-check the actual path to the repository, and only then try to use the ext transport.
  • Jan Vlcinsky
    Jan Vlcinsky almost 6 years
    @Cerin If you mean removing the "Error to avoid" I am going to keep it there. It shares common pitfall to avoid and it is very short. I am sure, someone would try optimizing the solution by providing all the things into variable (this happened to me), so I tried to shorten the path to success.
  • Ondra Žižka
    Ondra Žižka over 5 years
    This is probably a good way, but my Git tries my default GitHub user, which has another key (GitHub wants unique-per-user keys). How can I make it use another user for other repo?
  • flaviovs
    flaviovs over 5 years
    @OndraŽižka, you can add -l USER to the ssh command line to log in as user USER.
  • nuno
    nuno over 5 years
    This worked for me - important to note that creating a directory inside .ssh and trying to organize keys inside directories would require to also change the permissions of that directory.
  • Allan Andrade
    Allan Andrade over 5 years
    This was my mistake: "If you already have a remote set up...". Thanks a lot!!!
  • Tyler Collier
    Tyler Collier over 5 years
    For me GIT_SSH_COMMAND didn't work until I used IdentitiesOnly, such as this command: GIT_SSH_COMMAND="ssh -i ~/.ssh/mysubdir/id_rsa -o 'IdentitiesOnly yes'" git push.
  • thucnguyen
    thucnguyen over 5 years
    @CarlSmotricz the original one was moved here: medium.com/@thucnc/…
  • Mageician
    Mageician over 5 years
    FINALLY!!! This answer actually shows how you can utilize what you put in the ~/.ssh/config file. Every other answer misses how you can set the host when you add the origin, which automatically allows git to use the correct key file. THANK YOU!!
  • Goddard
    Goddard over 5 years
    none worked for me...not sure why
  • Lucas D'Avila
    Lucas D'Avila about 5 years
    Nice, that was what I was looking :)
  • Srikrushna
    Srikrushna about 5 years
    Please explain the process including How can I create an agent
  • Scott - Слава Україні
    Scott - Слава Україні about 5 years
    (1) Are you quoting somebody or something? If so, please identify the source. If not, please don’t use quote formatting.  (2) What is “ed25519”? … … … … … … … … … … … Please do not respond in comments; edit your answer to make it clearer and more complete.
  • Goddard
    Goddard about 5 years
    common mistake---this is the answer
  • eigenfield
    eigenfield almost 5 years
    This is the best answer. The use of the environment variable via export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_otherkey" is so handy and flexible. I don't like setting multiple github keys in configuration .ssh/config because I also have to alias the github url for example, github.com becomes github.com.smeagol just to differentiate and this alias URL becomes your git remote address.
  • Cerin
    Cerin almost 5 years
    This forces git to use a specific key for an entire domain, which usually won't work. For example, if someone has a personal github account as well as a work account, this configuration will break one of them.
  • Ding-Yi Chen
    Ding-Yi Chen over 4 years
    This is especially useful when debugging git ssh. I can add -vvv to increase verbose mode.
  • Arka Prava Basu
    Arka Prava Basu over 4 years
    Hi !! Do you know how to propagate this to a submodule?
  • Ross
    Ross about 4 years
    Won't work with GIT LFS
  • Zeth
    Zeth almost 4 years
    Sounds smart, - but maybe a little to good to be true, considering how clumbsy all the other answers are. I couldn't get this to work.
  • JimmyJames
    JimmyJames over 3 years
    This answer deserves way more upvotes.
  • Muhamed Huseinbašić
    Muhamed Huseinbašić over 3 years
    Why are you adding the -F flag? To make sure no other config is used aside from the one explicitly mentioned?
  • Flimm
    Flimm over 3 years
    @MuhamedHuseinbašić Yes.
  • pwned
    pwned over 3 years
    This answer is outdated.
  • pwned
    pwned over 3 years
    Tgus answer is outdated.
  • kenorb
    kenorb over 3 years
    @pwned Which part?
  • pwned
    pwned over 3 years
    @kenorb the part which doesn't suggest core.sshCommand
  • kas
    kas over 3 years
    The user option is not required since you're passing the user in the git clone command.
  • Jinmiao Luo
    Jinmiao Luo over 3 years
    @Zeth You may have a problem when creating the ssh agent. If you are using MacOS, you only need to execute ssh-agent. If you are using Linux, I suggest you read this article wiki.archlinux.org/index.php/SSH_keys#ssh-agent
  • therobyouknow
    therobyouknow over 3 years
    +1 upvote great answer, it helped me also, I've used this and found this to work. 2 additional tips: 1) slightly different for bitbucket, repos are identified by project/repo-name, so my git origin looks like: git@therobyouknow:therobyouknow/myproject.git (where the first therobyouknow is the Host in config and the 2nd therobyouknow is the bitbucket project.
  • therobyouknow
    therobyouknow over 3 years
    Tip 2) and essential: if you have other Host * also in your config, whereby you want to use that for all over remote machines, except for your gitlab/bitbucket/github, then you need to make sure you exclude that config from Host * and I did this by changing Host * to Host !bitbucket.org which meant that its config doesnt "bleed" into my bitbucket config. See My comment here to the original answer there I want to give credit for here for this idea
  • therobyouknow
    therobyouknow over 3 years
    To clarify Tip 2) further: from what I've found, it does the same job as Host * !bitbucket.org (which itself didn't work for me) but without the *, so what Host !bitbucket.org(which did work for me) is saying is: " Host * - everything except for bitbucket.org " - the * - meaning "everything", though absent, is still in effect and implied.
  • Maddes
    Maddes over 3 years
    Just for your interest: A Match Path feature for OpenSSH would not help here, see marc.info/?l=openssh-unix-dev&m=141833748901966&w=2
  • Jakob
    Jakob over 3 years
    With Windows that would be -F nul, but with OpenSSH one can use -F none
  • user905686
    user905686 about 3 years
    Regarding contacting the same host with different keys: Here it is essential to understand that in .ssh/config Host is a custom name you can give to the host specified under HostName. The github.com part in the git URL [email protected]:torvalds/linux.git refers to this Host and thus has to match it exactly. If you have a second Github ssh key, you can create a section Host github2 in .ssh/config and then use the URL git@github2:torvalds/linux.git (see also superuser.com/a/1519694/96128).
  • Aspiring Dev
    Aspiring Dev about 3 years
    This is it. There's no git command hacks no nothing. This is it. Thank you.
  • Vadim
    Vadim almost 3 years
    Brilliant stuff.
  • Tony Park
    Tony Park almost 3 years
    This was particularly useful setting up a CICD pipeline that pulled multiple projects from github. Github insists on using a separate deploy key per project, and using these custom hosts is how I get the pipeline to use the right keys per project.
  • jherek
    jherek almost 3 years
    The full process is also documented on chasethedevil.github.io/post/github-and-ssh (which uses the same trick)
  • nick-s
    nick-s almost 3 years
    I spent hours looking for a solution and this was the easiest. Works like a charm for setting different ID files using a shell function by just setting the env var.
  • Toto
    Toto over 2 years
    You answer is really short for a very old question that has many documented answers.
  • Arnold Parge
    Arnold Parge over 2 years
    Useful answer. In addition, in Mac -F /dev/null is not required.
  • toryan
    toryan over 2 years
    If it was my question, I would mark this as the correct answer. Cheers!
  • Tyson Phalp
    Tyson Phalp over 2 years
    Incredible. Thanks for this--this worked for me, and felt the most straight-forward.
  • m8labs
    m8labs over 2 years
    Or just git remote add origin git@personal:username/my-personal-project.git
  • shrimpwagon
    shrimpwagon over 2 years
    This is hands down the way to do it especially if you use deployment keys in Github
  • RicarHincapie
    RicarHincapie over 2 years
    Excellent. I didn't wanted to remember to modify the default cloning string, so as host I set the same that appears in the original cloning string and works perfect and don't have to clone anything again.
  • SamAko
    SamAko over 2 years
    Great, this worked super well for me as I already had git config files for work and personal projects.
  • Coco
    Coco over 2 years
    Or you can git remote set-url origin git@personal:username/my-personal-project.git for an existing project
  • Adrian Herscu
    Adrian Herscu about 2 years
    TortoiseGit does not like this :(
  • nyxz
    nyxz about 2 years
    @AdrianHerscu I believe it should be fine if your TurtoiseGit uses the same SSH client as git. See the following answer stackoverflow.com/a/33328628/776546
  • Admin
    Admin almost 2 years
    I have created an account just to upvote this...
  • Admin
    Admin almost 2 years
    This is the best and most flexible answer. +1