Git Fetch vs Pull: What's the Difference
- git fetch downloads changes and updates remote-tracking refs (origin/main) without touching your local branches or working directory.
- git pull is git fetch + git merge (or git rebase with --rebase). It's convenient but skips the inspection step.
- Fetch first, inspect with git log HEAD..origin/main, then decide to merge or rebase. This is the habit that keeps histories clean.
Every developer has run git pull on a branch, got an unexpected merge conflict, and wondered why things got complicated. Usually it's because pull combines two operations β fetch and integrate β and doesn't give you a chance to look before leaping.
The teams I've worked with that have the cleanest Git histories all have one habit in common: they fetch first, look at the log, then decide whether to merge or rebase. It takes five extra seconds and saves five extra minutes of merge archaeology.
What Each Command Actually Does
Understanding what goes where in your local repo clears up the confusion immediately.
git fetch origin downloads objects and refs from the remote and updates your remote-tracking refs (origin/main, origin/feature/x). Your local branches and working directory are completely untouched. You can now inspect what changed, compare branches, or decide your integration strategy.
git pull runs git fetch then immediately runs git merge (or git rebase with --rebase) to integrate the fetched changes into your current branch. Convenient, but removes the inspection step.
The thing that trips people up: after git fetch, your local main branch hasn't moved. origin/main has. They're now two different things pointing at potentially different commits.
# FETCH: download changes, update remote-tracking refs, touch NOTHING local git fetch origin # Now origin/main is updated but your local main branch hasn't moved # Inspect what changed before integrating git log main..origin/main --oneline # Shows commits on origin/main that aren't in your local main yet git diff main origin/main # Shows the actual file diff between your local and remote # If you're happy with what you see, integrate manually git merge origin/main # or: git rebase origin/main # PULL: fetch + merge in one step (less control) git pull origin main # Equivalent to: # git fetch origin main # git merge origin/main # PULL with rebase (cleaner history than merge) git pull --rebase origin main # Equivalent to: # git fetch origin main # git rebase origin/main # Configure pull to always rebase (recommended for feature branches) git config --global pull.rebase true git config --global pull.rebase merges # preserve merge commits when rebasing
From github.com:io/thecodeforge/payments-service.git
a3f9c2e..d4f8b3c main -> origin/main
# git log main..origin/main --oneline:
d4f8b3c feat(auth): Add JWT token refresh
9c3e8a2 fix(payment): Handle null payment reference
When to Use Fetch Over Pull
Fetch is the safer professional habit for a few specific scenarios:
Before merging a PR locally: fetch first, inspect the diff against your branch, verify there are no conflicts, then merge with confidence.
On shared branches: before pushing to main or develop, always git fetch origin main first to check if the remote has moved. If it has, rebase or merge before pushing.
In CI/CD scripts: pipelines should git fetch and compare refs programmatically rather than blindly pulling, which might trigger merge commits that pollute the history being built.
After a long coding session: fetch before you push to understand what changed while you were working. git log HEAD..origin/main tells you exactly what to expect before you integrate.
# Professional workflow: fetch first, then decide git fetch origin # What's changed on main since I branched? git log --oneline origin/main ^HEAD # How many commits am I behind? git rev-list HEAD..origin/main --count # Am I ahead of remote? (commits I haven't pushed yet) git rev-list origin/main..HEAD --count # Full status view git log --oneline --decorate --graph origin/main HEAD -10 # Only now integrate git merge origin/main # creates merge commit # OR git rebase origin/main # linear history, no merge commit
3
# You are 3 commits behind origin/main
# git rev-list origin/main..HEAD --count:
2
# You have 2 local commits not yet on remote
| Operation | Downloads from remote? | Updates remote-tracking refs? | Modifies local branch? | Modifies working dir? |
|---|---|---|---|---|
| git fetch | Yes | Yes | No | No |
| git pull (merge) | Yes | Yes | Yes (merge commit) | Yes |
| git pull --rebase | Yes | Yes | Yes (rebases) | Yes |
π― Key Takeaways
- git fetch downloads changes and updates remote-tracking refs (origin/main) without touching your local branches or working directory.
- git pull is git fetch + git merge (or git rebase with --rebase). It's convenient but skips the inspection step.
- Fetch first, inspect with git log HEAD..origin/main, then decide to merge or rebase. This is the habit that keeps histories clean.
- git config --global pull.rebase true makes git pull rebase by default, resulting in cleaner linear history on feature branches.
β Common Mistakes to Avoid
- βRunning git pull on a feature branch that teammates are also working on β this creates unnecessary merge commits. Use git pull --rebase to keep a linear history.
- βNever fetching and going straight to git push β your push will be rejected if the remote has moved. Always fetch first to check.
- βConfusing origin/main (remote-tracking ref) with main (local branch) β after git fetch, these two can diverge. git log main..origin/main shows the gap.
- βSetting pull.rebase true globally without understanding it β rebasing instead of merging changes the commit hashes, which is unexpected for people not used to it.
Interview Questions on This Topic
- QExplain the difference between git fetch and git pull. When would you choose one over the other?
- QAfter running git fetch, how do you inspect what changed on the remote before merging?
- QWhat does git pull --rebase do and why might a team prefer it over a regular git pull?
Frequently Asked Questions
Is git fetch safe?
Yes, completely. git fetch never modifies your working directory, your local branches, or your staged changes. It only updates the remote-tracking refs (like origin/main) in your local repo. You can run it at any time without risk.
Should I use git pull or git fetch?
For daily work on feature branches, git pull --rebase is fine. For shared branches or before important operations, prefer git fetch first so you can inspect what changed with git log HEAD..origin/main before integrating.
What does git pull --rebase do differently?
Instead of creating a merge commit, git pull --rebase fetches the remote changes and rebases your local commits on top of them, resulting in a linear history. The tradeoff: your local commit hashes change. This is generally preferred on feature branches but requires everyone on the team to be comfortable with rebase.
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.