Git on Ubuntu 20.04, 22.04 and 24.04: install, GitHub authentication and cloning over SSH
- ubuntu
- git
- github
- ssh
- linux
Git itself installs in one command. The part that eats an afternoon is authentication — GitHub removed password authentication in 2021, and the replacements are not obvious.
Installing Git
Git is in the Ubuntu repositories and, unlike Node, the packaged version is genuinely fine:
sudo apt update
sudo apt install -y git
git --version
| Ubuntu release | Git version |
|---|---|
| 20.04 LTS | 2.25.1 |
| 22.04 LTS | 2.34.1 |
| 24.04 LTS | 2.43.0 |
Good enough for almost everything. Two features in this guide need newer than 20.04 ships:
- SSH commit signing needs 2.34+
git switch/git restoreare stable from 2.23, so all three are fine there
If you are on 20.04 and want a current Git, the maintainers’ PPA is the least painful route:
sudo add-apt-repository ppa:git-core/ppa
sudo apt update
sudo apt install -y git
First-run configuration
Nothing works properly until Git knows who you are:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Use the same address you have on GitHub, or commits will not link to your account. If you would
rather not publish a real address, GitHub gives you a @users.noreply.github.com one under
Settings → Emails — use that instead and turn on “Block command line pushes that expose my
email”.
A few settings that save arguments later:
# Match GitHub's default branch name
git config --global init.defaultBranch main
# Rebase instead of merge on pull — no more "Merge branch 'main' of..." noise
git config --global pull.rebase true
# Only push the branch you are on
git config --global push.default simple
# Keep line endings sane if anyone on the team is on Windows
git config --global core.autocrlf input
# Whatever editor you actually use
git config --global core.editor "vim"
Check the result at any time:
git config --global --list
Authenticating with GitHub
There are three routes. They are not equivalent.
| Method | Best for | Trade-off |
|---|---|---|
| SSH key | Daily development | Set up once, then invisible |
| HTTPS + token | Locked-down networks, CI | Token expires, needs storing somewhere |
gh CLI |
Getting started fast | An extra tool, wraps HTTPS underneath |
SSH is what I use and what the rest of this guide assumes.
SSH keys, start to finish
1. Check for an existing key
ls -la ~/.ssh
If you see id_ed25519 and id_ed25519.pub, you already have one and can skip to step 3.
2. Generate a key
ssh-keygen -t ed25519 -C "you@example.com"
Ed25519 over RSA: shorter, faster, and stronger. Only fall back to
ssh-keygen -t rsa -b 4096 if you have to talk to something ancient that cannot handle it.
Press Enter to accept the default path. Set a passphrase. A key file without one is a plaintext credential — anyone who reads your disk or a stray backup owns your GitHub account. The agent in the next step means you type it once per session, not once per push.
3. Load it into the agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
To avoid doing that in every terminal, write a ~/.ssh/config:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
AddKeysToAgent yes
IdentitiesOnly yes matters more than it looks. Without it, ssh offers every key it can find, one
at a time, and GitHub disconnects after five failures — so on a machine with several keys you get
“Too many authentication failures” while holding a perfectly good key.
Permissions must be tight or ssh refuses to use the file at all:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub
4. Add the public key to GitHub
cat ~/.ssh/id_ed25519.pub
Copy the whole line. On GitHub: Settings → SSH and GPG keys → New SSH key, paste, give it a name that identifies the machine (“thinkpad-work”), key type Authentication Key.
Only ever paste the .pub file. The other one never leaves the machine.
5. Test it
ssh -T git@github.com
First connection asks you to verify the host fingerprint. Compare it against
GitHub’s published fingerprints
before typing yes — this is the one moment a man-in-the-middle would have to get past you.
Success looks like:
Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.
That message is the goal. It is not an error.
Cloning
# SSH — no credentials to type, ever
git clone git@github.com:owner/repo.git
# HTTPS — will ask for a token
git clone https://github.com/owner/repo.git
# Shallow, for a big repo you only need the tip of
git clone --depth 1 git@github.com:owner/repo.git
# One branch only
git clone --branch main --single-branch git@github.com:owner/repo.git
Already cloned over HTTPS and tired of the prompts? Switch the remote in place:
git remote -v
git remote set-url origin git@github.com:owner/repo.git
git remote -v
HTTPS with a personal access token
Sometimes port 22 is blocked, or you are configuring CI. Then it is tokens.
GitHub has two kinds:
- Fine-grained — scoped to specific repositories with per-permission control. Use these.
- Classic — broad scopes, all-or-nothing. Only when something demands them.
Create one under Settings → Developer settings → Personal access tokens. Give it an expiry. For read/write on a repo you need Contents: Read and write.
Use the token as the password when Git asks. Then decide where it lives:
# Held in RAM for 15 minutes. Safe, mildly annoying.
git config --global credential.helper cache
# Longer window
git config --global credential.helper 'cache --timeout=28800'
# Written to ~/.git-credentials — PLAIN TEXT. Convenient and a genuinely bad idea
# on a shared or portable machine.
git config --global credential.helper store
The good option on a desktop Ubuntu is the system keyring, which encrypts at rest:
sudo apt install -y libsecret-1-0 libsecret-1-dev make gcc
sudo make --directory=/usr/share/doc/git/contrib/credential/libsecret
git config --global credential.helper \
/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
SSH when port 22 is blocked
Corporate and hotel networks often block outbound 22. GitHub serves SSH on 443 as well:
Host github.com
HostName ssh.github.com
Port 443
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Test with ssh -T git@github.com as before. This is usually faster than migrating everything to
HTTPS.
The gh CLI
GitHub’s official CLI handles authentication for you and is genuinely useful for pull requests from the terminal.
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh
Then:
gh auth login
It walks you through browser or token authentication, and can generate and upload an SSH key for you. Afterwards:
gh repo clone owner/repo
gh pr create --fill
gh pr list
gh pr checkout 42
Deploy keys — the right way to give a server access
Do not copy your personal SSH key onto a VPS. If that box is compromised, the attacker has your whole GitHub account, every repository and organisation you belong to.
A deploy key is scoped to a single repository and read-only by default.
On the server:
ssh-keygen -t ed25519 -C "deploy@myserver" -f ~/.ssh/deploy_myapp -N ""
cat ~/.ssh/deploy_myapp.pub
An empty passphrase is the deliberate choice here: an unattended deploy cannot type one. That is exactly why the key must be per-repository and read-only.
On GitHub, in the repository: Settings → Deploy keys → Add deploy key. Paste, leave “Allow write access” unticked unless you truly need pushes.
There is a dedicated guide for cloning a private repository over SSH that covers this case in more depth, including the one-key-per-repository limit and the “Repository not found” error GitHub returns instead of a permission denial.
Point ssh at it with a host alias:
Host github-myapp
HostName github.com
User git
IdentityFile ~/.ssh/deploy_myapp
IdentitiesOnly yes
Then clone through the alias:
git clone git@github-myapp:owner/myapp.git
Two GitHub accounts on one machine
Work and personal on the same laptop is the classic case. Give each its own key and its own alias.
Two keys:
ssh-keygen -t ed25519 -C "personal" -f ~/.ssh/id_ed25519_personal
ssh-keygen -t ed25519 -C "work" -f ~/.ssh/id_ed25519_work
Upload each .pub to the matching account, then in ~/.ssh/config:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
Personal repositories clone normally. Work repositories use the alias:
git clone git@github-work:company/project.git
The remaining trap: commit email. Your global user.email is now wrong half the time. Fix it with
conditional includes, so the directory decides:
# ~/.gitconfig
[user]
name = Your Name
email = personal@example.com
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
# ~/.gitconfig-work
[user]
email = you@company.com
Everything under ~/work/ now uses the work identity automatically. Note the trailing slash — it
is required.
Signing your commits
The “Verified” badge on GitHub means a commit was cryptographically signed. Since Git 2.34 you can sign with the SSH key you already have, which is far less work than GPG.
Ubuntu 20.04 ships Git 2.25 — add the PPA above first, or this will not work.
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
Then add the same public key to GitHub a second time, under Settings → SSH and GPG keys → New SSH key, this time with key type Signing Key. Authentication and signing are separate roles for the same key, and GitHub tracks them separately.
To verify signatures locally, tell Git which keys to trust:
echo "you@example.com $(cat ~/.ssh/id_ed25519.pub)" >> ~/.config/git/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers
git log --show-signature -1
Troubleshooting
Permission denied (publickey). The usual suspects, in order:
ssh -vT git@github.com # verbose — shows which key it offered
ssh-add -l # is the key even loaded?
ssh-add ~/.ssh/id_ed25519 # load it
If ssh-add -l says “Could not open a connection to your authentication agent”, the agent is not
running: eval "$(ssh-agent -s)".
Host key verification failed. The host key changed or was never accepted. Remove the stale
entry and reconnect:
ssh-keygen -R github.com
ssh -T git@github.com
Too many authentication failures. ssh is cycling through keys and hitting the server limit.
Add IdentitiesOnly yes to the relevant Host block.
Support for password authentication was removed. You are using HTTPS with an account
password. Use a token, or move the remote to SSH.
Repository not found on a repository that exists. Usually the wrong identity — a personal key
against a work repository. Check what GitHub thinks you are:
ssh -T git@github.com
ssh -T git@github-work
Passphrase asked on every single push. The agent is not persisting. Confirm AddKeysToAgent yes is in ~/.ssh/config; on a desktop session, gnome-keyring normally handles it after the
first unlock.
A minimal cheat sheet
# identity
git config --global user.name "Name"
git config --global user.email "you@example.com"
# key
ssh-keygen -t ed25519 -C "you@example.com"
cat ~/.ssh/id_ed25519.pub # paste into GitHub
ssh -T git@github.com # verify
# work
git clone git@github.com:owner/repo.git
git switch -c feature/thing
git add -p
git commit -m "message"
git push -u origin feature/thingComments
Corrections, additions and "this broke on my machine" reports are all welcome. You can post anonymously — no account needed.