Issue
I have two types of Repositories on the same host with different beginning remote url:
github.com/foo/bar.git
github.com/foo/foo.git
github.com/bar/bar.git
github.com/bar/foo.git
And I want git to automatically select the identity and ssh-key depending on the current remote url. Is this even possible?
Solution
The ssh identity selection is a little bit complicated, but there are several ways to make this work. The easiest one is this: you don't do it based on the real GitHub URL, but rather on a sort of a fake URL:
ssh://gh-id1/user1/repo.git
vs:
ssh://gh-id2/user2/repo.git
In your ssh config file, you write, for instance:
Host gh-id1
Hostname github.com
User git
IdentityFile ~/.ssh/id-user1.rsa.pub
IdentitiesOnly yes
Host gh-id2
Hostname github.com
User git
IdentityFile ~/.ssh/id-user2.rsa.pub
IdentitiesOnly yes
The concept here is that Git asks ssh to connect to the bogus host name gh-id1
or gh-id2
(you choose the actual host name, these are just examples). When ssh gets this request, ssh reads its own config file and says: Aha, you don't really want gh-id1
, you really want [email protected]
.
The git@
part comes from the User
line in ~/.ssh/config
, which is optional. If you don't use it in the .ssh/config
file, you must set up the Git URL as ssh://git@gh-id1
.
The IdentityFile
line tells ssh which key to offer to github.com
. The IdentitiesOnly
line tells ssh not to try other keys. That way you're guaranteed to try only the keys listed in IdentityFile
lines. GitHub decides whether you are you (Fred Flintstone), your wife (Wilma Flintstone), your neighbor Barney, etc., based on which key you show them, rather than who you really are, so by controlling which key you show them, you make sure you get identified as the person you'd like to claim to be.
Note that Git's only role in this entire process is that Git asks ssh to connect to some fake, bogus host name that you made up, that you control, that you list in your .ssh/config
file. Git itself is not doing any authentication here: it's pawning the entire job off onto ssh.
You can trigger this with insteadOf
To make the above work, you would in general set the stored URL of some repository to ssh://gh-id1/user1/repo.git
for instance. You could do this with git remote set-url origin ssh://gh-id1/user1/repo.git
, or by cloning ssh://gh-id1/user1/repo.git
initially.
Note that if your goal is to do this based on the github.com/foo
vs github.com/bar
parts of the URL, you can combine the above trick with Git's insteadOf
so that you don't have to alter the stored URL in any way. The insteadOf
replacement trick is described in the git config
documentation:
url.base.insteadOf
Any URL that starts with this value will be rewritten to start, instead, withbase
. In cases where some site serves a large number of repositories, and serves them with multiple access methods, and some users need to use different access methods, this feature allows people to specify any of the equivalent URLs and have Git automatically rewrite the URL to the best alternative for the particular user, even for a never-before-seen repository on the site. When more than oneinsteadOf
strings match a given URL, the longest match is used.
So here you might write:
git config --global url.ssh://gh-user1/foo/.insteadOf ssh://github.com/foo/
to transform ssh://github.com/foo/repo.git
to ssh://gh-user1/foo/repo.git
. See also How to convert `git:` urls to `http:` urls and How do I get git to default to ssh and not https for new repositories for related (but different) examples.
If that's not enough
If for some reason you need really complex manipulations of ssh URLs, you can direct Git to run, not the system ssh
command, and not any Git-for-Windows provided ssh
command, but rather your own custom-made ssh
program. This program can do literally anything you like with its arguments, as long as it winds up implementing or running ssh
in the end. So you could write a script or program—making it as dumb or smart as you like—that finds the URL, rewrites it, and then invokes the system ssh.
To do this, first write your own program and verify that it works:
my-fake-ssh ssh://github.com/foo/bar.git
my-fake-ssh [email protected]/foo/bar.git
and so on. Then simply set core.sshCommand
to my-fake-ssh
:
git config --global core.sshCommand my-fake-ssh
Git will now run your program instead of Git's default, built-in ssh.
(To control the key you offer here, consider using ssh
's -i
option.)
Answered By - torek Answer Checked By - Mildred Charles (WPSolving Admin)