A Git remote can use one of two URL schemes to talk to a host like GitHub: SSH or HTTPS. They do the same job (push and pull), but they authenticate differently. HTTPS uses your account plus a token (or a credential helper); SSH uses a key pair you generate once and register with the host. For most personal development either works. If you push many times a day and do not want to deal with tokens, set up an SSH key once and use SSH.
You can tell which scheme a remote uses by looking at its URL:
git remote -vorigin git@github.com:you/repo.git (fetch) # SSH
origin https://github.com/you/repo.git (fetch) # HTTPSAn SSH URL starts with git@host: and a colon before the path. An HTTPS URL starts with https:// and uses a slash. That is the fastest way to know what a clone is using.
How HTTPS authenticates
When you push over HTTPS, the host needs to confirm you are allowed to write to the repo. GitHub stopped accepting your account password for this in August 2021. You now authenticate with a personal access token (PAT) used in place of the password, and Git typically remembers it through a credential helper so you are not pasting it every time.
The first push prompts for credentials:
git push origin mainUsername for 'https://github.com': you
Password for 'https://you@github.com': <paste your personal access token here>To stop the prompts, enable a credential helper that stores the token. On macOS, Git ships with the Keychain helper:
git config --global credential.helper osxkeychainOn Linux, the libsecret helper or the cache helper both work:
git config --global credential.helper libsecretIf you ever paste your old password by reflex you will hit the error that Support for password authentication was removed covers. The fix there is the same idea: generate a token and use it as the password.
How SSH authenticates
SSH does not use your account password or a token at all. You generate a key pair once, keep the private key on your machine, and upload the public key to the host. After that, every push and pull authenticates silently with the key.
Generate a key with the modern Ed25519 type:
ssh-keygen -t ed25519 -C "you@example.com"Then add the public key (the .pub file) to your GitHub account. If you need the full cross-platform key-generation walkthrough first, here is how to create an SSH key on any OS; to register it, adding an SSH key to GitHub covers starting the agent and testing the connection. Once the key is registered you can confirm it works:
ssh -T git@github.comHi you! You've successfully authenticated, but GitHub does not provide shell access.That message is the success case. If you instead see Permission denied (publickey), the host could not match your key. The page on fixing Permission denied (publickey) walks through the usual causes: the agent is not running, the key was never uploaded, or the wrong key is being offered.
SSH vs HTTPS at a glance
| Aspect | SSH | HTTPS |
|---|---|---|
| URL format | git@github.com:you/repo.git | https://github.com/you/repo.git |
| Credential | Key pair (private key + uploaded public key) | Personal access token (used as the password) |
| Set up once | Generate key, upload .pub | Generate token, store via credential helper |
| Per-push friction | None after the key is loaded | None after the helper stores the token |
| Works behind strict firewalls | Sometimes blocked (port 22) | Usually fine (port 443) |
| Two-factor accounts | Key is unaffected by 2FA | Token required (password will not work) |
| Best for | Frequent pushing from your own machine | CI, locked-down networks, quick one-off clones |
Neither is more secure than the other in any meaningful sense for normal use; both encrypt the connection. The real differences are friction and network constraints.
When to pick which
Reach for SSH when the machine is yours and you push often. The one-time key setup pays for itself the first day. It also sidesteps token expiry: an Ed25519 key does not expire, so you are not regenerating tokens every few months.
Reach for HTTPS when:
- You are on a corporate or campus network that blocks outbound SSH (port 22). HTTPS over 443 almost always gets through. GitHub also offers SSH over the HTTPS port as a fallback if you must use keys on such a network.
- You are setting up CI or a build server, where a scoped token is easier to rotate and revoke than managing keys.
- You are doing a quick read-only clone of someone else's public repo and do not care about pushing. The same decision shows up the moment you clone: SSH vs HTTPS is a clone-time choice too, since the URL you copy determines the scheme.
If you are still getting your bearings with remotes generally, the Git for beginners guide covers what a remote is and how origin gets wired up in the first place. And if a clone of an existing project is where you are starting, see how to start working on an existing Git project.
Switching an existing remote between SSH and HTTPS
You do not have to re-clone to change schemes. Change the URL in place with git remote set-url.
To switch a remote from HTTPS to SSH:
git remote set-url origin git@github.com:you/repo.gitTo switch it back from SSH to HTTPS:
git remote set-url origin https://github.com/you/repo.gitConfirm the change took:
git remote -vNothing else moves. Your branches, history, and local config are untouched; only the address Git dials for origin changed. This is the cleanest fix when you cloned over HTTPS, got tired of the token prompts, and want to move to keys (or the reverse, when SSH is blocked on a new network).
If you have not added the remote at all yet, you use git remote add instead, which is part of adding Git to an existing project; and if Git complains that remote origin already exists, set-url is exactly the command that resolves it.
Deploy keys: SSH access scoped to one repo
A normal SSH key is tied to your account and can reach every repo you have access to. That is wrong for a server. If a production box only needs to pull one repository, you do not want a key on it that could touch everything you own.
A deploy key solves this. It is an SSH key pair registered against a single repository rather than your account. The server gets a key that can pull (and optionally push to) exactly that one repo and nothing else.
The setup is the same key generation, run on the server:
ssh-keygen -t ed25519 -C "deploy@myserver" -f ~/.ssh/deploy_myrepoThen add the public key in the repository's own settings (Settings, then Deploy keys on GitHub) instead of your account settings. Leave it read-only unless the server genuinely needs to push. Read-only is the right default for a deploy target that only pulls new code. The same access-control surface applies on the server side, where how a pre-receive hook can decline a push shows the host rejecting writes it does not want.
This pattern is the foundation of pull-based deployment. If you are building a deploy flow around it, deploying with a Git post-receive hook and push-to-deploy with GitHub Actions both build on a server that can authenticate to the repo without a human pasting credentials. On the security side, never commit a private key into the repo; the article on removing a secret from Git history exists because that mistake is common, and a leaked key is exactly the kind of thing the exposed .git directory attack feeds on.
A note on changing the URL after a security incident
If a token leaks, you revoke it in your account settings and the HTTPS remote simply stops working until you authenticate with a new one. If a private key leaks, you remove its public counterpart from the host (your account or the repo's deploy keys) and generate a fresh pair. In both cases the remote URL itself does not need to change; you are rotating the credential, not the address. Knowing which one a remote uses tells you exactly where to go to cut access.
Related reading
Sources
Authoritative references this article was fact-checked against.
- Pro Git: Git on the Server, The Protocolsgit-scm.com
- GitHub Docs: Connecting to GitHub with SSHdocs.github.com
- GitHub Docs: Managing your personal access tokensdocs.github.com





