Fetching and Pulling

To get other people's commits from a remote you have two commands. git fetch downloads new commits but doesn't change your branches, so you can look before you combine. git pull fetches and then immediately merges (or rebases) the changes into your current branch.

git fetch

Alex has pushed two commits. Sam's local repository doesn't know yet — git status only compares with what Sam last downloaded:

$
git status
Output
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
$
git fetch
Output
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), 564 bytes | 282.00 KiB/s, done.
From https://github.com/sam-rivera/recipes
   6b13d64..de456d3  main       -> origin/main
$
git status
Output
On branch main
Your branch is behind 'origin/main' by 2 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working tree clean

Fetching updated origin/main, Sam's local record of the server's main. Sam's own main and working files haven't changed. Now Sam can see exactly what arrived:

$
git log --oneline main..origin/main
Output
de456d3 (origin/main) Add cinnamon to porridge
8b0160c Add porridge recipe
$
git diff main origin/main --stat
Output
 porridge.txt | 1 +
 1 file changed, 1 insertion(+)

Fetching is always safe — it never touches your branches or files — so you can run it whenever you like. git fetch --all fetches from every remote.

Bringing the changes in

After fetching, integrate the remote commits into your branch with a merge (or a rebase):

$
git merge origin/main
Output
Updating 6b13d64..de456d3
Fast-forward
 porridge.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 porridge.txt

Because Sam had no new local commits, this was a fast-forward.

git pull = fetch + merge

git pull does both steps in one command, and it's what you'll normally use:

$
git pull
Output
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 312 bytes | 312.00 KiB/s, done.
From https://github.com/sam-rivera/recipes
   de456d3..6fc79e0  main       -> origin/main
Updating de456d3..6fc79e0
Fast-forward
 granola.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 granola.txt

When both sides have new commits

If you've committed locally and the remote has new commits, the branches have diverged. A fast-forward is impossible, and Git needs to know whether to merge or rebase. Without a setting, recent versions of Git stop and ask you to choose:

$
echo "Pancakes: flour, milk, eggs, sugar" > pancakes.txt
git commit --quiet -am "Add sugar to pancakes"
git pull
Output
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 282 bytes | 282.00 KiB/s, done.
From https://github.com/sam-rivera/recipes
   6fc79e0..604368d  main       -> origin/main
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.

The three choices:

SettingDivergent pull doesHistory
pull.rebase falseMerge — creates a merge commitShows parallel work, adds "Merge branch 'main' of …" commits
pull.rebase trueRebase your local commits on top of the remote'sStraight line; popular for day-to-day pulling
pull.ff onlyRefuse; you decide each timeNothing happens until you merge or rebase yourself

Set your preference once (many developers choose rebase), or decide per pull with --rebase / --no-rebase:

$
git config --global pull.rebase true
git pull
Output
Successfully rebased and updated refs/heads/main.
$
git log --oneline --graph
Output
* 4193a2e (HEAD -> main) Add sugar to pancakes
* 604368d (origin/main) Add shakshuka recipe
* 6fc79e0 Add granola recipe
* de456d3 Add cinnamon to porridge
* 8b0160c Add porridge recipe
* 6b13d64 Add pancake recipe

Sam's commit was replayed on top of Alex's, and the history stays linear. Sam can now push.

Conflicts while pulling

A pull can hit a merge conflict like any merge or rebase. Resolve it the same way (lesson 25) and finish with git commit for a merge, or git rebase --continue for a rebase. git merge --abort or git rebase --abort backs out.

Pull before you start

A simple habit avoids most trouble: git pull before you begin work and before you push. Pulling with uncommitted changes in files that the incoming commits also changed is refused — commit or stash first. To pull with uncommitted changes in other files, add --autostash, which stashes them, pulls, and restores them.

Try it yourself

Clone the same repository into two folders to act as two people. Commit and push from one; in the other, use git fetch and git log main..origin/main to inspect the new commit before merging it. Then create a divergence and practise git pull --rebase.