ssh-Based git Upstreams with Multiple Identities
I have largely given up on self-hosting version control systems for the part of my stuff that the general public might want to look at. In this game, it's platforms[1] exclusively nowadays, as there is no way anyone would find the material anywhere else.
That, of course, is a severe privacy problem, even when the platform itself is relatively benevolent (i.e., codeberg). For people like me – spending a significant part of their lives at the keyboard and version-controlling a significant part of the keystrokes, the commit history says a lot about their lives, quite likely a lot more than they care to publicly disclose.
As a partial mitigation, I am at least using different accounts for different functions: work, hacking, politics, the lot. The partial commit histories are decidedly less telling than a global commit history would be.
However, this turns out to be trickier than you might expect, which is why I am writing this post.
First off, the common:
git config user.name "Anselm Flügel" git config user.email zuengeln@tfiu.de
does not have anything to do with the platform accounts. It only changes the authorships in the log entries, and you are completely free to put anything at all there. The account used for pushing – and hence the source of the platforms' user history and activity images (see above) is absolutely unrelated to the commits' user.name-s. Instead, the account name is, in effect, encoded in the URI of the remote; and that is where things become subtle.
Because, you see, there is no useful user name in:
$ git remote get-url origin git@codeberg.org:AnselmF/crapicity.git
The AnselmF in there is part of the repo path; you can push into other peoples' repos if they let you, so that cannot be the source of the user name. And the “git@” at the start, while it looks like a username and actually is one, is the same for everyone.
So, how do github, codeberg and their ilk figure out which account to do a push under? Well: They use the ssh key that you uploaded into your profile. Since each ssh key can only be assigned to one account, the platforms can deduce the account from the fingerprint of the public key that ssh presents on connecting.
Historical note: the big Debian SSL disaster 16 years ago, where Debian boxes would only generate a very small number of distinct secret keys (thus making them non-secret), was uncovered in this way, as just when the early github phased in this scheme, impossibly many keys from different persons turned out to have the same fingerprint. Matt Palmer recently related how in his work at github he worked out Debian's broken random number generator back then.
In practice, this means that when you want to have multiple accounts on a single platform, after you have created a new account, you need to create a new ssh key associated with it (i.e., the new account), preferably with a name that roughly matches its intended use:
cd ~/.ssh ssh-keygen -t ed25519 -f id_anselm
This will leave the public key in ~/.ssh/id_anselm.pub; the contents of that file will go into (say) codeberg's SSH key text box (look for the “Keys” section in your “Settings”).
This still is not enough: ssh will by default try all the keys you have in ~/.ssh in a deterministic order. This means that you will still always be the same user as long as you use a remote URL like git@codeberg.org:AnselmF/crapicity.git – the user the public key of which is tried first. To change this, you must configure ssh to use your account-specific key for some bespoke remote URIs. The (I think) simplest way to do that is to invent a hostname in your ~/.ssh/config, like this:
Host codeberg-anselm HostName codeberg.org User git IdentitiesOnly yes IdentityFile ~/.ssh/id_anselm
This lets you choose your upstream identity using the authority part of the remote URI; use (in this case) codeberg-anselm rather than codeberg.org to work with your new account. Of course the URIs you paste from codeberg (or github or whatever) will not know about this. Hence, you will normally have to manually configure the remote URI, with a (somewhat hypothetical) command sequence like this:
git clone git@codeberg.org:AnselmF/crapicity.git # pasted URI git remote set-url origin git@codeberg-anselm:AnselmF/crapicity.git
After that, you will push and pull using the new account.
[1] | Well, at this point it is, if I have to be absolutely honest, one platform largely, but I outright refuse to acknowledge that. |