Enforce SSH instead of HTTPS for Git operations
GitHub stopped accepting passwords for Git this month. Keys were the better answer anyway — here is a setup that also survives tools with HTTPS URLs baked in.
Ten days ago GitHub stopped accepting account passwords for Git operations over HTTPS. If you push over HTTPS you now paste a personal access token instead — a longer secret, kept in the same place the password was, expiring on a schedule you have to remember.
SSH avoids the question. You generate a key pair once, keep the private half on your machine, hand the public half to the host, and stop typing credentials for Git entirely. It also authenticates the server to you, which a token does not.
Setup takes about five minutes. The last two steps are the ones most guides leave out, and they are the reason this sticks.
Generate a key
ssh-keygen -t ed25519 -C "personal github" -f ~/.ssh/personal-github
Ed25519 rather than RSA: shorter keys, faster handshakes, and no key-size
argument to get wrong. If you have to talk to something older than OpenSSH 6.5,
-t rsa -b 4096 is the fallback.
Name the key after what it unlocks — personal-github, work-gitlab — and
make one per account rather than one per machine. Accounts get revoked
individually, and a key named id_ed25519_2 tells you nothing on the day you
need to revoke it.
Use a passphrase. The agent means you type it once per session, not once per push.
Add the public key to the host
Copy the public half — the file ending in .pub, never the other one:
pbcopy < ~/.ssh/personal-github.pub
Then paste it into your account settings: GitHub, GitLab, or Bitbucket.
Rewrite HTTPS URLs to SSH
A key does nothing while your remotes still say https://. Instead of fixing
them one repository at a time, tell Git to substitute globally, in
~/.gitconfig:
[url "ssh://git@github.com/"]
insteadOf = https://github.com/
[url "ssh://git@gitlab.com/"]
insteadOf = https://gitlab.com/
[url "ssh://git@bitbucket.org/"]
insteadOf = https://bitbucket.org/
Every HTTPS URL for those hosts is now rewritten before the request leaves your
machine — including the URLs you did not write. That covers CocoaPods specs,
go get, npm dependencies that point at a Git repository, submodules cloned
from someone else’s .gitmodules, and CI scripts you would rather not touch.
This is the step that turns “I set up a key” into “I never see a credential prompt again”.
Tell SSH which key to use
Git speaks SSH now, but SSH still has to choose a key. Left alone it tries the
default names, so a key called personal-github is never offered. In
~/.ssh/config:
Host github.com
User git
IdentityFile ~/.ssh/personal-github
IdentitiesOnly yes
AddKeysToAgent yes
Host gitlab.com
User git
IdentityFile ~/.ssh/work-gitlab
IdentitiesOnly yes
AddKeysToAgent yes
IdentitiesOnly yes earns its line. Without it SSH offers every key the agent
holds, in whatever order it likes, and a host that sees the wrong key first can
reject you before the right one is ever tried — which reads as a permissions
bug and is not one.
On macOS, add UseKeychain yes to each host block and the passphrase survives
a restart.
Check it
ssh -T git@github.com
A greeting with your username means the key works. To confirm the rewriting, clone something over HTTPS and watch it go through without a prompt:
git ls-remote https://github.com/omaralbeik/SwifterSwift.git
If that returns refs without asking for anything, both halves are in place: Git is rewriting the URL, and SSH is picking the right key for it.