Chapter 23: Git Pull from GitHub
Git pull from GitHub
Many people think git pull is just “download latest code” — but it’s actually two commands glued together, and understanding what each part does will save you from 90% of the frustration and merge conflicts you see in the first few months.
I’m going to explain it like we’re sitting together debugging your laptop — slowly, with real examples, what you’ll actually see on screen, why it behaves the way it does, and how to use it safely in 2026.
What does git pull really do?
git pull = git fetch + git merge (by default)
Or in plain English:
- git fetch → “Go look at GitHub and download any new commits / branches / tags I don’t have yet — but don’t change my working files”
- git merge → “Now take whatever was just downloaded and try to merge it into my current branch”
So when you run:
|
0 1 2 3 4 5 6 |
git pull origin main |
Git actually does:
|
0 1 2 3 4 5 6 7 |
git fetch origin main git merge origin/main |
That’s why sometimes you see:
- “Already up to date” (nothing new on GitHub)
- Fast-forward message (clean catch-up)
- Merge commit created
- Or… CONFLICT (the scary part)
Why not just one command? Why two steps?
Because separating fetch and merge gives you control:
- You can fetch first → look at what changed (git log ..origin/main) → decide if you want to merge
- You can fetch → rebase instead of merge (git pull –rebase) → cleaner history
- In teams → fetch often, merge carefully
But most people just type git pull every morning — and that’s fine as long as you understand what’s happening underneath.
Hands-on Example – Let’s Do It Step by Step
Assume you have a repo already connected to GitHub (from previous lessons):
|
0 1 2 3 4 5 6 7 |
cd my-todo-app git remote -v # should show origin git@github.com:Webliance/my-todo-app.git |
Scenario 1 – Someone pushed new work to GitHub (you need to update)
Imagine your teammate (or you from another laptop) added a new file app.js on GitHub.
You run:
|
0 1 2 3 4 5 6 7 |
git pull origin main # or shorter (if tracking is set): git pull |
Typical clean output (fast-forward):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), done. From github.com:Webliance/my-todo-app abc1234..def5678 main -> origin/main Updating abc1234..def5678 Fast-forward app.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 app.js |
→ Your local main moved forward automatically → New app.js appeared in your folder
Scenario 2 – You have local changes + remote has changes (merge or conflict)
You edited README.md locally but didn’t push yet.
Meanwhile teammate pushed a change to the same file on GitHub.
You run:
|
0 1 2 3 4 5 6 |
git pull |
Git says:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
remote: Enumerating objects: ... From github.com:Webliance/my-todo-app * branch main -> FETCH_HEAD Auto-merging README.md CONFLICT (content): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result. |
Now git status:
|
0 1 2 3 4 5 6 7 8 |
You are in the middle of a merge -- cannot proceed until conflicts are resolved. Unmerged paths: both modified: README.md |
Open README.md — Git added conflict markers:
|
0 1 2 3 4 5 6 7 8 9 10 |
<<<<<<< HEAD - Buy milk (your local change) ======= - Buy eggs (what came from GitHub) >>>>>>> origin/main |
Fix it:
- Decide what to keep (or combine both lines)
- Remove the <<<<<<<, =======, >>>>>>> markers
Then:
|
0 1 2 3 4 5 6 7 |
git add README.md git commit # Git auto-fills message "Merge branch 'main' of github.com:..." |
Done — merge complete.
Everyday Safe Workflow (what most people do in 2026)
Morning / before work:
|
0 1 2 3 4 5 6 7 |
git switch main # make sure you're on main git pull origin main # or just git pull |
If you have uncommitted changes:
|
0 1 2 3 4 5 6 7 8 |
git stash # temporarily save your mess git pull git stash pop # bring your changes back (may conflict) |
Or safer (recommended):
|
0 1 2 3 4 5 6 7 8 |
git fetch origin git log --oneline --graph --decorate main..origin/main # see what you'll get git merge origin/main # or git rebase origin/main for linear history |
git pull Options Cheat Sheet (very useful)
| What you want | Command | Result / When to use |
|---|---|---|
| Normal (fetch + merge) | git pull or git pull origin main | Default – most common |
| Fetch + rebase (clean linear history) | git pull –rebase | Very popular in 2026 – no merge bubbles |
| Only download (look first) | git fetch | Safe – see changes before merging |
| Force overwrite local changes | git fetch && git reset –hard origin/main | Dangerous – throws away local uncommitted work |
| Pull but don’t commit merge | git pull –no-commit | Inspect before final commit |
Quick Summary Table – git pull vs Related Commands
| Command | Downloads from GitHub? | Merges / changes files? | Safe if I have local changes? | Use when… |
|---|---|---|---|---|
| git fetch | Yes | No | Yes | Want to see what’s new without touching files |
| git pull | Yes | Yes (merge) | No (may conflict) | Want latest code now |
| git pull –rebase | Yes | Yes (rebase) | No (may conflict) | Want clean linear history |
| git merge origin/main | No (after fetch) | Yes | No | After manual fetch |
Got the feeling now? git pull = “get latest from GitHub and join it to my work” But always remember the two hidden steps: fetch first → then merge.
Next class?
- Want to practice real merge conflict resolution after pull?
- How to configure pull.rebase = true by default?
- Or move to pull requests / reviewing changes?
Just tell me — we’ll keep building together. You’re doing fantastic! 🚀
