Skip to content
Laviyx Learn

Try

Git and GitHub course menu

git clone, fetch and pull: Staying in Sync with GitHub

Copy a repository with git clone, download changes with git fetch, update your branch with git pull, understand the difference between fetch and pull, and fix rejected pushes.

Beginner9 min readUpdated
On this page

In this lesson, two people work on the same GitHub repository. To show both sides, we use two folders: asha and ravi.

git clone#

git clone downloads a repository with its full history, and sets up origin for you:

Terminal
git clone https://github.com/your-name/notes.git asha
git clone https://github.com/your-name/notes.git ravi
Output
Cloning into 'asha'...
Cloning into 'ravi'...

The last word is the folder name. Without it, Git uses the repository's name, notes.

Terminal
cd asha
git log --oneline
git remote -v
Output
3b1b8d5 Add shopping note
origin	https://github.com/your-name/notes.git (fetch)
origin	https://github.com/your-name/notes.git (push)

Get a teammate's work#

Ravi commits and pushes. git -C ravi runs the command in the ravi folder, so that we can stay in asha:

Terminal
git -C ../ravi commit -q --allow-empty -m "Ravi: plan the week"
git -C ../ravi push -q
git status
Output
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

Asha's Git says it is up to date, because origin/main is only updated when you talk to GitHub. It does not check by itself.

git fetch#

git fetch downloads new commits and updates origin/main, but it leaves your branch and files alone. It is always safe.

Terminal
git fetch
git status
Output
From https://github.com/your-name/notes.git
   3b1b8d5..c2501d1  main       -> origin/main
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working tree clean

Now you can look at the changes before accepting them:

Terminal
git log --oneline main..origin/main
Output
c2501d1 Ravi: plan the week

git pull#

git pull is a git fetch followed by a merge of origin/main into your branch:

Terminal
git pull
git log --oneline
Output
Updating 3b1b8d5..c2501d1
Fast-forward
c2501d1 Ravi: plan the week
3b1b8d5 Add shopping note
CommandDownloads commitsChanges your files
git fetchYesNo
git pullYesYes

When a push is rejected#

If someone pushed while you were working, GitHub refuses your push, so that their work is not overwritten:

Terminal
echo "Pay rent" >> notes.txt
git commit -q -am "Asha: add rent"
echo "Water plants" > ../ravi/plants.txt
git -C ../ravi add .
git -C ../ravi commit -q -m "Ravi: add plants"
git -C ../ravi push -q
git push
Output
To https://github.com/your-name/notes.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://github.com/your-name/notes.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Get their work first. Both of you have new commits now, so the branches have diverged, and Git wants you to say how to combine them:

Terminal
git pull
Output
From https://github.com/your-name/notes.git
   c2501d1..8d22c68  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.

There are two choices: merge, or rebase. For now, merge. --no-edit accepts the default message for the merge commit:

Terminal
git pull --no-rebase --no-edit
git push
git log --oneline --graph
Output
Merge made by the 'ort' strategy.
 plants.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 plants.txt
To https://github.com/your-name/notes.git
   8d22c68..3847148  main -> main
*   3847148 Merge branch 'main' of https://github.com/your-name/notes.git
|\  
| * 8d22c68 Ravi: add plants
* | 948566d Asha: add rent
|/  
* c2501d1 Ravi: plan the week
* 3b1b8d5 Add shopping note

To set your choice once, so that plain git pull always works, run git config --global pull.rebase false. If both of you had changed the same lines, you would resolve a conflict at this point.

Pull with rebase#

The merge commit above adds nothing useful to the history. Many teams prefer the other choice, which replays their local commits on top of the new remote commits and keeps history in a straight line:

Terminal
git pull --rebase

To make this your default:

Terminal
git config --global pull.rebase true

You will learn how this works in the rebase lesson.

Remove deleted remote branches#

When a branch is deleted on GitHub, your origin/ copy remains. Clean up with:

Terminal
git fetch --prune

Common mistakes#

Practice#

Practice exercise

Ravi adds a commit and pushes it. From the asha folder, download it without changing the branch, and print how many commits it is behind with git rev-list --count main..origin/main. Then pull.

Show solution
Terminal
git -C ../ravi commit -q --allow-empty -m "Ravi: update plan"
git -C ../ravi push -q
git fetch -q
git rev-list --count main..origin/main
git pull -q
git log -n 1 --format=%s
Output
1
Ravi: update plan

Key takeaway#

Next: Pull Requests and Code Review.

Finished this lesson?