Skip to content

Pushing and Pulling

With your local repository connected to GitHub, the two commands you use every day are git push (send commits up) and git pull (receive commits down). This lesson covers both, plus git fetch, which pulls without merging.

Terminal window
git push

After the first push with -u origin main, subsequent pushes only need git push. Git already knows the upstream.

If you are on a branch that has no upstream yet:

Terminal window
git push -u origin feature/add-trailhead

This pushes the branch to GitHub and sets the upstream in one step.

Git sends only the commits GitHub does not already have — not the entire repository. If you have made three commits locally since your last push, only those three objects travel over the network.

If GitHub’s branch has commits that your local branch does not, Git will refuse the push:

! [rejected] main -> main (non-fast-forward)
hint: Updates were rejected because the remote contains work that you do not have locally.

This means someone else (or you from another machine) pushed commits after your last sync. You need to pull first, then push.

Terminal window
git pull

git pull does two things in sequence:

  1. Fetches new commits from the remote (same as git fetch)
  2. Merges them into your current branch

If the remote has commits you do not, Git merges them. If there are no conflicts, the merge is a fast-forward and your branch simply advances. If there are conflicts, Git pauses and lets you resolve them — the same conflict resolution process as any other merge.

Terminal window
git fetch

git fetch downloads new commits from GitHub and updates your remote-tracking branches (origin/main, etc.) but does not touch your local branches. Your working tree is unchanged.

After fetching, you can inspect what arrived:

Terminal window
git log main..origin/main --oneline

This shows commits that are on origin/main but not yet on your local main. You can review them before deciding to merge:

Terminal window
git merge origin/main

Why use fetch instead of pull?

Fetch lets you see what changed before integrating it. On a shared project, you might want to review incoming commits before they touch your working branch. On a solo project, git pull is almost always fine.

When a branch has an upstream set, git status tells you where you stand:

On branch main
Your branch is ahead of 'origin/main' by 2 commits.
(use "git push" to publish your local commits)

Or, if the remote has commits you lack:

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)

Or, if both sides have diverged:

On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)

This last state — diverged — is where you need to pull, resolve any conflicts, and then push.

An alternative to git pull (which merges):

Terminal window
git pull --rebase

Instead of creating a merge commit, this replays your local commits on top of the fetched commits. It produces a cleaner linear history. Many teams prefer this for solo-branch work. You do not need to use it now, but you will encounter it in team workflows.

  1. In your git-practice folder (connected to GitHub from the previous lesson), make a new commit locally:
Terminal window
echo "New local note" >> pine-ridge.txt
git add pine-ridge.txt
git commit -m "Add local note for push exercise"
  1. Run git status and observe the “ahead of ‘origin/main’” message.

  2. Push to GitHub:

Terminal window
git push
  1. Visit your GitHub repository in a browser and confirm the new commit appears.

  2. Run git fetch (nothing to fetch since you just pushed, but observe the output — it will be silent when there is nothing new).

  3. Run git log --oneline --all and observe both main and origin/main pointing to the same commit.

  • git push sends local commits to GitHub. After the first push with -u, you only need git push.
  • Git rejects a push if the remote has commits you lack — pull first, then push.
  • git pull fetches remote commits and merges them into your current branch.
  • git fetch downloads remote commits and updates remote-tracking branches without touching your local branches.
  • git status shows how your branch relates to its upstream (ahead / behind / diverged).

Next: cloning — how to get a copy of an existing GitHub repository onto your machine.