Git over SSH: how to use SSH with GitHub, GitLab, and Bitbucket
Quick Answer: Git over SSH uses key-based authentication instead of passwords. Generate an SSH key pair, add the public key to your GitHub/GitLab/Bitbucket account, and clone repositories using the git@github.com:username/repo.git format. After setup, every git push and git pull runs without prompting for credentials.
When you clone a repository using HTTPS, Git asks for your credentials on every push. Since GitHub removed password authentication in 2021, HTTPS now requires a Personal Access Token — which is just another credential to manage, store securely, and rotate when it expires.
SSH authentication solves this permanently. You generate a key pair once, add the public key to your account, and from that point on git push just works.
SSH vs HTTPS for Git: quick comparison
| | SSH | HTTPS |
|---|---|---|
| Authentication | Private key (stored locally) | Password or Personal Access Token |
| Credential prompts | None after setup | Every push (unless cached) |
| Setup effort | One-time, ~5 minutes | Immediate, but token management ongoing |
| Firewall issues | Port 22 may be blocked on some networks | Port 443, almost never blocked |
| Multiple accounts | Easy with ~/.ssh/config | Awkward with credential managers |
| Recommended for | Daily development work | CI/CD pipelines, read-only cloning |
The short version: use SSH for day-to-day development. Use HTTPS tokens for automated pipelines where you cannot use key files.
Step 1: Generate an SSH key pair
If you already have an Ed25519 key at ~/.ssh/id_ed25519, you can reuse it. To create a dedicated key for Git services (recommended if you want separate keys per service):
macOS / Linux:
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/github-key
Windows (PowerShell or Git Bash):
ssh-keygen -t ed25519 -C "your_email@example.com" -f "$env:USERPROFILE\.ssh\github-key"
This creates two files:
github-key— your private key. Never share this. Never copy it to a remote server.github-key.pub— your public key. This goes on the hosting service.
Use Ed25519 rather than RSA. It produces smaller keys, signs faster, and avoids the SHA-1 deprecation issue that breaks old RSA keys on modern OpenSSH servers. See our RSA vs Ed25519 comparison for the full breakdown.
Step 2: Add the public key to your account
GitHub
Copy your public key to the clipboard:
macOS:
cat ~/.ssh/github-key.pub | pbcopy
Linux:
cat ~/.ssh/github-key.pub | xclip -selection clipboard
# or
cat ~/.ssh/github-key.pub | xsel --clipboard --input
Windows (PowerShell):
Get-Content "$env:USERPROFILE\.ssh\github-key.pub" | Set-Clipboard
Then:
- Go to github.com → profile picture → Settings
- Click SSH and GPG keys in the left sidebar
- Click New SSH key
- Give it a descriptive title (e.g. "MacBook Pro 2026" or "Work Windows Laptop")
- Paste the public key → click Add SSH key
GitLab
- Go to gitlab.com → profile picture → Preferences
- Click SSH Keys in the left sidebar
- Paste the public key, optionally set an expiry date → click Add key
Bitbucket
- Go to bitbucket.org → profile picture → Personal settings
- Click SSH keys under Security
- Click Add key → paste the public key → click Add key
Step 3: Test the connection
Before cloning anything, verify the key works:
# GitHub
ssh -T git@github.com
# GitLab
ssh -T git@gitlab.com
# Bitbucket
ssh -T git@bitbucket.org
GitHub responds with:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
The "does not provide shell access" message is expected. You are authenticated as the git system user — the hosting service maps your key to your account.
If you get "Permission denied (publickey)", see the troubleshooting section below.
Step 4: Configure SSH to use your key
If you named your key file something other than the default (id_ed25519), add this to ~/.ssh/config so SSH knows which file to use:
macOS / Linux — edit ~/.ssh/config:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github-key
AddKeysToAgent yes
Windows — edit C:\Users\YourName\.ssh\config (create it if it doesn't exist):
Host github.com
HostName github.com
User git
IdentityFile C:/Users/YourName/.ssh/github-key
On Windows, use forward slashes in the IdentityFile path even though Windows normally uses backslashes. The OpenSSH client on Windows handles this correctly.
Step 5: Clone using SSH
On GitHub, click the Code button on any repository, switch from HTTPS to SSH, and copy the URL. The format is:
git clone git@github.com:username/repository.git
For an existing repository cloned via HTTPS, update the remote URL:
git remote set-url origin git@github.com:username/repository.git
git remote -v # verify the change
Using the SSH agent
If your private key has a passphrase (it should), your system will ask for it the first time you use the key in each session. The SSH agent caches the decrypted key in memory so you only enter the passphrase once.
macOS / Linux:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/github-key
On macOS, add this to ~/.ssh/config to persist across reboots:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github-key
AddKeysToAgent yes
UseKeychain yes
UseKeychain yes stores the passphrase in the macOS Keychain. On Linux, add ssh-add ~/.ssh/github-key to your ~/.bashrc or ~/.zshrc so the key loads on every terminal session.
Windows: The OpenSSH Authentication Agent service handles this. Start it once in PowerShell as admin, then add your key:
# Enable and start the agent service
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
# Add your key
ssh-add "$env:USERPROFILE\.ssh\github-key"
After this, Windows automatically uses the agent across sessions without re-prompting for the passphrase.
Managing multiple GitHub accounts
A common scenario: a personal GitHub account and a work GitHub account, each needing its own SSH key. SSH always sends one default key, so without configuration it will authenticate to whichever account that key belongs to.
Step 1: Generate two separate keys:
ssh-keygen -t ed25519 -C "personal@email.com" -f ~/.ssh/github-personal
ssh-keygen -t ed25519 -C "work@company.com" -f ~/.ssh/github-work
Step 2: Add each public key to the corresponding GitHub account.
Step 3: Create aliases in ~/.ssh/config:
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/github-personal
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/github-work
Step 4: Use the alias when cloning:
# Personal repository
git clone git@github-personal:your-personal-username/repo.git
# Work repository
git clone git@github-work:your-work-org/repo.git
Step 5: For existing repositories, update the remote:
git remote set-url origin git@github-personal:your-username/repo.git
SSH sees github-personal in the URL, looks it up in ~/.ssh/config, and uses ~/.ssh/github-personal as the key. Both accounts work from the same machine without interfering with each other.
Complete working config for GitHub + GitLab + multiple accounts
# Personal GitHub
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/github-personal
AddKeysToAgent yes
# Work GitHub
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/github-work
AddKeysToAgent yes
# GitLab
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/gitlab-key
AddKeysToAgent yes
# Self-hosted GitLab at your company
Host git.company.com
HostName git.company.com
User git
IdentityFile ~/.ssh/company-gitlab-key
Port 22
# Global defaults
Host *
ServerAliveInterval 60
AddKeysToAgent yes
Switching all existing repos from HTTPS to SSH
To update all local repositories in a directory from HTTPS to SSH at once:
find . -name ".git" -type d | while read gitdir; do
repo="$(dirname "$gitdir")"
cd "$repo"
current=$(git remote get-url origin 2>/dev/null)
if [[ "$current" == https://github.com/* ]]; then
new="${current/https:\/\/github.com\//git@github.com:}"
git remote set-url origin "$new"
echo "Updated: $repo → $new"
fi
cd - > /dev/null
done
Run this from a parent directory containing multiple cloned repositories. It only modifies GitHub HTTPS remotes — adjust the pattern for GitLab or Bitbucket if needed.
Troubleshooting
"Permission denied (publickey)"
This is the most common error. Work through this checklist:
1. Check the key is added to your account. On GitHub: Settings → SSH keys. Make sure the key fingerprint matches your local key:
ssh-keygen -lf ~/.ssh/github-key.pub
2. Check SSH is trying the right key.
ssh -vv git@github.com 2>&1 | grep -i "identity\|offer\|auth"
If SSH is not trying the key you expect, your ~/.ssh/config may be missing or using the wrong IdentityFile path.
3. Check the SSH agent has the key loaded.
ssh-add -l
If the output says "The agent has no identities", add your key: ssh-add ~/.ssh/github-key.
4. Check file permissions (macOS/Linux).
chmod 700 ~/.ssh
chmod 600 ~/.ssh/github-key
chmod 644 ~/.ssh/github-key.pub
If permissions are too open, SSH silently ignores the key.
"Warning: Permanently added 'github.com' to the list of known hosts"
Normal — SSH stores the server's fingerprint in ~/.ssh/known_hosts the first time you connect to detect future changes.
"Host key verification failed"
GitHub occasionally rotates its SSH host keys. If your ~/.ssh/known_hosts has an old fingerprint, you will see this error. Remove the old entry and reconnect:
ssh-keygen -R github.com
ssh -T git@github.com # accept the new fingerprint
Always verify the new fingerprint against the official list published by the service before accepting.
SSH on port 443 (when port 22 is blocked)
Some corporate firewalls block port 22. GitHub supports SSH over port 443 as a fallback:
Host github.com
HostName ssh.github.com
User git
Port 443
IdentityFile ~/.ssh/github-key
This connects to ssh.github.com:443 which behaves identically to github.com:22 from Git's perspective.