Remotes, Push, Pull & Fetch
A remote is a bookmark to a copy of your repository hosted elsewhere (usually GitHub). Push uploads your commits. Pull downloads and integrates remote commits. Fetch downloads without integrating. These commands are how you collaborate and keep repositories synchronized.
Understanding Remotes
flowchart LR
L["Local Repository<br/>(your machine)"]
R["Remote: origin<br/>(GitHub)"]
L -->|git push| R
R -->|git fetch| L
R -->|"git pull<br/>fetch + merge"| L
Adding and Managing Remotes
# View existing remotes
git remote -v
# Add a remote
git remote add origin git@github.com:donnyaw/my-project.git
# Add a second remote (e.g., upstream fork)
git remote add upstream git@github.com:original-author/project.git
# Rename a remote
git remote rename origin github
# Remove a remote
git remote remove upstream
# Change a remote's URL
git remote set-url origin git@github.com:donnyaw/new-project.git
Expected output:
$ git remote -v
origin git@github.com:donnyaw/my-project.git (fetch)
origin git@github.com:donnyaw/my-project.git (push)
upstream git@github.com:original/project.git (fetch)
upstream git@github.com:original/project.git (push)
git push — Upload Commits
# Push current branch to origin
git push
# Push specific branch
git push origin main
# Push and set upstream tracking (-u, first time only)
git push -u origin main
# Push all branches
git push --all origin
# Push tags
git push --tags
# Force push (dangerous — overwrites remote)
git push --force
# Safe force push (won't overwrite others' work)
git push --force-with-lease
First Push for a New Branch
# Create branch, make changes, push for the first time
git switch -c feature/api
# ... make changes and commit ...
git push -u origin feature/api
The -u flag sets up tracking so future git push and git pull know which remote branch to target.
git push --force overwrites the remote history. Only use it on branches where you're the sole contributor. Prefer --force-with-lease which checks that no one else has pushed since your last fetch.
git fetch — Download Without Merging
Downloads new commits, branches, and tags from the remote — but doesn't modify your working files.
# Fetch from origin
git fetch origin
# Fetch from all remotes
git fetch --all
# Fetch and prune deleted remote branches
git fetch --prune
Why Fetch?
sequenceDiagram
participant L as Local
participant R as Remote (origin)
R->>L: git fetch (downloads new commits)
Note over L: origin/main updated<br/>Your main unchanged
L->>L: git log origin/main (inspect)
L->>L: git merge origin/main (integrate when ready)
Fetch is safe — it never modifies your working directory or current branch. It only updates your remote-tracking branches (origin/main, origin/feature/x).
git pull — Fetch + Merge
# Pull (fetch + merge in one step)
git pull origin main
# Pull with rebase (cleaner history)
git pull --rebase origin main
# Pull current tracking branch
git pull
Pull = Fetch + Merge
# These are equivalent:
git pull origin main
# Same as:
git fetch origin
git merge origin/main
Pull with Rebase
# These are equivalent:
git pull --rebase origin main
# Same as:
git fetch origin
git rebase origin/main
git config --global pull.rebase true
This avoids unnecessary merge commits when pulling.
Remote-Tracking Branches
When you fetch, Git creates remote-tracking branches like origin/main:
# List all remote-tracking branches
git branch -r
# See how your branch compares to remote
git log main..origin/main # Commits on remote not in local
git log origin/main..main # Commits in local not on remote
$ git branch -r
origin/HEAD -> origin/main
origin/main
origin/feature/auth
origin/fix/login-bug
Common Workflows
Solo Developer
# Daily workflow
git add .
git commit -m "feat: add new feature"
git push
Team Collaboration
# Start of day: get latest changes
git pull --rebase origin main
# Work on feature
git switch -c feature/dashboard
# ... make changes ...
git commit -m "feat: add dashboard layout"
# Before merging: update with latest main
git fetch origin
git rebase origin/main
# Push feature branch
git push -u origin feature/dashboard
# Create pull request on GitHub...
Contributing to Open Source (Fork Workflow)
# 1. Fork on GitHub, then clone your fork
git clone git@github.com:donnyaw/project.git
cd project
# 2. Add original repo as upstream
git remote add upstream git@github.com:original/project.git
# 3. Keep your fork updated
git fetch upstream
git rebase upstream/main
# 4. Push your changes to your fork
git push origin main
Decision Guide
| What You Want | Command |
|---|---|
| See remote URLs | git remote -v |
| Upload commits to GitHub | git push |
| Download remote changes | git fetch |
| Download and integrate | git pull |
| Push new branch first time | git push -u origin <branch> |
| Clean up stale remote branches | git fetch --prune |
| Check ahead/behind status | git status (with tracking set) |
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
rejected (non-fast-forward) | Remote has commits you don't have | git pull --rebase then git push |
Permission denied (publickey) | SSH key not configured | See SSH Setup |
remote origin already exists | Ran git remote add twice | Use git remote set-url origin <url> |
no tracking information | Branch doesn't track a remote | git push -u origin <branch> |
fatal: refusing to merge unrelated histories | Repos have different origins | git pull --allow-unrelated-histories |
Best Practices
- Always pull before push — reduces conflicts and rejected pushes
- Use
--rebasefor pull — avoids unnecessary merge commits - Set up tracking with
-uon first push — enables simplegit push/git pull - Fetch regularly — stay aware of remote changes without modifying your work
- Prune stale branches —
git fetch --prunekeeps your branch list clean
What's Next
- Repository Creation — Create repos on GitHub via web and API
- Forking & Pull Requests — Contribute to other projects