git fetch & git pull โ Getting Remote Changes
The Differenceโ
| Command | What it does |
|---|---|
git fetch | Downloads remote commits and updates remote-tracking refs (origin/main) โ does not touch your working tree or local branches |
git pull | Runs git fetch and then immediately integrates those changes into your current branch (via merge or rebase) |
The golden rule: Prefer git fetch + manual inspect over git pull when you want to see what's changed before integrating. Use git pull --rebase for routine updates to keep history linear.
git fetchโ
Fetch from origin (default remote)โ
git fetch
git fetch origin
Fetch a specific branchโ
git fetch origin main
Fetch all remotesโ
git fetch --all
Fetch and prune deleted remote branchesโ
git fetch --prune
# or configure it globally:
git config --global fetch.prune true
Inspect what was fetched before integratingโ
# View commits that are on origin/main but not on your local main
git log main..origin/main --oneline
# See the diff
git diff main origin/main
# Then merge when ready
git merge origin/main
git pullโ
git pull = git fetch + git merge (by default) or git fetch + git rebase (with --rebase).
Default pull (fetch + merge)โ
git pull origin main
This creates a merge commit if your branch has diverged from the remote, which can clutter history.
Pull with rebase (recommended for feature branches)โ
git pull --rebase origin main
This replays your local commits on top of the fetched commits, keeping history linear without a merge commit.
Set rebase as the default pull strategy globallyโ
git config --global pull.rebase true
Pull and automatically stash/unstash local changesโ
git pull --rebase --autostash
# Stashes uncommitted changes, pulls, replays commits, then pops the stash
Handling Diverged Historyโ
When your branch and the remote have both moved forward, you have three options:
Local: A -- B -- C (your commits)
\
Remote: A -- B -- D -- E (remote commits you don't have yet)
Option 1: Merge (creates a merge commit)
git pull origin main
# Result: A -- B -- C -- M (M = merge commit of C and E)
# \ /
# D -- E
Option 2: Rebase (linear โ preferred for feature branches)
git pull --rebase origin main
# Result: A -- B -- D -- E -- C' (C replayed on top of E)
Option 3: Fast-forward only (reject if diverged)
git pull --ff-only origin main
# Fails if branches have diverged โ forces you to decide explicitly
Useful Flags Summaryโ
fetch flagsโ
| Flag | Meaning |
|---|---|
--all | Fetch from all remotes |
--prune | Remove remote-tracking refs for deleted remote branches |
--tags | Fetch all tags |
--depth=N | Shallow fetch โ only last N commits |
-v | Verbose output |
pull flagsโ
| Flag | Meaning |
|---|---|
--rebase | Rebase instead of merge after fetch |
--ff-only | Only fast-forward โ abort if history diverged |
--autostash | Stash before pull, pop after |
--no-commit | Fetch and merge but don't auto-commit the merge |
--prune | Prune stale remote-tracking branches during fetch |
Before starting work each day, run:
git fetch --prune
git log HEAD..origin/main --oneline # see what teammates pushed
git pull --rebase origin main # catch up
This keeps your branch current and avoids large, painful merges at PR time.
Interview Questions (Senior Level)โ
- How do you design team defaults for
pullbehavior to reduce history drift? - When should engineers avoid
git pulland prefer explicitfetch+ inspect? - What risks come with always-on rebase pulls in shared branches?
- How do you operationalize
--ff-onlyin protected branch workflows?
Short answer guide:
- Standardize pull strategy by branch type and governance needs.
- Use fetch-first when risk or uncertainty is high.
- Rebase can rewrite context and confuse shared history if misused.
--ff-onlyenforces explicit conflict resolution before integration.
Compare fetch, pull --rebase, and pull --ff-only using branch policy and team collaboration context.
Using git pull blindly on shared branches without understanding merge/rebase side effects.