Comparison

git fetch vs git pull: what's the difference and which to use

Updated: · Skillaria.Top

git fetch only downloads new commits from the remote and updates remote-tracking branches like origin/main, leaving your files and branches untouched. git pull does the same and then immediately integrates the changes into your current branch with a merge or a rebase. Fetch is always safe; pull is convenient when you are ready to accept other people's changes right away.

The short answer

git fetch downloads new commits from the remote and updates your remote-tracking branches (origin/main, origin/feature-x), but it doesn't touch your current branch or the files in your working directory. git pull is git fetch followed immediately by integrating what was downloaded into your current branch: with a merge (the default) or with a rebase.

That gives you a practical rule of thumb: you can run fetch any time, it never breaks anything. Pull changes your branch and can end in a conflict, so run it with a clean working directory and a rough idea of what's about to come in.

Where remote branches live

To make the difference obvious, you need to know that a local repository has two kinds of branches. Local branches like main and feature-x are the ones you move with your own commits. Remote-tracking branches like origin/main are bookmarks that say "this is what the server looked like the last time we synced". You can't move them by hand; only talking to the server updates them: fetch, pull and push.

git branch -a
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/feature-x

git status compares your branch with the origin/main bookmark, not with the live server. That's why "Your branch is up to date with 'origin/main'" can be misleading: if you haven't fetched in a while, Git simply doesn't know about your teammates' new commits.

What git fetch does

$ git fetch
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
Unpacking objects: 100% (4/4), done.
From github.com:team/project
   3f2a1c9..8b7d4e2  main       -> origin/main

The last line tells you what matters: origin/main moved from 3f2a1c9 to 8b7d4e2. Your own main stayed where it was. Now you can calmly look at what came in:

git status                       # Your branch is behind 'origin/main' by 2 commits
git log main..origin/main --oneline   # commits you don't have yet
git diff main origin/main        # what will change in your files

Useful fetch options:

  • git fetch --all — fetch from every remote (handy when a fork has both origin and upstream);
  • git fetch --prune (-p) — delete local remote-tracking refs for branches that no longer exist on the server;
  • git fetch origin main — fetch a single branch only;
  • git fetch --tags — also fetch all tags.

To prune on every fetch, turn it on once: git config --global fetch.prune true.

What git pull does

git pull runs two steps back to back. First it fetches the upstream of your current branch, then it integrates origin/<branch> into your branch. Literally, it's equivalent to:

git fetch origin
git merge origin/main      # or git rebase origin/main with pull --rebase

What happens next depends on how the histories have diverged:

  • you have no new commits — Git does a fast-forward and simply moves your branch ahead;
  • both you and the server have new commits — a merge creates a merge commit, a rebase replays your commits on top of the server's;
  • the same lines were changed on both sides — you get a conflict that you have to resolve by hand.

git fetch vs git pull side by side

git fetchgit pull
Downloads commitsYesYes
Updates origin/*YesYes
Changes the current branchNoYes
Changes files in the working directoryNoYes
Can cause a conflictNoYes
Needs a clean working directoryNoRecommended
Affects other branchesUpdates all remote-tracking refsIntegrates into the current branch only
When to useSee what changed; before a rebase; in scriptsQuickly catch up with the server on your branch

git pull: merge or rebase?

Since Git 2.27, pulling into a diverged branch without an explicit setting prints a warning, and newer versions stop with the error "Need to specify how to reconcile divergent branches" instead of silently merging. Git asks you to pick a strategy once:

git config --global pull.rebase false   # merge (the old default behavior)
git config --global pull.rebase true    # rebase
git config --global pull.ff only        # fast-forward only, refuse otherwise

Merge keeps history as it was and adds a commit like "Merge branch 'main' of github.com:...". If you pull every day into a branch with local commits, your history fills up with these housekeeping merges.

Rebase replays your unpushed commits on top of the fresh ones from the server. History stays linear, and conflicts are resolved one commit at a time. For local commits you haven't published yet, this is usually the best option. Rebase is only dangerous for commits you've already pushed and that others are building on.

ff only is the strictest mode: pull only succeeds when you have no commits of your own. If history has diverged, you decide explicitly what to do. Many experienced developers use exactly this for main branches.

If you have uncommitted changes and need to pull right now, use git pull --rebase --autostash: Git stashes your changes, runs the rebase and puts them back.

A typical workflow: fetch, inspect, integrate

The "fetch first" approach gives you control over what lands on your branch. It's especially useful before opening a pull request and after a long break.

git fetch
git log --oneline --graph HEAD origin/main   # see how the branches diverged
git rebase origin/main                       # or git merge origin/main
git push

Another common case is updating your feature branch with the latest main without switching to it:

git switch feature-x
git fetch
git rebase origin/main

Pull is the wrong tool here: git pull on a feature branch brings in changes from that branch's own upstream (origin/feature-x), not from the main branch. You could write git pull --rebase origin main, but the fetch version is clearer.

Syncing with the remote: keeping your branch up to date

When people search for "git sync", they usually mean the "get their changes, push mine" loop. Plain Git has no sync command (IDEs and GUI clients have a Sync button, which runs pull and then push under the hood). Done by hand, a reliable loop looks like this:

  1. git status — make sure everything is committed or stashed with git stash;
  2. git pull --rebase — get the changes and replay your commits on top;
  3. resolve conflicts if there are any: fix the files, git add, git rebase --continue;
  4. run the tests;
  5. git push.

To sync a fork with the original repository:

git remote add upstream https://github.com/original/project.git
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main

Common git pull errors and how to fix them

Your local changes would be overwritten by merge

Pull wants to change files you're editing and haven't committed. Your options: commit them, stash them (git stash, then pull and git stash pop) or use --autostash. There's no need to throw away your changes just to pull.

Conflict after git pull

Git stops and lists the conflicted files in git status. Open them, keep the right version between the <<<<<<< and >>>>>>> markers, then run git add and git commit (for a merge) or git rebase --continue (for a rebase). Changed your mind? git merge --abort or git rebase --abort puts everything back the way it was before the pull.

There is no tracking information for the current branch

The branch has no upstream set, so Git doesn't know where to pull from. Specify it explicitly: git pull origin main, or set up tracking once: git branch --set-upstream-to=origin/main.

refusing to merge unrelated histories

The local and remote repositories were created independently, for example the server one got a README when it was created. If you're sure they should be combined: git pull origin main --allow-unrelated-histories.

How to undo a bad git pull

If the merge from a pull has already completed and you don't like the result, reset the branch to where it was before: git reset --hard ORIG_HEAD. This discards uncommitted changes, so check git status first. As a last resort, the branch's previous position can be found in git reflog.

Which one should you use?

  • Want to see what's new without changing anything — git fetch.
  • Working on your own branch and just catching up with the server — git pull --rebase (or pull with pull.rebase true configured).
  • Updating a main branch with no commits of your own — git pull --ff-only.
  • Need to bring main into a feature branch — git fetch, then git rebase origin/main or git merge origin/main.
  • Writing a script or CI job — fetch and explicit commands, no pull.

What it looks like in the commit graph

Say you and a teammate both started from commit C. You made commit D locally, and your teammate pushed E to the server. After git fetch your repository knows about both lines: main points to D, origin/main points to E, and their common ancestor is C.

          D   <- main (HEAD)
         /
A---B---C
         \
          E   <- origin/main

From here it all depends on how you integrate. git merge origin/main creates a commit M with two parents, D and E. git rebase origin/main copies D on top of E as a new commit D' with a different hash, and history becomes a straight line. git pull just does the same steps automatically, with no pause in between. That pause — the chance to look at the graph before integrating — is the main value of a separate fetch.

Fetch and pull in your IDE

In VS Code, IntelliJ IDEA and other editors the buttons have different names, but the same commands sit behind them. "Fetch" is git fetch, "Pull" or "Update Project" is a pull with the strategy chosen in settings (merge or rebase), and "Sync Changes" is pull followed by push. Before clicking Sync on a shared branch, it's worth knowing which strategy is configured, or merge commits will show up in your history unexpectedly. Many IDEs also fetch periodically in the background, so the incoming commits counter in the status bar is usually up to date.

Summary

git fetch updates what you know about the server; git pull also applies that knowledge to your current branch. Fetch is safe at any moment. Pull is convenient, but it changes your branch and can bring conflicts, so configure its strategy once and keep your working directory clean. The differences between push, pull and fetch, working with remotes and GitHub are covered hands-on in the Git course.

FAQ

Do I need to run git fetch before git pull?

No, pull runs fetch as its first step. A separate fetch is useful when you want to review the changes first and then decide how to integrate them.

Can git fetch delete my changes?

No. Fetch only updates remote-tracking refs like origin/main and never touches your local branches, the index or the working directory.

Does git pull update all branches?

No, pull integrates changes into the current branch only. The origin/* refs for other branches get updated by the fetch step, but the local branches themselves stay where they are.

How often should I run git fetch?

Before you start working, before opening a pull request and before pushing. Many IDEs fetch automatically in the background, and that's perfectly safe.

What is FETCH_HEAD?

A special ref where fetch records what it last downloaded. For example, after git fetch origin main you can run git merge FETCH_HEAD.

Learn this topic on video

This topic is covered in depth with practice in the course “Git from Scratch to Confident Developer”.

Go to course