Friday, October 28, 2022

[SOLVED] Select configuration depending on remote url

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, with base. 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 one insteadOf 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)