git fetch --all downloads every branch from every remote and updates every remote-tracking reference. That is almost certainly what you wanted. What does not exist is a single command that merges all of those into all of your local branches, and the reason it does not exist is that it would be a bad idea.
The confusion comes from git pull --all, which looks like it should do exactly that. It does not. It fetches from all remotes and then merges into the one branch you currently have checked out. The other local branches are untouched, which is why people run it, see nothing change, and conclude Git is being obtuse.
Table of contents
- Fetch versus pull, precisely
- What git pull —all actually does
- Actually updating every local branch
- Why you probably do not want this
- Setting up a branch that exists only on the remote
- The one-screen summary
- How this fits the rest of the stack
- FAQ
Fetch versus pull, precisely
The distinction is the whole topic, so it is worth being exact.
- fetch downloads objects and updates remote-tracking references like
origin/main. It never touches your working tree and never modifies a local branch. It is always safe. - pull is
fetchfollowed bymerge(orrebase, depending on config) into the current branch. It changes your working tree and can produce conflicts.
git fetch --all
git fetch --all --prune
git fetch origin
git branch -r # remote-tracking branches you now have
git branch -a # local plus remote-tracking
Add --prune. Without it, remote-tracking references for branches that were deleted on the server hang around forever, and git branch -r slowly becomes a list of every feature branch anyone has merged in two years. git config --global fetch.prune true makes it the default and is one of the better small config changes available.
After a fetch, origin/feature-x exists locally as a read-only pointer. You can git log origin/feature-x, git diff main origin/feature-x, or git switch feature-x to create a local branch tracking it. None of that requires pulling anything.
What git pull —all actually does
It fetches from every configured remote, then merges the upstream of the current branch into the current branch. One branch is updated. The flag controls which remotes are contacted, not which branches are merged.
git remote -v
git pull --all # fetches from all remotes, merges into HEAD only
On the overwhelmingly common single-remote setup, git pull --all and git pull do the same thing. The flag only means something when you have both an origin and an upstream, which is the fork workflow.
So if you ran git pull --all expecting six branches to update and one did, nothing is broken. The command did what it says; the name just implies something broader than it delivers.
Actually updating every local branch
If you genuinely need it — before going offline, say — the honest version is a loop. There is no built-in because Git does not want to guess what to do when one of those merges conflicts.
git fetch --all --prune
for b in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
git rev-parse --verify --quiet "origin/$b" >/dev/null || continue
git branch --force "$b" "origin/$b" 2>/dev/null || \
echo "skipped $b (checked out or diverged)"
done
Read what that does before running it, because it is destructive. git branch --force moves the local branch pointer to match the remote, discarding any local commits that were not pushed. It refuses on the currently checked-out branch, which is the only safety net it has.
The safer variant only fast-forwards, so it stops rather than discarding work:
git fetch --all --prune
for b in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
git merge-base --is-ancestor "$b" "origin/$b" 2>/dev/null &&
git branch --force "$b" "origin/$b"
done
--is-ancestor checks that the local branch is strictly behind the remote before moving it. Branches with unpushed commits are left alone. That is the version worth keeping in a script.
Why you probably do not want this
The opinion, stated plainly: a repository with fifteen local branches that all need updating is usually telling you something about the branches, not about Git.
Local branches are checkouts of work in progress. Once a branch is merged, the local copy has no further purpose — the commits live in main and the remote-tracking reference covers anything you need to look at. Keeping it around and dutifully updating it is maintenance with no payoff.
The cleanup that removes the problem entirely:
# list local branches already merged into main
git branch --merged main | grep -v '^\*\|main'
# delete them
git branch --merged main | grep -v '^\*\|main' | xargs -r git branch -d
# and prune the stale remote-tracking refs
git fetch --prune
Do that fortnightly and the local branch list stays at three or four — the ones you are actually working on. At that size, updating them individually takes ten seconds and the loop stops being interesting.
git branch -d refuses to delete anything unmerged, so it is safe to run broadly. -D forces and is the one to be careful with.
Setting up a branch that exists only on the remote
The other half of this question: a colleague pushed a branch, you fetched, and now you want to work on it.
git fetch origin
git switch feature-x # auto-creates a tracking branch
# explicit form
git switch -c feature-x origin/feature-x
# older syntax, still works
git checkout -t origin/feature-x
Modern Git creates the local tracking branch automatically when the name matches exactly one remote branch, which covers nearly every case. The explicit form matters when the same branch name exists on two remotes and Git refuses to guess.
Check what is tracking what with git branch -vv. It prints each local branch, its upstream, and how far ahead or behind it is — which is usually the information people were after when they went looking for a pull-all command in the first place.
The one-screen summary
git fetch --all --prune— download everything, clean up deleted branches. Safe, and what you want most of the time.git pull— fetch and merge into the current branch only.--alldoes not change that.git branch -a— see everything, local and remote-tracking.git branch -vv— see what tracks what and how far behind you are.git switch <name>— start working on a remote branch.- A loop over
for-each-ref— the only way to update every local branch, and worth avoiding by deleting merged branches instead.
Set fetch.prune to true globally and delete merged branches on a schedule. Those two habits between them dissolve the problem this search is usually about.
How this fits the rest of the stack
Branch hygiene tends to matter most at the point where a branch becomes a deploy. Knowing which commit is live, being able to compare it to the one before, and being able to go back when the new one misbehaves is worth more than any local tidiness. On RunxBuild a push to the connected branch builds and deploys, the log stays attached to that deploy, and the previous deploy remains one action away — deploying from GitHub on RunxBuild covers connecting the repository and choosing the branch. If part of what you are working out is whether a separate staging environment is affordable, the RunxBuild hosting calculator prices the service, database, and bandwidth as separate line items so a second environment is a concrete figure.
Useful related references:
- See All Branches in Git: Local, Remote, and the Ones You Forgot
- How to Rename a File in Linux: mv, rename, and git mv
- git push -f: When It Is Fine, When It Is Not, and the Safer Flag
- Services on RunxBuild
FAQ
Does git pull —all update all my local branches?
No. It fetches from every configured remote, then merges only into the branch you currently have checked out. Your other local branches are untouched. The flag controls which remotes are contacted, not which branches get merged.
How do I download all branches from a remote?
git fetch --all --prune. This updates every remote-tracking reference and removes references to branches that were deleted on the server. Add git config --global fetch.prune true to make pruning automatic.
How do I check out a branch that only exists on the remote?
Fetch first, then git switch feature-x. Modern Git creates a local tracking branch automatically when the name matches exactly one remote branch. The explicit form is git switch -c feature-x origin/feature-x.
Is there a command to update every local branch at once?
Not built in. You need a loop over git for-each-ref that fast-forwards each branch to its upstream. Guard it with git merge-base --is-ancestor so branches with unpushed commits are skipped rather than reset.
How do I clean up local branches that are already merged?
git branch --merged main | grep -v '^\*\|main' | xargs -r git branch -d. The -d form refuses to delete anything unmerged, so it is safe to run broadly. Follow it with git fetch --prune to clear stale remote-tracking references.