Skip to content
Ameen Abozaid
PublishedBEG-047-L01

Remotes, push, and pull

  • Lesson 1 of 5
  • 12 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

In the previous module you put the Bank Accounts project under Git. Everything lived in one folder on one computer. If the laptop is lost, so is the history. And nobody else can see your work, let alone improve it.

This lesson fixes both problems. You will connect your local repository to a remote, a copy of the repository stored on another server, and move commits between the two with git push and git pull. Think of a shared online bookshelf: your album sits on your desk, a second copy sits on the shelf for everyone, and you decide when to put new pages on the shelf or bring new pages home.

GitHub is the most common place to host such a copy, but the commands you learn here are plain Git and work with any server. The next lesson covers how to prove to GitHub that you are allowed to push. For now, the practice works best with a repository you can already push to; if the push asks for credentials you do not have yet, finish the next lesson and come back.

Learning Objectives

By the end of this lesson you will be able to:

  • Explain what a remote is and why origin is the usual name of the main one.
  • Connect an existing local repository to an empty GitHub repository with git remote add and publish main with git push -u origin main.
  • Copy an existing remote repository to your computer with git clone.
  • Bring new commits to your computer with git pull, and explain how git fetch differs.
  • Read git remote -v and git status to see where you stand relative to the remote.
  • Explain why a push can be rejected and what to do about it.

Written Explanation

What a remote is

A remote is a version of your repository hosted somewhere else: on the internet, on a company network, or even in another folder on your own machine. Git stores the address of each remote under a short name, so you do not have to retype the address every time.

The important idea is that a remote is a full repository too, not just a pile of files. It has commits and branches. Your local repository and the remote do not stay in sync automatically. They only change when you explicitly send or receive commits. That gives you control: you can commit ten times on a train with no network, and share all ten when you are online.

origin, and the three commands

By convention the main remote is called origin. When you copy a repository with git clone, Git names the source origin automatically. When you start from a local repository, you register the remote yourself:

bash
git remote add origin https://github.com/you/bank-accounts.git

The name is just a label. You could call it github or backup, but almost every tutorial, tool, and teammate expects origin, so use it.

Three commands do most of the work:

CommandDirectionWhat it does
git pushlocal to remoteUploads your new commits
git pullremote to localDownloads new commits and merges them into your current branch
git clone <url>remote to a new folderCopies the whole repository, including history, and sets origin for you

git pull is really two steps in one: git fetch (download new commits and update your record of the remote's branches, without touching your own work) followed by a merge. Because you already know merging from the previous module, pull holds no new idea: it is a fetch plus a merge.

Remote-tracking branches and -u

After a fetch or push, Git keeps a read-only bookmark for each remote branch, named like origin/main. It means "where main on origin was the last time I talked to it". It is not live: it only moves when you fetch, pull, or push.

The first push of a branch usually uses the -u flag (short for --set-upstream):

bash
git push -u origin main

This sends main to origin and records that your local main is linked to origin/main. From then on, a plain git push and git pull on that branch know where to go, and git status can tell you how far apart you are. You only need -u once per branch.

Publishing an existing project

The usual first-time sequence is:

  1. On GitHub, create a new repository with the name you want. If you already have a local project, leave it empty: do not let GitHub add a README or license, because that creates a commit your local repository does not have, and your first push would then be rejected. (The exact buttons on the website change over time, so follow the page's labels.)
  2. In your project folder, run git remote add origin <url> with the URL GitHub shows you.
  3. Check the branch name with git branch and push it: git push -u origin main.

GitHub offers two kinds of URL for each repository: an HTTPS one (https://github.com/you/repo.git) and an SSH one (git@github.com:you/repo.git). Both reach the same repository. They differ in how you prove who you are, which is the next lesson. If you got the address wrong, git remote set-url origin <new-url> changes it, and git remote -v lists the current addresses.

Why a push can be rejected

Suppose you and a teammate both start from the same commit. They push first. When you try to push, Git refuses: your history and the remote's history have diverged, and the remote holds a commit you do not have. Git will not overwrite their work. The fix is to bring their commits to you, merge them with yours, and push again. That is exactly git pull followed by git push. If the same lines changed on both sides, you will meet a merge conflict and resolve it as in the previous module.

You may see advice online to force the push. Do not do that as a beginner: a forced push can erase other people's commits from the remote.

Examples

Example 1: connect and publish (simple)

You have the Bank Accounts project with a few commits and an empty GitHub repository. The commands below were run in a scratch setup where the "remote" is a folder on disk standing in for GitHub; the output format is the same.

bash
git remote -v

This prints nothing: the repository has no remotes yet.

bash
git remote add origin ../remote.git
git remote -v
text
origin	../remote.git (fetch)
origin	../remote.git (push)
bash
git push -u origin main
text
branch 'main' set up to track 'origin/main'.
To ../remote.git
 * [new branch]      main -> main

[new branch] tells you the remote did not have main yet. With your own GitHub repository, the To line shows your GitHub URL instead.

Example 2: clone, change, push, pull (practical)

This is how you simulate a second person or a second computer. A new folder gets a clone, a commit is made and pushed there, and the first folder pulls it.

bash
git clone remote.git copy
cd copy
# edit Main.java, then:
git commit -am "Change greeting"
git push
text
   628f00b..0233358  main -> main

The two hashes are the old and new tip of main on the remote. Because the clone set up tracking, a plain git push was enough. Back in the original folder:

bash
git fetch
git status -sb
text
From ../remote
   628f00b..0233358  main       -> origin/main
## main...origin/main [behind 1]

The fetch downloaded the commit and moved origin/main, but your own main has not moved, and status says you are behind 1. Now pull:

bash
git pull
text
Updating 628f00b..0233358
Fast-forward
 Main.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

"Fast-forward" means your branch had no commits of its own, so Git simply moved it ahead to the remote's tip with no merge commit.

Example 3: a rejected push (realistic)

Both folders now commit on top of the same commit. The clone pushes first, then the original tries:

bash
git push
text
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to '../remote.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.

Git is protecting the other commit. Pull, and since the two commits touched different lines, Git merges automatically:

bash
git pull
text
Merge made by the 'ort' strategy.
 Main.java | 1 +
 1 file changed, 1 insertion(+)
bash
git status -sb
text
## main...origin/main [ahead 2]

You are now ahead 2: your own commit plus the new merge commit. A git push now succeeds. Had both edits changed the same line, git pull would have stopped with a conflict, and you would resolve it, commit, and then push. (The ort name is just the merge algorithm Git 2.44 used here; you do not need to know more.)

Backend Insight

Almost every backend team treats the remote repository as the single source of truth. The build server, the test runner, and eventually the deployment system all start by cloning or pulling from the remote, never from someone's laptop. If your work is not pushed, it does not exist for them.

That is why pushing often matters: small, frequent pushes mean smaller conflicts and a safe backup. It is also why git pull before you start work is a daily habit: you begin from what the team has now, not from last week. In later modules you will see this pattern again with branches and pull requests: your commits go to a branch on the remote first, and only reach main after review.

Common Mistakes

Mistake 1: Creating the GitHub repository with a README, then pushing a local project

  • Incorrect: tick "add a README" on GitHub, run git remote add, and push. The push is rejected because the remote already has a commit you lack.
  • Correct: create an empty repository, or pull first. If you must combine them, git pull origin main --allow-unrelated-histories can work, but starting empty is simpler.

Mistake 2: Forgetting -u and wondering why git pull complains

On a branch with no upstream, git pull cannot tell what to pull from. Fix: git push -u origin <branch> once, or git branch --set-upstream-to=origin/<branch>.

Mistake 3: Believing a commit is backed up

A commit exists only in the repository where you made it. Until you push, a lost laptop means lost commits. Commit locally, then push at the end of every work session.

Mistake 4: Force-pushing to fix a rejection

Forcing overwrites remote history. Pull, merge, and push instead.

Mistake 5: Confusing origin/main with main

origin/main is a bookmark to the remote's main as of your last fetch. It can be stale. Run git fetch before you judge how far behind you are.

Exercises

Try each exercise before opening the solutions. For B and C you can use a free GitHub account, or an empty folder as a stand-in remote (git init --bare remote.git).

Level A: Foundation

A1. In your own words, what is a remote, and why is origin the usual name?

Show solution A1

A1. A remote is a copy of the repository hosted elsewhere (for example on GitHub), registered under a short name. origin is the convention: git clone creates it automatically, and tools and teammates expect it.

A2. Match each command to its job: git clone, git push, git fetch, git pull. Jobs: (a) upload commits, (b) download commits without changing your branch, (c) download and merge, (d) copy a whole repository into a new folder.

Show solution A2

A2. git clone is (d). git push is (a). git fetch is (b). git pull is (c).

A3. What does git push -u origin main do that git push origin main does not?

Show solution A3

A3. -u also records that local main tracks origin/main, so later a plain git push and git pull work on that branch, and git status can report ahead/behind.

Level B: Application

B1. You have a local project with two commits and an empty remote at https://github.com/you/library.git. Write the commands to publish it, then the command that shows the remote's address.

Show solution B1

B1.

bash
git remote add origin https://github.com/you/library.git
git push -u origin main
git remote -v

(If your branch has another name, use it instead of main.)

B2. After git fetch, git status -sb shows ## main...origin/main [behind 2]. What does this say, and what command brings your branch up to date?

Show solution B2

B2. Your local main is 2 commits behind the remote's main: the remote has two commits you do not have. git pull (a fast-forward, if you have no local commits of your own) brings it up to date.

B3. Your push is rejected with "fetch first". Write what you do, in order, and what could appear during the second step.

Show solution B3

B3. First git pull, which downloads the remote's new commits and merges them. During it, Git may merge automatically, or stop with a conflict that you resolve by editing the files, then git add and git commit. Then run git push again. Never force the push.

Level C: Challenge

C1. Set up two folders, one and two, that share a remote. Commit a change in each, in different files, and get both commits into both folders. Write the command sequence and the git log --oneline you expect at the end.

Show solution C1

C1. One possible sequence:

bash
git init --bare -b main remote.git
git clone remote.git one
git clone remote.git two
cd one && echo a > a.txt && git add a.txt && git commit -m "Add a" && git push -u origin HEAD && cd ..
cd two && git pull && echo b > b.txt && git add b.txt && git commit -m "Add b" && git push && cd ..
cd one && git pull

The git push -u origin HEAD pushes the current branch under the same name. Both folders end with the same two commits, newest first: Add b, then Add a. Details such as whether git clone of an empty repository warns you will vary with the Git version.

C2. A teammate says "I pushed, but my commit isn't on GitHub." List three plausible reasons, and one command for each that helps you diagnose it.

Show solution C2

C2. (1) They committed but never ran git push: git status -sb shows ahead 1. (2) They pushed a different branch: git branch -vv shows which branch they are on and what it tracks, and the GitHub branch menu shows where the commit is. (3) They pushed to a different remote or URL: git remote -v shows the address.

Mini Challenge

Take the project you put under Git in the last module. Create an empty GitHub repository for it (or use a bare folder as a stand-in), connect it as origin, and push main. Then clone it into a second folder, make one commit there, push it, and pull it into the original.

Check your work: git remote -v shows the right address, git status -sb shows no ahead or behind on both folders, and git log --oneline is identical in both.

Summary & Next Lesson

Key takeaways

  • A remote is a full copy of your repository on another server. By convention the main one is named origin.
  • git push uploads commits, git pull downloads and merges them, and git clone copies a whole remote repository to your computer.
  • git pull is git fetch plus a merge. Fetch only updates your origin/... bookmarks.
  • git push -u origin main links your branch to the remote branch, once.
  • A rejected push means the remote has commits you lack: pull, resolve any conflict, and push again. Do not force.

Next lesson

You pushed commits, but how does GitHub know it is really you? The next lesson, "Authentication with GitHub (SSH keys or tokens)", covers the two safe ways to prove it and how to keep secrets out of your repository.

Self-check

  1. Which command sends your commits to the remote?
  2. What does git clone <url> set up for you that git init does not?
  3. What is the difference between git fetch and git pull?
  4. Why did the first push fail after you created the GitHub repository with a README?
  5. What does [behind 1] in git status -sb mean?
Show answers
  1. git push.
  2. It copies the history and creates a remote called origin that your branch tracks.
  3. git fetch only downloads new commits and updates your origin/... bookmarks. git pull fetches and then merges them into your current branch.
  4. The remote already had a commit (the README) that your local repository lacked, so Git refused to overwrite it.
  5. The remote branch has one commit that your local branch does not have.

References

  • Git project, Pro Git book, Working with Remotes. Supports: what a remote is, origin set by clone, git remote add and -v, fetch versus pull, push to origin, and rejected pushes when someone pushed first.
  • GitHub Docs, About remote repositories. Supports: the HTTPS and SSH URL forms of a GitHub repository.
  • Not verified from an authoritative page: the exact wording of --allow-unrelated-histories advice and the git status -sb output were checked only by running Git 2.44 locally.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.