Remote Repositories — push, pull, fetch
Section Objectives
- Configure and manage remotes with
git remote - Push local commits to GitHub with
git push - Retrieve and integrate remote changes with
git pullandgit fetch - Understand the difference between
fetchandpull - Manage remote branches
Understanding Remotes
A remote is a Git repository stored on another server (GitHub, GitLab, a server, etc.). A local repository can have multiple remotes.
By convention:
origin= your own remote (your fork or your repository)upstream= the original project (when you fork an existing project)
git remote — Manage Remotes
# View configured remotes
git remote
# origin
# View with URLs
git remote -v
# origin git@github.com:alice/my-project.git (fetch)
# origin git@github.com:alice/my-project.git (push)
# Add a remote
git remote add origin git@github.com:alice/my-project.git
git remote add upstream git@github.com:facebook/react.git
# Change a remote URL
git remote set-url origin git@github.com:alice/new-project.git
# Rename a remote
git remote rename origin old-origin
# Remove a remote
git remote remove upstream
# Fetch info about a remote (without downloading changes)
git remote show origin
git push — Send Commits
# Push current branch to origin
git push
# Push a specific branch
git push origin feature/login
# Push and set tracking (-u = --set-upstream)
git push -u origin feature/login
# After this, just 'git push' suffices on this branch
# Force push (DANGEROUS — see warning below)
git push --force
git push --force-with-lease # Safer version
# Push tags
git push --tags # Push all tags
git push origin v1.0.0 # Push specific tag
# Push all branches
git push --all origin
# Delete a remote branch
git push origin --delete feature/old-branch
git push origin :feature/old-branch # Equivalent
git push --force overwrites the remote history. Never use it on a shared branch (main, develop, etc.) unless you fully understand the implications. It forces your teammates to reset their local copies.
Prefer git push --force-with-lease which fails if someone else has pushed since your last fetch.
git fetch — Download Without Integrating
git fetch downloads changes from the remote without modifying your working tree or local branches:
# Fetch all remotes
git fetch
# Fetch a specific remote
git fetch origin
# Fetch a specific branch
git fetch origin main
# Fetch all remotes including pruning deleted branches
git fetch --all --prune
After fetch, you can inspect before integrating:
# View what was fetched
git log --oneline origin/main
# Compare with your local main
git log --oneline main..origin/main
# View diff
git diff main origin/main
# Now integrate if you're happy
git merge origin/main
# or
git rebase origin/main
git pull — Fetch + Integrate
git pull is a shortcut for git fetch + git merge (or git rebase):
# Pull current branch (fetch + merge)
git pull
# Pull a specific branch
git pull origin main
# Pull with rebase (cleaner history)
git pull --rebase
# Pull and create merge commit even if fast-forward is possible
git pull --no-ff
# Pull and automatically stash local changes, then restore them
git pull --autostash
git fetch vs git pull
git fetch | git pull | |
|---|---|---|
| Downloads | Yes | Yes |
| Modifies working tree | No | Yes |
| Safe at any time | Yes | Only when working tree is clean |
| Lets you inspect before merging | Yes | No (merges immediately) |
| Recommended for | When you want control | Routine updates |
Prefer git fetch + inspect + git merge (or git rebase) over a direct git pull. This gives you full control over what gets integrated.
Tracking Branches
A tracking branch is a local branch that knows which remote branch it corresponds to:
# View all tracking relationships
git branch -vv
# main a3f4b2c [origin/main] Last commit message
# feature/login b7c9d1e [origin/feature/login: ahead 2] My work
# "ahead 2" = 2 local commits not yet pushed
# "behind 3" = 3 remote commits not yet fetched
# Set a tracking branch
git branch --set-upstream-to=origin/main main
# Check how many commits behind/ahead
git status
# Your branch is ahead of 'origin/main' by 2 commits.
Common Workflows
Everyday Push Workflow
# 1. Make sure you're up to date
git fetch origin
git status # "Your branch is up to date with 'origin/main'"
# 2. Work on your branch
git switch -c feature/new-stuff
# ... edit, add, commit ...
# 3. Push to GitHub
git push -u origin feature/new-stuff
# 4. If main has evolved since you branched:
git fetch origin
git rebase origin/main # Update your branch on top of latest main
# 5. Force push after rebase (only on YOUR branch!)
git push --force-with-lease
Pull Request Workflow (Preview)
# After push, create a PR on GitHub
gh pr create --title "feat: add new stuff" --body "Description of changes"
# After PR is merged, clean up
git switch main
git pull
git branch -d feature/new-stuff
git push origin --delete feature/new-stuff
Synchronize with an Upstream Repository
# For a forked repository, sync with the original
git remote add upstream git@github.com:original-author/project.git
# Fetch upstream
git fetch upstream
# Merge upstream changes into your main
git switch main
git merge upstream/main
# or with rebase for a cleaner history
git rebase upstream/main
# Push the update to your fork
git push origin main
Summary of Key Commands
| Command | Description |
|---|---|
git remote -v | View remotes |
git remote add <name> <url> | Add a remote |
git push -u origin <branch> | Push + set tracking |
git push --force-with-lease | Careful force push |
git fetch | Download without integrating |
git pull | Fetch + merge |
git pull --rebase | Fetch + rebase |
git branch -vv | View tracking status |