I have the following use case: I would like to be able to push to git@git.company.com:gitolite-admin
using the private key of user gitolite-admin
, while I want to push to git@git.company.com:some_repo
using 'my own' private key. AFAIK, I can't solve this using ~/.ssh/config
, because the user name and server name are identical in both cases. As I mostly use my own private key, I have that defined in ~/.ssh/config
for git@git.company.com
. Does anyone know of a way to override the key that is used for a single git
invocation?
(Aside: gitolite distinguishes who is doing the pushing based on the key, so it's not a problem, in terms of access, ownership and auditing, that the user@server string is identical for different users.)
Even if the user and host are the same, they can still be distinguished in ~/.ssh/config
. For example, if your configuration looks like this:
Host gitolite-as-alice
HostName git.company.com
User git
IdentityFile /home/whoever/.ssh/id_rsa.alice
IdentitiesOnly yes
Host gitolite-as-bob
HostName git.company.com
User git
IdentityFile /home/whoever/.ssh/id_dsa.bob
IdentitiesOnly yes
Then you just use gitolite-as-alice
and gitolite-as-bob
instead of the hostname in your URL:
git remote add alice git@gitolite-as-alice:whatever.git
git remote add bob git@gitolite-as-bob:whatever.git
Note
You want to include the option IdentitiesOnly yes
to prevent the use of default ids. Otherwise, if you also have id files matching the default names, they will get tried first because unlike other config options (which abide by "first in wins") the IdentityFile
option appends to the list of identities to try. See: https://serverfault.com/questions/450796/how-could-i-stop-ssh-offering-a-wrong-key/450807#450807
You can utilize git environment variable GIT_SSH_COMMAND
. Run this in your terminal under your git repository:
GIT_SSH_COMMAND='ssh -i ~/.ssh/your_private_key' git submodule update --init
Replace ~/.ssh/your_private_key
with the path of ssh private key you wanna use. And you can change the subsequent git command (in the example is git submodule update --init
) to others like git pull
, git fetch
, etc.
-F /dev/null
Configure your repository using git config
git config --add --local core.sshCommand 'ssh -i <<<PATH_TO_SSH_KEY>>>'
This applies to your local repository only.
An alternative approach to the one offered above by Mark Longair is to use an alias that will run any git command, on any remote, with an alternative SSH key. The idea is basically to switch your SSH identity when running the git commands.
Advantages relative to the host alias approach in the other answer:
Will work with any git commands or aliases, even if you can't specify the remote explicitly.
Easier to work with many repositories because you only need to set it up once per client machine, not once per repository on each client machine.
I use a few small scripts and a git alias admin
. That way I can do, for example:
git admin push
To push to the default remote using the alternative ("admin") SSH key. Again, you could use any command (not just push
) with this alias. You could even do git admin clone ...
to clone a repository that you would only have access to using your "admin" key.
Step 1: Create the alternative SSH keys, optionally set a passphrase in case you're doing this on someone else's machine.
Step 2: Create a script called “ssh-as.sh” that runs stuff that uses SSH, but uses a given SSH key rather than the default:
#!/bin/bash
exec ssh ${SSH_KEYFILE+-i "$SSH_KEYFILE"} "$@"
Step 3: Create a script called “git-as.sh” that runs git commands using the given SSH key.
#!/bin/bash
SSH_KEYFILE=$1 GIT_SSH=${BASH_SOURCE%/*}/ssh-as.sh exec git "${@:2}"
Step 4: Add an alias (using something appropriate for “PATH_TO_SCRIPTS_DIR” below):
# Run git commands as the SSH identity provided by the keyfile ~/.ssh/admin
git config --global alias.admin \!"PATH_TO_SCRIPTS_DIR/git-as.sh ~/.ssh/admin"
More details at: http://noamlewis.wordpress.com/2013/01/24/git-admin-an-alias-for-running-git-commands-as-a-privileged-ssh-identity/
$@
-> "$@"
to be safe.
I've cribbed together and tested with github the following approach, based on reading other answers, which combines a few techniques:
correct SSH config
git URL re-writing
The advantage of this approach is, once set up, it doesn't require any additional work to get it right - for example, you don't need to change remote URLs or remember to clone things differently - the URL rewriting makes it all work.
~/.ssh/config
# Personal GitHub
Host github.com
HostName github.com
User git
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/github_id_rsa
# Work GitHub
Host github-work
HostName github.com
User git
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/work_github_id_rsa
Host *
IdentitiesOnly yes
~/.gitconfig
[user]
name = My Name
email = personal@personal.email
[includeIf "gitdir:~/dev/work/"]
path = ~/dev/work/.gitconfig
[url "github-work:work-github-org/"]
insteadOf = git@github.com:work-github-org/
~/dev/work/.gitconfig
[user]
email = work@work.email
As long as you keep all your work repos under ~/dev/work and personal stuff elsewhere, git will use the correct SSH key when doing pulls/clones/pushes to the server, and it will also attach the correct email address to all of your commits.
References:
1
2
includeIf
should only work if there's a .git
directory present I thought?
UseKeychain
line. For more info: stackoverflow.com/a/47455373/2037998
From git 2.10 upwards it is also possible to use the gitconfig sshCommand setting. Docs state :
If this variable is set, git fetch and git push will use the specified command instead of ssh when they need to connect to a remote system. The command is in the same form as the GIT_SSH_COMMAND environment variable and is overridden when the environment variable is set.
An usage example would be: git config core.sshCommand "ssh -i ~/.ssh/[insert_your_keyname]
In some cases this doesn't work because ssh_config overriding the command, in this case try ssh -i ~/.ssh/[insert_your_keyname] -F /dev/null
to not use the ssh_config.
One Unix based systems (Linux, BSD, Mac OS X), the default identity is stored in the directory $HOME/.ssh, in 2 files: private key: $HOME/.ssh/id_rsa public key: $HOME/.ssh/id_rsa.pub
When you use ssh
without option -i
, it uses the default private key to authenticate with remote system.
If you have another private key you want to use, for example $HOME/.ssh/deploy_key, you have to use ssh -i ~/.ssh/deploy_key ...
It is annoying. You can add the following lines in to your $HOME/.bash_profile : ssh-add ~/.ssh/deploy_key ssh-add ~/.ssh/id_rsa
So each time you use ssh
or git
or scp
(basically ssh
too), you don't have to use option -i
anymore.
You can add as many keys as you like in the file $HOME/.bash_profile.
Another alternative is to use ssh-ident, to manage your ssh identities.
It automatically loads and uses different keys based on your current working directory, ssh options, and so on... which means you can easily have a work/ directory and private/ directory that transparently end up using different keys and identities with ssh.
I am using Git Bash on Win7. The following worked for me.
Create a config file at ~/.ssh/config or c:/users/[your_user_name]/.ssh/config. In the file enter:
Host your_host.com
IdentityFile [absolute_path_to_your_.ssh]\id_rsa
I guess the host has to be a URL and not just a "name" or ref for your host. For example,
Host github.com
IdentityFile c:/users/[user_name]/.ssh/id_rsa
The path can also be written in /c/users/[user_name]/.... format
The solution provided by Giordano Scalzo is great too. https://stackoverflow.com/a/9149518/1738546
One possibility to use ~/.ssh/config
is to use the Match
restriction instead of the Host
restriction. In particular Match Exec
calls a shell command to decide whether to apply the declarations or not. In bash you could use the following command:
[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]
This uses the bash [
command to verify if two strings are equal. In this case it is testing if the string git@git.company.com:gitolite-admin
matches the output that is obtained from the $(git config --get remote.origin.url)''
command.
You can use any other command that identifies the repository that the shell is on. For this to work it is important to have the $SHELL
variable defined to your shell, in my case /bin/bash
. The full example would then be the following ~/.ssh/config
:
Match Exec "[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]"
IdentityFile ~/.ssh/gitolite-admin
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no
Match Exec "[ git@git.company.com:some_repo = $(git config --get remote.origin.url)'' ]"
IdentityFile ~/.ssh/yourOwnPrivateKey
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no
In this example I assumed that ~/.ssh/yourOwnPrivateKey
contains your own private key and that ~/.ssh/gitolite-admin
contains the private key of the user gitolite-admin
. I included the IdentitiesOnly yes
declaration to make sure that only one key is offered to the git server, mentioned by Mark Longair. The other declarations are just standard ssh options for git.
You can add this configuration if you have several some_repo
that you want to use with different keys. If you have several repositories at git@git.company.com
and most of them use the ~/.ssh/yourOwnPrivateKey
it makes more sense to include this key as default for the host. In this case the ~/.ssh/config
would be:
Match Exec "[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]"
IdentityFile ~/.ssh/gitolite-admin
IdentitiesOnly yes
Host git.company.com
IdentityFile ~/.ssh/yourOwnPrivateKey
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no
Note that the order matters and the Host git.company.com
restriction should appear after the Match Exec
one or ones.
Host
value in Host gitolite-as-alice
(ignoring HostName
) but this method avoids that problem! Note that you can also use wildcard to match: Match Exec "[[ $(git config --get remote.origin.url)'' == 'git@github.com:YourOrganization'* ]]"
Match Exec "[[ $(git config --get remote.origin.url)'' == 'git@github.com:YourOrganization'* ]]"
Bash
then the conditional can be as simple as this: Match Exec "[[ $(git config --get remote.origin.url) == git@github.com:YourOrganization/* ]]"
(notice the trailing slash after the org name so it doesn't overlap with YourOrganizationAnother
)
To use a specific key on the fly:
GIT_SSH_COMMAND='ssh -i $HOME/.ssh/id_ed25519 -o IdentitiesOnly=yes -F /dev/null' git push origin c13_training_network
Explanation:
local ENV var before doing the push
-i specifies key
-F forces an empty config so your global one doesn't overwrite this temporary command
As someone else mentioned, core.sshCommand
config can be used to override SSH key and other parameters.
Here is an exmaple where you have an alternate key named ~/.ssh/workrsa
and want to use it for all repositories cloned under ~/work
.
Create a new .gitconfig file under ~/work:
[core]
sshCommand = "ssh -i ~/.ssh/workrsa"
In your global git config ~/.gitconfig, add:
[includeIf "gitdir:~/work/"]
path = ~/work/.gitconfig
If you already have default ssh key config but want to use different for specific repository then this should do the trick:
git config core.sshCommand "ssh -i ~/.ssh/github-personal -o IdentitiesOnly=yes -F /dev/null"
If using Git's version of ssh on windows, the identity file line in the ssh config looks like
IdentityFile /c/Users/Whoever/.ssh/id_rsa.alice
where /c
is for c:
To check, in git's bash do
cd ~/.ssh
pwd
https://i.stack.imgur.com/hb86h.png
For git to figure out, that it should use a different SSH keys, apart from changing your config file, as mentioned here: https://stackoverflow.com/a/7927828/1306884 you may also need to purge and reload an active SSH identities.
On Mac, do the following:
ssh-add -D
ssh-add ~/.ssh/id_rsa_one_that_you_want_to_use_instead
Using these two commands, and setting up the GIT URL to match the string defined in the Host
of the ssh/config file, should allow you to use different SSH keys, for a different repositories.
For example for Host work.github.com
use work.github.com
as an URL when cloning your repository git@work.github.com:your/repository.git
.
you most specified in the file config key ssh:
# Default GitHub user
Host one
HostName gitlab.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/key-one
IdentitiesOnly yes
#two user
Host two
HostName gitlab.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/key-two
IdentitiesOnly yes
Note: There's a way to apply the git config proposed in a previous answer for directories, not just at the repo level.
In my case, all projects were under the ~/work/
directory, so I updated my gitconfig as follows:
# ~/.gitconfig
...
[includeIf "gitdir:~/work/**"]
path = "~/work/.gitconfig"
# ~/work/.gitconfig
[user]
email = amr@work.com
name = Amr Awad
sshCommand = ssh -i ~/.ssh/work
and now all repos inside the ~/work/
directory use the work key ~/.ssh/work
without the need for configuring each repo separately.
here is the simple approach :
-From your local root git folder.
-Check the current type of authentication method HTTPS or SSH of your local repository.
git remote -v
Example using HTTPS:
origin https://github.com/juantorres9/SQLite_crash_cours.git (fetch)
origin https://github.com/juantorres9/SQLite_crash_cours.git (push)
Example using SSH:
origin git@github.com:juantorres9/SQLite_crash_cours.git (fetch)
origin git@github.com:juantorres9/SQLite_crash_cours.git (push)
-Set the authentication method of your choice in case it's not already set.
For setting SSH
git remote set-url origin git@github.com:USERNAME/REPOSITORY.git
For setting HTTPS
git remote set-url origin https://github.com/USERNAME/REPOSITORY.git
-Check again in case you want to double check
git remote -v
-You are now able to use git push:fetch using your configured method.
git push origin master
Note Last but not least , check updated official doc https://docs.github.com/en/get-started/getting-started-with-git/managing-remote-repositories
Success story sharing
git@
part in the remote is not necessary as it is given in theUser
line of the config.IdentitiesOnly yes
immediately after the line withIdentityFile
for the host. It seems it was passing along multiple identities and one of those was blocked from accessing the host.