Computing and the Command Line

Clone, Fetch, Pull, Push

A remote is another copy of the repository, usually named origin. Clone copies one; fetch downloads new commits and moves your remote-tracking branches like origin/main without touching your work; pull fetches and then integrates (fast-forward, merge, or rebase, depending on version and settings); push sends your commits and is rejected if the remote has commits you don't. Upstream tracking with push -u, and why git status can be out of date.

  • 5 min
  • 6 steps
  • 2 questions
  • Lesson 34 of 80

In this lesson

  1. Remotes
  2. Clone
  3. Fetch and pull
  4. Push
  5. Your turn
  6. So

Remotes

A remote is another copy of your repository, somewhere else: on GitHub, on a server, or in another folder 1. Each has a short name. When you clone, git names the one you cloned from origin 1.

me@linuxbox:~/garden$ git remote -v
origin  git@github.com:you/garden.git (fetch)
origin  git@github.com:you/garden.git (push)

Your repository keeps remote-tracking branches such as origin/main: read-only bookmarks of where the remote’s branches were the last time you talked to it 1. Your own main and origin/main can differ, and that difference is what fetch, pull, and push sort out.

Left, your repository, with main at e92017d Plan the beds and origin/main at f30ca24 Add beans, your last-known copy of the remote's main; your working files are what your main says. Right, the remote, origin on GitHub, with main at f30ca24 Add beans. Arrows: git fetch downloads and moves origin/main only; git pull fetches and integrates into main; git push sends your main and is rejected if you're behind. Commands: git clone URL copies a repository and sets up origin; git remote -v lists remotes; git fetch updates origin/* without touching your work; git pull fetches then fast-forwards, merges, or rebases; git push -u origin main for the first push, sending main and tracking origin/main; then just git push.
Two copies of one history, and the four commands that move commits between them. Credit: StudyCorner diagram · CC BY 4.0 · Source

Clone

git clone copies a whole repository, every commit and branch, sets up origin, and checks out the default branch 1:

me@linuxbox:~$ git clone git@github.com:you/garden.git
Cloning into 'garden'...

Fetch and pull

git fetch downloads commits you don’t have and moves your origin/... branches to match the remote. It never touches your own branches or your files, so it’s always safe 1. Afterward, git status tells you where you stand:

me@linuxbox:~/garden$ git status
On branch main
Your branch is up to date with 'origin/main'.
me@linuxbox:~/garden$ git fetch
From github.com:you/garden
   e92017d..f30ca24  main       -> origin/main
me@linuxbox:~/garden$ git status
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)

Notice the first git status said “up to date”: it compares with origin/main as of your last fetch, not with the remote right now.

git pull is a fetch followed by integrating origin/main into your branch 2. If only the remote has new commits, that’s a fast-forward:

me@linuxbox:~/garden$ git pull
Updating e92017d..f30ca24
Fast-forward
 beds.txt | 1 +
 1 file changed, 1 insertion(+)

If both you and the remote have new commits, the histories have diverged, and pull has to merge or rebase. Older versions of git merge automatically; current git’s documentation makes fast-forward-only the default, so pull stops and asks you to choose 2:

me@linuxbox:~/garden$ git pull --rebase       # replay my commits on top of theirs (module 3)
me@linuxbox:~/garden$ git pull --no-rebase    # merge, making a merge commit

Pick a default once so you’re not asked every time 2. For your own projects, rebasing keeps history straight:

me@linuxbox:~/garden$ git config --global pull.rebase true

Quick check

What’s the difference between git fetch and git pull?

Push

git push sends your branch’s new commits to the remote and moves the remote’s branch to match 1. The first time, add -u (--set-upstream) so git remembers that your main goes with origin/main; after that, plain git push and git pull know where to go 3:

me@linuxbox:~/garden$ git push -u origin main
To github.com:you/garden.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

If the remote has commits you don’t have, the push is rejected 3:

me@linuxbox:~/garden$ git push
To github.com:you/garden.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:you/garden.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. ...

Pushing only ever moves a remote branch forward, so it can’t silently throw away someone else’s commits 3. The fix is to pull first (with --rebase, ideally), then push:

me@linuxbox:~/garden$ git pull --rebase
Successfully rebased and updated refs/heads/main.
me@linuxbox:~/garden$ git push

You’ll see advice to use git push --force to override a rejection. It replaces the remote branch with yours, discarding whatever’s there that you don’t have. If you ever truly need it, after rebasing your own branch that nobody else uses, use --force-with-lease, which refuses if the remote has changed since you last fetched 3.

Quick check

git push says ! [rejected] main -> main (fetch first). What do you do?

Your turn

Practice with two clones, no account needed

A remote can be another folder. Make one to stand in for GitHub:

  1. git init --bare ~/server.git makes an empty repository with no working files, the kind servers hold.
  2. In your garden repository: git remote add origin ~/server.git and git push -u origin main.
  3. git clone ~/server.git ~/garden-laptop makes a second copy, like a second computer.
  4. Commit a change in garden-laptop and push it. In garden, run git status, then git fetch, then git status again. What changed?
  5. Commit different changes in both copies. Push from one, try to push from the other, read the rejection, then git pull --rebase and push.
Answers
  1. The first git status in garden still says up to date; after git fetch, it says your branch is behind origin/main by 1 commit. git pull brings it in.
  2. The second push is rejected with (fetch first). After git pull --rebase your commit sits on top of the other one, and git push succeeds. git log --oneline --graph shows a straight line.

So

A remote is another copy of the repository, usually origin, and origin/main is your last-known copy of its main. git clone copies one, git fetch safely updates origin/*, git pull fetches and integrates (set pull.rebase once), and git push -u sends your branch and sets up tracking. A rejected push means pull first; avoid --force, and if you must, use --force-with-lease.

Lesson complete

Nice work.

1day streak
0/1today's goal
–correct

Up next · 5 min

GitHub over SSH

Next lesson
Sources for this lesson
  1. 1
    Scott Chacon, Ben Straub. Pro Git, 2nd edition. Apress; free online at git-scm.com. 2014. verifiedFree CC BY-NC-SA 3.0 book, maintained online. Ch. 1: version control; Git's 2005 origin when the Linux kernel lost free use of BitKeeper; snapshots, not differences (unchanged files stored once); nearly every operation local; integrity through 40-character SHA-1 checksums; the three states (modified, staged, committed) and three areas (working tree, staging area or index, .git directory); first-time setup with system/global/local config levels, user.name and user.email baked into commits, core.editor, git config --list --show-origin. Ch. 2: git init, status (and -s), add, diff and diff --staged, commit (-m, -a), .gitignore, log options, amending, undoing, remotes, tags, aliases. Ch. 3: branches as movable pointers, HEAD, merging and conflicts, remote branches, rebasing and its rule. Ch. 7: reset demystified, stashing, revision selection. Ch. 8: core.autocrlf true on Windows, input on Linux and macOS. Ch. 10: objects (blob, tree, commit) and references.
  2. 2
    git-pull documentation. Git project (git-scm.com). verifiedgit pull runs git fetch, then integrates the current branch's upstream into it. Four main ways to integrate: --ff-only, which fails if the local branch has diverged and which the current documentation names the default; --rebase; --no-rebase (merge); --squash. Set a preference with pull.rebase, pull.ff, or pull.squash. A conflicted merge or rebase can be backed out with git merge --abort or git rebase --abort.
  3. 3
    git-push documentation. Git project (git-scm.com). verifiedUpdates remote refs using local refs. -u/--set-upstream records the upstream for later argument-less pull and push. Usually push refuses to update a remote ref that is not an ancestor of the local ref (the must-fast-forward rule); --force overrides it, and --force-with-lease overrides it only if the remote ref still has the value your remote-tracking branch expects.