git fetch is half of what git pull does. Only half: download,
without merge. That is its main advantage.
What physically happens
git fetch origin
- Connects to origin (via SSH or HTTPS).
- Asks the remote for its list of refs and their SHAs.
- Downloads all commits that are not local yet, into
.git/objects/. - Updates
refs/remotes/origin/<branch>(these are remote-tracking branches).
Local branches do not change. main, feature/x, HEAD stay
where they are. Only origin/main, origin/feature/x move; these
are separate refs that track the state of the remote.
git log main..origin/main # commits that arrived but are not merged yet
git diff main origin/main # what will change on merge
This gives you a pause between "got data" and "applied it." You can inspect what came in before merging.
When to use fetch instead of pull
- Complex merges. You want to see what arrived before merging.
- Multiple remotes. Working via a fork (see upstream-vs-origin)
usually means
git fetch upstream, then decide separately what to do. - CI/scripts. A version-comparison script: fetch, then diff.
- Just looking. "Who pushed what today" without touching the working tree.
Useful flags
git fetch --all # all remotes at once
git fetch --prune # delete local refs for branches
# that no longer exist on the remote
git fetch --tags # including tags
git fetch origin main # one specific branch only
git fetch origin pull/123/head:pr-123 # GitHub PR as a local branch
--prune is especially useful in a long-lived clone: branches are
created and deleted by the team, and without --prune the local list
of origin/<branches> fills up with dead refs. Set it once globally:
git config --global fetch.prune true.
What to do after fetch
Common patterns:
# Bring local main up to date without a merge commit
git fetch origin
git switch main
git merge --ff-only origin/main
# Alternative: rebase your feature on top of the fresh main
git fetch origin
git switch feat/x
git rebase origin/main
# Just see what is new
git fetch origin
git log main..origin/main --oneline
Pitfalls
git fetchshows nothing in the working tree. If you expect to see new files, you still need merge or rebase.- Without
--prune, stale branches pile up inorigin/. After a year there can be dozens. - In CI with a shallow clone (
--depth 1), fetch behaves in a limited way: history is not extended. Use--unshallowor--deepen N.