Career OS

Git 03 — Remotes, PRs & Collaboration

Everything so far happened on your laptop. But the job is team work: your code on a server, teammates’ code arriving daily, changes reviewed before they touch main. This module connects your local git to GitHub and walks the real collaboration loop — fetch, push, pull request, review, merge — the exact cycle that ships every line of code at a product company.

The Goal

By the end of this module you can:

  • Explain what origin actually is — a named bookmark for a remote URL, not a magic GitHub link
  • Distinguish fetch from pull and say precisely why fetch is the safe first move
  • Describe a tracking branch and how it connects your local branch to one on the remote
  • Run the full pull-request workflow with the gh CLI — from branch to merged PR — without leaving the terminal
  • Choose between a fork and a branch and explain when each is the right model

The Lesson

A remote is a named URL — origin is just the default name

A remote is a bookmark: a short name that stands for a repository URL somewhere else (usually GitHub). When you git clone, git automatically creates one remote called origin pointing at the URL you cloned from. There’s nothing special about the name “origin” — it’s a convention, the default. You could rename it; you can add more (upstream is the common second one, covered under forks below).

git remote -v
origin  https://github.com/you/splitease-api.git (fetch)
origin  https://github.com/you/splitease-api.git (push)

Two lines because git tracks a fetch URL and a push URL separately (almost always identical). The mental model: origin is a label for “the GitHub copy.” Your local repo and the GitHub repo are two independent clones of the same history that you keep in sync by hand with fetch, pull, and push.

flowchart LR
    L[Your laptop repo] -->|push sends commits| R[GitHub repo - origin]
    R -->|fetch and pull bring commits| L

origin/main is a cached photo, not GitHub live

Here is the single most important idea in this module, and the one that clears up most “but GitHub says something different” confusion. When you git fetch, git downloads the remote’s commits and updates a set of remote-tracking branches — local pointers named origin/main, origin/feature, and so on.

origin/main is your machine’s cached snapshot of where GitHub’s main was at your last fetch. It is not live. git status and git log compare against this cached copy offline — they never phone GitHub themselves. So if a teammate pushed five minutes ago and you haven’t fetched, your tools still report “up to date” — up to date with old news.

This exact trap has its own real-error writeup — read fetch-updates-your-knowledge now, because internalizing “origin/main is a photo on my desk, fetch takes a fresh photo” is what stops you from being confused by remotes for the rest of your career.

fetch vs pull — the difference that matters

These are the two ways to bring remote changes down, and confusing them is how beginners get surprise conflicts.

git fetchgit pull
What it doesDownloads remote commits, updates origin/maingit fetch then git merge (or rebase)
Touches your working files?No — only updates your knowledgeYes — merges remote changes into your files
Can cause a conflict?NeverYes
When to useAnytime you want to see what’s incoming before actingWhen you’re ready to integrate remote changes now

git fetch is always safe — it changes no files and can never conflict. That makes it the right first move when you’re unsure what’s going on. Look before you leap:

git fetch
git log HEAD..origin/main --oneline   # what GitHub has that I don't yet
git status                            # now this answer is actually current

git pull is fetch + merge in one step — convenient, but it changes your working files and can drop a conflict on you mid-stride. Prefer git fetch then inspect when you want to see changes before they touch your files; use git pull when you already know you want them.

sequenceDiagram
    participant You as Your repo
    participant Origin as origin cache
    participant GH as GitHub
    You->>GH: git fetch
    GH-->>Origin: latest commits and branch tips
    Note over You,Origin: files unchanged - only knowledge updated
    You->>Origin: git merge origin main
    Note over You: now your files change - this is the pull half

When your local main is tracking origin/main, git knows they’re a pair. That link is what lets git status say “your branch is ahead of origin/main by 2 commits,” and what lets you type a bare git push or git pull without naming the remote and branch every time.

Clone sets this up automatically for main. When you create a new branch locally and push it the first time, you establish the link with -u (short for --set-upstream):

git switch -c add-rate-limit
# ...commit some work...
git push -u origin add-rate-limit

After that one-time -u, plain git push and git pull work on this branch. Check what’s tracking what:

git branch -vv
* add-rate-limit  a1b2c3d [origin/add-rate-limit] add token bucket
  main            f4e5d6a [origin/main] release v2

The bracketed name is the upstream each local branch tracks. No bracket means an untracked local-only branch — git push will refuse until you give it -u.

The pull request workflow — how code actually ships

Nobody pushes straight to main at a real company. The unit of change is a pull request (PR): you do work on a branch, push it, open a PR, a teammate reviews it, CI runs against it, and only then is it merged into main. The PR is where review and the automated checks (your CI/CD pipeline) gate every change.

flowchart LR
    A[Branch off main] --> B[Commit your work]
    B --> C[Push the branch]
    C --> D[Open a pull request]
    D --> E[Review plus CI checks]
    E --> F[Merge into main]
    F --> G[Delete the branch]

The whole loop, in the terminal, with the gh CLI (GitHub’s official command-line tool — free, and it means you never leave the keyboard for the browser):

gh auth login                                   # one-time: authenticate gh to GitHub
git switch -c add-rate-limit
# ...make changes, commit...
git push -u origin add-rate-limit
gh pr create --title "Add rate limiting" --body "Token bucket on the auth endpoint"
gh pr view --web                                # open it in the browser if you want
gh pr checks                                     # watch CI status from the terminal
gh pr merge --squash --delete-branch            # merge once approved and green

gh pr create opens the PR from your current branch against main. gh pr merge finishes the loop and cleans up the branch. Merge strategies you’ll choose between:

StrategyWhat it doesWhen
--mergeCreates a merge commit (two parents)Preserve the full branch history
--squashCollapses all branch commits into one on mainThe common default — keeps main history clean, one commit per feature
--rebaseReplays the branch commits onto main individuallyLinear history, no merge commit

Squash is the most common team default: your messy work-in-progress commits become one clean commit on main. This is the merge vs rebase trade-off from Git 02 showing up as a button in your daily workflow.

Forks vs branches — two collaboration models

Both isolate your work, but the access model differs:

BranchFork
Where it livesThe same repoYour own separate copy of the repo
Needs write access to the original?YesNo
Used forTeam members on a shared projectOutside contributors (open source) who can’t push to the original
PR comes fromA branch in the same repoA branch in your fork

Branch model: you’re on the team, you have write access, you push branches to the shared repo and open PRs there. This is your day job at a company — splitease-api with your teammates.

Fork model: you want to contribute to a project you don’t have write access to (any open-source repo). You fork it — GitHub makes a full copy under your account — clone your fork, push branches to your fork, and open a PR from your fork back to the original. The original is conventionally added as a second remote called upstream so you can pull in its updates:

gh repo fork owner/project --clone        # fork and clone in one step
git remote -v                              # origin = your fork, upstream = the original
git fetch upstream
git merge upstream/main                    # keep your fork current with the original

Rule of thumb: branch when you have write access, fork when you don’t. Inside a company you’ll almost always use branches; the first time you contribute to open source, you’ll use a fork.

Check The Concept

How This Shows Up At Work

  • The surprise conflict at pull. A teammate runs git pull on a stale branch, gets a wall of conflicts, and freezes. You git fetch + git log HEAD..origin/main first, see what’s coming, and decide calmly. The habit of fetch-then-look marks you as someone who understands remotes.
  • The PR that ships your feature. Every line of splitease-api you ever ship in a job goes through: branch → push → gh pr create → review → green CI → merge. Knowing the gh loop cold means you spend your energy on the code, not on fighting the tool.
  • The first open-source contribution. You find a typo in a library’s docs, fork it, fix it, and open a PR — your first commit in a stranger’s repo. Knowing fork-vs-branch is what makes that a 10-minute act instead of a confusing afternoon.
  • The interview question. “Walk me through how your team’s code gets from your laptop to production.” The answer is this module — remotes, tracking branches, PRs, review, merge. A clear walk-through signals you’ve actually worked on a team.

Build This

All in PowerShell, using your real GitHub account and the free gh CLI. You’ll create a repo, set up the remote, push a branch, and run a complete PR loop from the terminal. (gh is free and the most useful single tool on this list — install it from cli.github.com if you don’t have it.)

  1. Authenticate gh once (skip if already done) and create a throwaway repo:
gh auth login
gh repo create gh-pr-lab --private --clone
cd gh-pr-lab

gh repo create makes the repo on GitHub and clones it, so origin is already wired. Confirm:

git remote -v

You should see origin pointing at https://github.com/<you>/gh-pr-lab.git.

  1. Make a first commit on main and push it:
"# gh PR lab" | Out-File -Encoding utf8 README.md
git add README.md
git commit -m "Add README"
git push

Note git push worked with no -u — clone/gh repo create already set main to track origin/main. Confirm:

git branch -vv

main shows [origin/main] — that’s the tracking link.

  1. Branch, commit, and push with -u (the first push of a new branch needs it):
git switch -c add-license
"MIT" | Out-File -Encoding utf8 LICENSE.txt
git add LICENSE.txt
git commit -m "Add license file"
git push -u origin add-license

The -u created origin/add-license and linked them. Future pushes on this branch are bare git push.

  1. Open and inspect the PR from the terminal:
gh pr create --title "Add license file" --body "Adds an MIT license"
gh pr status
gh pr view

gh pr create opens a PR from add-license into main. gh pr view shows it in the terminal; add --web to open it in the browser.

  1. Merge it and watch the loop close:
gh pr merge --squash --delete-branch
git switch main
git pull
git log --oneline

--squash collapsed your branch into one clean commit on main; --delete-branch removed the merged branch on GitHub. Then git pull brought that merged commit down to your local main. The full ship cycle, all from PowerShell.

  1. Break it on purpose — feel the stale-cache trap. Make a change directly on GitHub (edit the README in the web UI and commit), then back in your terminal:
git status          # still says up to date - it has not fetched
git fetch
git status          # NOW it says behind origin/main by 1 commit

That’s fetch-updates-your-knowledge live: git status was reading a stale photo until fetch refreshed it. Finish with git pull to sync.

Interview Practice

Real remote/collaboration git questions from backend and fintech interviews. Answer out loud first.

1. What is origin?

origin is the default name git assigns to the remote you cloned from — a short bookmark standing for a repository URL (usually on GitHub). There’s nothing special about the name; it’s a convention. You can rename it, and you can add more remotes (commonly upstream for the original repo when you’ve forked). Your local repo and the remote are independent clones of the same history that you sync by hand with fetch, pull, and push.

2. What's the difference between git fetch and git pull?

git fetch downloads the remote’s commits and updates your remote-tracking branches (origin/main) but does not touch your working files — it just refreshes your knowledge, and can never cause a conflict. git pull is git fetch followed by git merge (or rebase) — it brings the changes down and integrates them into your working files, so it can produce conflicts. Best practice when unsure: fetch first, inspect with git log HEAD..origin/main, then decide.

3. What is origin/main and why might it be out of date?

origin/main is a remote-tracking branch — your machine’s cached snapshot of where GitHub’s main was at your last fetch. It’s local and offline; git status and git log compare against it without phoning GitHub. So if a teammate pushed after your last fetch, origin/main (and therefore git status) is stale until you git fetch again. Mental model: it’s a photo of GitHub on your desk; fetch takes a fresh photo.

4. What is a tracking (upstream) branch?

A tracking branch is a local branch linked to a specific remote branch, so git knows they’re a pair. That link lets git status report ahead/behind counts and lets you use bare git push/git pull without naming the remote and branch. Clone sets it up for main; for a new branch you create it with git push -u origin <branch> on the first push. git branch -vv shows each branch’s upstream in brackets.

5. Walk me through opening a pull request from the command line.

Branch off main (git switch -c feature), commit the work, push with git push -u origin feature to create and link the remote branch, then gh pr create --title ... --body ... to open the PR against main. From there gh pr checks watches CI, the team reviews, and once approved and green, gh pr merge --squash --delete-branch merges it and cleans up. Finally git switch main and git pull to bring the merged commit local.

6. Squash vs merge vs rebase when merging a PR — what's the difference?

--merge creates a merge commit with two parents, preserving every commit from the branch and recording that it was a unit. --squash collapses all the branch’s commits into a single new commit on main — the common default, because it keeps main’s history clean (one commit per feature) and hides messy work-in-progress commits. --rebase replays the branch commits onto main individually for a linear history with no merge commit. It’s the Git 02 merge-vs-rebase trade-off as a merge-button choice.

7. What's the difference between a fork and a branch?

A branch lives inside the same repository and requires write access — it’s how teammates on a shared project work. A fork is your own full copy of someone else’s repository under your account, needing no write access to the original — it’s how outside contributors work on projects they can’t push to (open source). With a fork you push to your copy and open a PR from your fork back to the original, usually adding the original as an upstream remote to stay current. Rule: branch when you have write access, fork when you don’t.

8. How do you keep your fork up to date with the original repo?

Add the original as a second remote (conventionally upstream): git remote add upstream <original-url>. Then git fetch upstream to download its latest, and git merge upstream/main (or rebase) into your local main, then git push to update your fork on GitHub. gh repo sync does the same in one command. This is why a fork needs two remotes — origin is your copy, upstream is the source of truth.

Where to Practice

ResourceWhat to do thereHow long
docs.github.comRead “About pull requests” and the gh CLI manual — official, free, and the source of truth for the workflow40 min
git-scm.comPro Git chapter 2.5 “Working with Remotes” and 5.x “Distributed Git” (fork model) — free official book45 min
Your own gh-pr-lab repoRedo the Build This from memory: create repo, branch, push with -u, open and merge a PR, all via gh30 min

Check Yourself

  1. What is origin, and is the name special?
  2. What does origin/main represent, and why can it be out of date?
  3. State the difference between git fetch and git pull, and which is safe to run anytime.
  4. What is a tracking branch, and how do you set one up for a new local branch?
  5. List the steps of the PR workflow from branch to merged, using gh.
  6. What’s the difference between --squash, --merge, and --rebase when merging a PR?
  7. When do you use a fork instead of a branch?
  8. Why does a fork-based contributor usually have two remotes, and what are they?
Answers
  1. origin is the default name git gives the remote you cloned from — a bookmark for a repo URL. The name is just a convention, not special; you can rename it or add more.
  2. It’s your machine’s cached snapshot of the remote’s main at your last fetch — a local, offline pointer. It’s stale whenever someone pushed after your last git fetch.
  3. fetch downloads commits and updates origin/main without touching your files (never conflicts, always safe). pull is fetch + merge — it changes your files and can conflict. fetch is the safe anytime move.
  4. A local branch linked to a remote branch so git knows they’re a pair (enables ahead/behind and bare push/pull). Set it up on a new branch’s first push with git push -u origin <branch>.
  5. Branch off main → commit → git push -u origin <branch>gh pr create → review + CI checks → gh pr merge --squash --delete-branchgit switch main + git pull.
  6. --merge keeps all commits via a two-parent merge commit; --squash collapses the branch into one commit on main (clean history, common default); --rebase replays commits individually for a linear history.
  7. When you don’t have write access to the repo (e.g. contributing to open source). Branch when you have write access; fork when you don’t.
  8. origin points at their own fork (where they push), upstream points at the original repo (where they fetch updates from to stay current).

Explain it out loud: Explain to an empty chair how one line of code travels from your laptop to production — name every step (commit, push with tracking, PR, fetch/review, CI, merge, pull) and explain why git status can lie until you fetch. If you stumble on fetch vs pull, re-read that section.

Why AI Can’t Do This For You

AI can generate gh pr create commands all day. What it can’t do is know that your origin/main is stale because you haven’t fetched, that this branch was already pushed so a force-push would wreck a teammate, or that the right merge strategy for your team is squash because that’s the convention they agreed on. Those facts live in your remote and your team’s habits, not in any prompt.

And when “GitHub says something different from my terminal” at 11pm, the engineer who knows origin/main is a cached photo — and that git fetch is the free, safe way to refresh it — solves it in seconds. The collaboration loop isn’t knowledge you can paste in; it’s a reflex you build by pushing branches and shipping PRs until the remote model is something you feel.

Module done? Add it to today’s tracker

Saves your progress on this device.