Git Basics #4: Remotes — clone, fetch, pull, push, and What origin Really Is

7 min read

Everything up to “Git Basics #3: Branching and Merging — Fast-forward and 3-way” happened inside the .git directory on your computer. Commits, branches, and merges all work without a network. But in this state, a broken machine means losing the entire history, and there is no way to work together with other people. The remote repository solves both problems at once.

It runs in six parts.

  • #1 What Git is — the snapshot model and the three areas
  • #2 add, commit, status — what the staging area means
  • #3 Branching and merging — fast-forward and 3-way
  • #4 Remotes — clone, fetch, pull, push, and what origin really is ← this post
  • #5 Undoing changes — restore, reset, and revert
  • #6 GitHub and your first Pull Request

This post organizes the flow from clone, which replicates a remote repository, through fetch, pull, and push, which exchange work with the remote. Along the way we pin down what origin and origin/main — names many people use knowing only the name, not the identity — actually are.

git clone — replicates the entire history #

Work with a remote repository usually starts with clone.

Cloning a repository
$ git clone https://github.com/schoolofweb/sample-project.git
Cloning into 'sample-project'...
remote: Enumerating objects: 127, done.
Receiving objects: 100% (127/127), done.

What clone brings over is not just the latest files. The entire history, including every commit and every branch, is replicated. That is why, from the moment the clone finishes, git log and branch creation work without a network. The clone is not a limited copy with reduced features — you get one more complete repository, fully equal to the one on the remote.

What origin really is — just the default name for a remote #

Right after cloning, let’s check the list of remotes inside the repository.

Checking remotes
$ cd sample-project
$ git remote -v
origin  https://github.com/schoolofweb/sample-project.git (fetch)
origin  https://github.com/schoolofweb/sample-project.git (push)

origin is not a reserved word with special powers. It is just the default nickname automatically attached to the URL of the source repository when you clone. Instead of typing the long URL every time, you call it by the short name origin. If you dislike the name you can change it, as in git remote rename origin upstream, and you can register several remotes. The one thing to remember is that there is no magic in the name origin itself.

origin/main — a local pointer that remembers the remote #

List every branch and one unfamiliar name shows up.

Checking remote-tracking branches
$ git branch -a
* main
  remotes/origin/main

origin/main is not a branch on the remote server. It is a read-only pointer inside your repository that records where the remote’s main was pointing the last time you communicated with the remote. It is called a remote-tracking branch.

Your main and origin/main are different pointers
[remote repository (GitHub)]
A --- B --- C            ← main

[your repository]
A --- B --- C            ← origin/main (as recorded at the last communication)
              \
                D        ← main (HEAD, the commit you added)

When you make commit D locally, only your main advances and origin/main stays at C. Conversely, even if someone else pushes commits to the remote, your origin/main knows nothing about it until you communicate again. Once this structure is clear, the difference between fetch and pull becomes obvious.

git fetch — bring it in without touching anything #

fetch downloads new commits from the remote and updates only the remote-tracking branches.

Fetching the remote state
$ git fetch origin
remote: Enumerating objects: 5, done.
From https://github.com/schoolofweb/sample-project
   1a2b3c4..9f8e7d6  main       -> origin/main

The last line of the output is the key. The only thing updated is origin/main; your main and the files in the working directory stay exactly as they were. That is why fetch is safe to run at any time. You can bring things in, check what changed, and then decide whether to merge.

Checking the difference after fetch, then merging
$ git log main..origin/main --oneline   # commits that exist only on the remote
9f8e7d6 Fix login bug

$ git merge origin/main                  # merge into your main after checking

git pull — fetch and merge in one go #

pull is not a new command. It is a shorthand that runs fetch and then immediately runs merge.

pull is fetch + merge
$ git pull origin main
# equivalent to the two commands below
# git fetch origin
# git merge origin/main

For day-to-day work pull is convenient. But it means you merge without seeing what is coming down, so when the remote seems to have big changes or you are unsure of its state, the two-step fetch-then-merge is safer. Whenever pull feels confusing, unpacking it into fetch and merge clears up most of the confusion.

git push — upload your commits to the remote #

Reversing direction, push uploads your commits to the remote. Only the very first push of a new branch looks slightly different.

Pushing for the first time
$ git push -u origin feature-login
To https://github.com/schoolofweb/sample-project.git
 * [new branch]      feature-login -> feature-login
branch 'feature-login' set up to track 'origin/feature-login'.

-u is the upstream option. It records the fact that your feature-login is paired with the remote’s origin/feature-login. Record the pair once, and from then on a plain git push or git pull is enough, because Git already knows where to send to and where to receive from.

When push is rejected #

push does not always succeed. If someone else pushed to the remote after your last fetch, the remote is ahead of you, and Git rejects the push.

Push rejected
$ git push
To https://github.com/schoolofweb/sample-project.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs
hint: Updates were rejected because the remote contains work that you do not
hint: have locally.

This is a normal safety guard that keeps your push from overwriting commits on the remote. The order of the fix is fixed as well: receive the remote’s commits first, combine them with yours, then upload again.

The flow after a rejection
$ git pull      # receive the remote commits and merge them with yours
$ git push      # upload the combined result

If the pull produces a conflict, follow the conflict-resolution steps covered in the previous post.

Authentication — HTTPS and SSH #

push writes to the repository, so it requires authentication. There are two methods.

  • HTTPS — the URL starts with https://. On the first push, your operating system’s credential manager asks you to sign in to GitHub, and the saved credentials are reused afterwards. It is simple to start with, which suits the beginner stage.
  • SSH — the URL starts with git@github.com:. Register a public key with your GitHub account and communication happens without further authentication steps. It needs initial setup but is convenient once done.
Note
There is no difference in capability either way, so starting with HTTPS is perfectly fine for now. The SSH key registration steps are laid out in the GitHub official documentation under “Connecting to GitHub with SSH”.

Wrapping up #

Four key points from this post.

  • clone replicates not the latest files but the entire history, and origin is just the default nickname attached to the source URL.
  • origin/main is a read-only pointer inside your repository recording the remote’s state as of the last communication.
  • fetch is the safe checking step that updates only remote-tracking branches, and pull is the shorthand that runs fetch and merge in one go.
  • When push is rejected, the remote is ahead of you — combine with pull, then upload again.

We have not covered undoing yet. A file staged by mistake, a typo in the commit you just made, and a bug in a commit already pushed each call for a different way of undoing. In the next post, “Git Basics #5: Undoing Changes — restore, reset, and revert”, we sort out when each of the three commands is the one you need.

X