Remotes: fetch, pull, push
Learn how commits travel between your laptop and GitHub — and how to get your teammates' work back without clobbering anyone.
What you'll learn
- What a remote is and why `origin` is the default name
- The critical difference between `git fetch` (safe download) and `git pull` (download + merge)
- How to handle a rejected push when the remote has commits you don't have yet
Before you start
The last chapter ended on exactly this realization: everything you have made so far lives only on your laptop, and the whole point was a team. This lesson is the handshake that ends the isolation. It rests on one new idea — a remote, a named address for another copy of your repo — and three verbs for moving commits across it: push, fetch, pull.
The distributed model in one sentence
Every git clone is a complete copy of the repository — history and all. There is no “master server” that holds the only real version. GitHub is just another copy that happens to be reachable over the internet and never goes to sleep.
Remotes are how Git tracks the addresses of other copies. A remote is nothing more than a named URL pointing to another repo. The convention is to call the first one origin — that is the copy you cloned from or the one you pushed to when you first shared your project.
Listing and adding remotes
After a clone, git remote -v shows the stored URLs:
git remote -v
origin https://github.com/yourname/my-project.git (fetch)
origin https://github.com/yourname/my-project.git (push)
Two lines per remote: one URL for downloading (fetch) and one for uploading (push). They are almost always identical.
If you started a repo locally with git init and now want to connect it to GitHub, add the remote by hand:
git remote add origin https://github.com/yourname/my-project.git
origin is just a name — you could call it github or upstream. But sticking to origin saves confusion with every tutorial and error message you will ever read.
Cloning: copy + wire up in one step
git clone https://github.com/yourname/my-project.git
git clone does three things at once: downloads the entire repository, creates a local directory, and automatically sets origin to the URL you gave it. After a clone you are ready to push and pull immediately.
The diagram: two repos, three arrows
git push sends your commits to origin. git fetch downloads theirs without touching your files. git pull fetches then merges.
Remote-tracking branches
After a fetch, Git stores what it downloaded in a remote-tracking branch — a read-only local reference like origin/main. You can inspect it:
git log origin/main --oneline
Your own main and the remote-tracking origin/main are separate pointers. They converge when you push or pull. This distinction is what makes git fetch safe: it updates origin/main without touching your working files or your local main.
Pushing for the first time: setting the upstream
git push -u origin main
The -u flag (short for --set-upstream) tells Git: “from now on, when I say git push or git pull on this branch, default to origin/main.” After that one-time setup you can type the short forms:
git push # same as: git push origin main
git pull # same as: git pull origin main
fetch vs pull — the key distinction
| Command | What it does | Touches your files? |
|---|---|---|
git fetch | Downloads remote commits into origin/main | No |
git pull | Fetch + merge origin/main into your current branch | Yes |
git fetch is the safer reflex: download first, look around, then decide how to integrate. git pull is the shortcut when you trust that the incoming changes will merge cleanly.
# safe pattern
git fetch
git log main..origin/main --oneline # see what arrived
git merge origin/main # integrate when ready
# shortcut
git pull
For a linear history (no merge commit), use:
git pull --rebase
This replays your local commits on top of the fetched commits instead of creating a merge commit.
The rejected push: non-fast-forward
Putting it all together: a typical day
# morning: get the team's latest work
git fetch
git log main..origin/main --oneline # see what came in overnight
git pull # merge it into your branch
# do your work, commit as usual
git add feature.py
git commit -m "add search filter"
# end of day: share your commits
git push
Quick reference
git remote -v # list remotes and their URLs
git remote add origin <url> # connect a new remote called origin
git clone <url> # clone a repo (sets origin automatically)
git push -u origin main # first push; sets upstream
git push # subsequent pushes (upstream already set)
git fetch # download remote commits, do not merge
git pull # fetch + merge
git pull --rebase # fetch + rebase (linear history)
In one breath
A remote is just a named URL for another copy of the repo; the first one is origin by convention, and git clone wires it up automatically. Three verbs move commits across it: git push sends your commits up (the first time, git push -u origin main sets the upstream so later you can type bare git push/git pull); git fetch downloads the remote’s commits into a read-only remote-tracking branch (origin/main) without touching your files — which is why it is the safe reflex; and git pull is fetch plus a merge into your current branch (--rebase for a linear one). If a teammate pushed first, your push is rejected as non-fast-forward — and the fix is always pull-then-push, never --force on a shared branch.
Practice
Before the quiz, work the rejection: you commit locally, run git push, and Git replies ! [rejected] ... (non-fast-forward). Explain in one breath what that message proves about origin/main versus your local main, the two-command fix that resolves it safely, and why reaching for git push --force here could quietly erase a teammate’s commit.
Quick check
A question to carry forward
You can now move commits in both directions — but look closely at what this lesson quietly assumed: that you push straight to main. On a real team, almost nobody does. Pushing finished work directly onto the branch everyone depends on, with no second pair of eyes, is how bugs and bad ideas slip in. So the actual workflow wraps everything you just learned in one more step: you push your feature branch instead, then open a pull request — a formal “please review and merge this” — where teammates read your diff, comment, approve, and only then does it join main. That social layer on top of push and pull is the GitHub flow, and it is the next lesson — the one that ties this whole section together.