Remote Repositories¶
So far, everything has been local - one repository on your machine. In practice, you work with code that lives on a server, collaborate with other developers, and synchronize changes between multiple copies of the same repository. Remotes are Git's mechanism for connecting these repositories together.
What Is a Remote?¶
A remote is a bookmark to another Git repository. It's a short name (like origin) mapped to a URL where another copy of your repository lives. Remotes don't maintain a live connection - they're just URLs that Git uses when you explicitly fetch or push.
When you clone a repository, Git automatically creates a remote called origin pointing to the URL you cloned from. You can add more remotes, rename them, or remove them.
origin git@github.com:yourname/project.git (fetch)
origin git@github.com:yourname/project.git (push)
The fetch and push URLs are usually the same, but they can differ (for example, fetching over HTTPS but pushing over SSH).
Cloning a Repository¶
git clone creates a local copy of a remote repository. It does more than download files:
- Creates a new directory
- Initializes a
.gitdirectory - Creates a remote called
originpointing to the source URL - Fetches all branches and their history
- Creates remote-tracking branches (
origin/main,origin/feature/x) - Checks out the default branch (usually
main) and creates a local tracking branch
# Clone via SSH (preferred - uses your SSH key)
git clone git@github.com:user/repo.git
# Clone via HTTPS (prompts for credentials)
git clone https://github.com/user/repo.git
# Clone into a specific directory
git clone git@github.com:user/repo.git my-project
# Clone only the most recent history (faster for large repos)
git clone --depth 1 git@github.com:user/repo.git
After cloning, git remote -v shows the origin:
git remote -v
# origin git@github.com:user/repo.git (fetch)
# origin git@github.com:user/repo.git (push)
Remote-Tracking Branches¶
When you clone or fetch, Git creates remote-tracking branches - read-only references that remember where branches are on the remote. They're named <remote>/<branch>:
You can't commit to remote-tracking branches directly. They're updated only by git fetch or git pull. Think of them as bookmarks: "this is where main was on origin the last time I checked."
# List remote-tracking branches
git branch -r
# List all branches (local + remote-tracking)
git branch -a
The relationship between local branches, remote-tracking branches, and remote branches:
flowchart LR
subgraph Local["Your Machine"]
direction TB
LB["Local branch<br/>main"]
RTB["Remote-tracking branch<br/>origin/main"]
end
subgraph Remote["GitHub / GitLab"]
direction TB
RB["Remote branch<br/>main"]
end
RTB -->|"git push"| RB
RB -->|"git fetch"| RTB
RTB -->|"git merge origin/main"| LB
LB -->|"git push"| RB
Fetch vs Pull¶
This distinction trips up most beginners. They're related but different operations.
git fetch¶
git fetch downloads new commits, branches, and tags from a remote - but does not change your working directory or local branches. It only updates your remote-tracking branches.
# Fetch from origin
git fetch origin
# Fetch from all remotes
git fetch --all
# Fetch and prune deleted remote branches
git fetch --prune
After fetching, you can inspect what changed before integrating:
# See what's new on origin/main
git log main..origin/main --oneline
# See the diff
git diff main origin/main
git pull¶
git pull is git fetch followed by git merge (by default). It downloads and immediately integrates remote changes into your current branch:
# Equivalent operations:
git pull origin main
# is the same as:
git fetch origin
git merge origin/main
Why fetch + merge Is Often Safer¶
git pull merges automatically, which can create unexpected merge commits or conflicts when you're not ready. With fetch + merge, you can:
- Fetch to see what changed
- Inspect the incoming commits
- Decide how to integrate (merge, rebase, or wait)
git fetch origin
git log --oneline main..origin/main # Review new commits
git merge origin/main # Integrate when ready
Configure pull behavior
You can make git pull rebase instead of merge:
Or require explicit choice every time (no silent merges):
With pull.ff = only, git pull refuses to create a merge commit. If a fast-forward isn't possible, it fails and tells you to choose between merge and rebase explicitly.
Pushing Changes¶
git push uploads your local commits to a remote repository:
# Push current branch to its upstream
git push
# Push a specific branch to a specific remote
git push origin main
# Push and set upstream tracking (first push of a new branch)
git push -u origin feature/auth
# Push all branches
git push --all
# Push tags
git push --tags
Push Rejection¶
If the remote has commits that you don't have locally, Git rejects the push to prevent overwriting others' work:
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'git@github.com:user/repo.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. Integrate the remote changes (e.g., 'git pull ...') before
hint: pushing again.
The fix: fetch, integrate (merge or rebase), then push again:
Never force push shared branches
git push --force overwrites the remote branch with your local version, potentially destroying other people's commits. Only force push to branches that you alone work on (and even then, prefer --force-with-lease which fails if someone else has pushed since your last fetch).
Tracking Branches and Upstream Configuration¶
A tracking branch (or upstream branch) is a local branch configured to follow a remote branch. When you git clone, main automatically tracks origin/main. For new branches, you set tracking explicitly:
# Set upstream when pushing a new branch
git push -u origin feature/auth
# Set upstream for an existing branch
git branch --set-upstream-to=origin/feature/auth feature/auth
# Check tracking configuration
git branch -vv
git branch -vv shows each branch's upstream:
feature/auth a1b2c3d [origin/feature/auth: ahead 2] Add OAuth handler
* main e4f5a6b [origin/main] Latest commit message
"ahead 2" means your local branch has 2 commits not yet pushed. "behind 3" would mean the remote has 3 commits you haven't fetched.
Managing Remotes¶
Adding a Remote¶
Common when working with forks - you have your fork as origin and the original repo as upstream:
# Add a new remote
git remote add upstream git@github.com:original-author/repo.git
# Verify
git remote -v
# origin git@github.com:yourname/repo.git (fetch)
# origin git@github.com:yourname/repo.git (push)
# upstream git@github.com:original-author/repo.git (fetch)
# upstream git@github.com:original-author/repo.git (push)
Renaming and Removing¶
# Rename a remote
git remote rename origin github
# Remove a remote
git remote remove upstream
# Show details about a remote
git remote show origin
git remote show origin displays useful information: the fetch/push URLs, tracked branches, and whether local branches are ahead or behind.
SSH vs HTTPS Authentication¶
Git supports two main protocols for communicating with remote repositories.
HTTPS¶
- URL format:
https://github.com/user/repo.git - Prompts for username/password (or token)
- Works through most firewalls and proxies
- Requires credential helper to avoid retyping passwords
# Configure credential caching (in memory for 15 minutes)
git config --global credential.helper cache
# macOS keychain
git config --global credential.helper osxkeychain
# Windows credential manager
git config --global credential.helper manager
Use tokens, not passwords
GitHub, GitLab, and Bitbucket no longer accept account passwords for HTTPS Git operations. Use a personal access token (PAT) instead of your password. Generate one in your platform's settings under Developer Settings or Access Tokens.
SSH¶
- URL format:
git@github.com:user/repo.git - Uses SSH key pairs (no passwords after setup)
- More secure than HTTPS with passwords
- Requires SSH key generation and registration with the platform
Switching a Remote from HTTPS to SSH¶
# Check current URL
git remote -v
# origin https://github.com/user/repo.git (fetch)
# Switch to SSH
git remote set-url origin git@github.com:user/repo.git
# Verify
git remote -v
# origin git@github.com:user/repo.git (fetch)
Working with Forks¶
In open-source projects, you typically don't have push access to the original repository. The workflow is:
- Fork the repository on the platform (creates your copy under your account)
- Clone your fork locally (this becomes
origin) - Add the original repository as a remote called
upstream - Fetch from upstream to stay current
- Create branches for your work (based on
upstream/main) - Push to your fork (
origin) - Open a pull request from your fork to the original repository
# Clone your fork
git clone git@github.com:yourname/project.git
cd project
# Add the original repo as upstream
git remote add upstream git@github.com:original-author/project.git
# Stay current with upstream
git fetch upstream
git merge upstream/main # or rebase
# Work on a feature
git switch -c feature/my-contribution
# ... make changes, commit ...
# Push to your fork
git push -u origin feature/my-contribution
# Open a pull request on the platform
Exercise¶
Further Reading¶
- Pro Git - Chapter 2.5: Working with Remotes - fetching, pulling, pushing, and remote management
- Pro Git - Chapter 5: Distributed Git - distributed workflows and contributing to projects
- GitHub SSH Documentation - setting up SSH keys for GitHub
- GitLab SSH Documentation - SSH setup for GitLab
- Official git-remote documentation - complete reference for remote management
- Official git-fetch documentation - fetch options and configuration
Previous: Branches and Merging | Next: Rewriting History | Back to Index