→ From Coder to Shipper
From Coder to Shipper · Foundations

Git — Version Control

A time machine for your code: every change is saved, so you can go back, work in parallel, and ship together with other people.

← / → to navigate · EN/VI switch below

Why it exists

The 'final_final_v3' problem

Without version control, your code lives on one hard drive, file by file. Change something and pray.

Files multiply

index.html, index_v2.html, index_final.html, index_final_REAL.html — at 2 a.m. you have no idea which one is the truth.

One wrong save, everything is gone

An overwrite, a crash, a bad AI edit — and there is no 'undo' for a whole project.

You can't see the past

What did the code look like last Tuesday? Why did it break after that change? No way to know.

Alone is fine, together is chaos

Two people editing the same file on one laptop? Good luck deciding who wins.

Big picture

Git is a time machine with a share button

One idea: git keeps a full history of your project on your machine — and can sync that history with a copy on the internet (GitHub).

Your laptop
Working tree — the files you edit
.git folder — every snapshot, in order
git push →← git pull
The internet
network — just carries bytes
⇄
GitHub — "origin"
Remote repo — the shared copy of history
Teammates & servers pull from it
01
Part 1 · Mental model

The four rooms

Every git command moves things between four rooms: working tree → staging area → commits → the branch pointer.

Part 1 · the rooms

Working tree, staging, commits, branch

That's the whole vocabulary. Everything else is detail.

Working tree — your desk

The real files on disk, the ones you and AI edit. 'Current', but not yet saved in history.

Staging area — the tray

A checklist of exactly which changes will go into the next commit. You choose; git doesn't guess.

Commits — the photo album

Each commit = one snapshot of the whole project + a message. Snapshots stack up into history.

Branch — a movable name tag

Not a copy of the code — just a pointer that says 'latest snapshot so far = this one'.

Part 1 · how it moves

edit → add → commit

The one diagram to remember: you edit in the working tree, select changes into staging, and commit turns the tray into a new snapshot.

1 · Working tree
app.pyedited
styles.cssedited
git add
2 · Staging area
app.pyselected
git commit
3 · Commits (history)
C3fix loginmain →
C2add styles
C1first commit
Part 1 · a commit

What a commit actually is

A short ID, a message, and a frozen snapshot of the project. git log shows you the album.

terminal
git log --oneline

a1b2c3d  fix: handle empty search results
d4e5f6a  feat: add user profile page
0f9e8d7  first commit

Newest at the top. Each line = one snapshot you can always go back to.

Part 1 · the why

Why the tray? Why the photo?

Both answers are the same word: control. You decide exactly what is saved, and when.

Staging = control over WHAT

You can stage 1 of 5 changed files. The commit contains exactly what you put in the tray — nothing more, nothing less.

Classic use: stage the code fix, but not the .env file with your secrets.

Commits = control over WHEN

A commit is a save point you create deliberately. No auto-save, no accidents — history is a sequence of decisions.

Small, frequent commits = a fine-grained undo history.

02
Part 2 · The daily loop

status → add → commit

90% of a day in git is this three-command loop. Learn it until it's muscle memory.

Part 2 · the loop

The three commands

Check, choose, save. Repeat.

  1. 1

    git status — where am I?

    Lists changed and new files: 'you edited X, and Y is new'. The first thing to type whenever you're unsure.

  2. 2

    git add — put it in the tray

    git add app.py puts that file's current state into staging. git add . = everything changed.

  3. 3

    git commit — take the photo

    git commit -m "message" turns the tray into a new snapshot in history. The message is for future you.

Part 2 · status

git status: the compass

It tells you exactly where you are: what's edited, what's selected, what's brand new.

ops@vps — zsh
$ git status
On branch main
Changes not staged for commit:
modified: app.py
Untracked files:
styles.css
← 'modified' = edited, 'untracked' = git has never seen it
Part 2 · add + commit

Choose, then save

Two commands and a snapshot exists. The message is the only part you write yourself.

ops@vps — zsh
$ git add app.py
$ git commit -m "fix: login fails on empty form"
[main a1b2c3d] fix: login fails on empty form
1 file changed, 2 insertions(+), 1 deletion(-)
$ git status
On branch main
nothing to commit, working tree clean
← 'working tree clean' = everything is saved in history
Commit small, commit often. A commit is a save point, not a monument.
the only rule that matters
Part 2 · messages

What makes a good commit

You'll read these messages months later — or a teammate will. Write for that reader.

One thing per commit

Fixed the login bug = its own commit. The new icon = another. Mixing them makes undo impossible.

Present tense, short

"fix: handle empty form" — not "I fixed the thing with the form or maybe". A headline, not a diary.

The why, briefly

The diff shows WHAT changed. The message is for WHY — 'because the API now returns null'.

AI helps, you decide

Let AI draft the message from your changes — but keep it to one line you'd stand behind.

03
Part 3 · History & undo

Looking back & going back

History is the point. git can show you any past state — and put you back in it.

Part 3 · the readers

Three ways to look at the past

log = the list, diff = the comparison, show = one snapshot up close.

CommandIt answersWhen you use it
git logWhat happened, in what order?Always — the map of your history
git diffWhat changed, line by line?Before committing, or 'did I break it?'
git show a1b2c3dWhat did THAT one commit change?When a commit caused a problem
Part 3 · log

git log: the map of the past

--oneline = one line per commit. The habit: skim the map before you change anything.

ops@vps — zsh
$ git log --oneline
a1b2c3d fix: handle empty search results
d4e5f6a feat: add user profile page
9c8b7a6 fix: login fails on empty form
0f9e8d7 first commit
← newest first. Each line = one snapshot you can go back to
Part 3 · diff

git diff: see exactly what changed

Lines starting with + were added, lines with - were removed. The fastest way to answer 'did I break it?'.

terminal
git diff
--- a/app.py
+++ b/app.py
-price = 100
+price = 99   # black friday!

The diff is the truth: exactly what will go into the next commit.

Part 3 · undo

Three levels of undo

Ask: how far back do I want to go? Working tree → staging → history. Each level has its own undo.

Working tree — git restore

'I messed up this file, give me back the last committed version.' git restore app.py. The commits are untouched.

Staging — git restore --staged

'I staged the wrong file.' Take it out of the tray. The file on disk is untouched.

History — git reset

'That commit was a mistake.' Move the branch pointer back one step. The work is still recoverable — don't panic.

Part 3 · restore

Undo one file, keep the rest

The most common rescue: one file edited badly (often by an AI), everything else fine.

ops@vps — zsh
# oops — app.py got clobbered
$ git restore app.py
$ git status
On branch main
nothing to commit, working tree clean
← app.py is back to its last committed version. Other files untouched.
04
Part 4 · Branching

Branches: parallel universes

A branch is a pointer, not a copy. That's why creating one is instant and switching is free.

Part 4 · the mental model

A branch is just a name on a commit

The branch 'main' points at the newest snapshot. Every new commit slides the pointer forward. That's all.

Pointer, not a copy

Creating a branch copies nothing — it just pins a name to a commit. Milliseconds, zero cost.

Commits move it

Commit on 'main' and 'main' slides forward to the new snapshot. History is a chain; the branch is the label on its tail.

Many names, one chain

Ten branches can point at the same commit — or at different ones. They share history like family trees.

You're always on a branch

Even if you never make one, 'main' (or 'master') exists. Your commits go wherever the pointer stands.

Part 4 · the picture

Two branches, one family

You fork off from C2, add C3 on the feature branch, then merge back — main absorbs your work.

main C1first commit── C2add styles── C4merge feature
feature C3fix login── merges into main above →
Part 4 · the workflow

The branch dance

Four commands: cut a branch, work, go home, merge. That's the whole dance.

ops@vps — zsh
$ git switch -c feature/login
← creates feature/login AND switches to it (-c = create)
$ git commit -m "fix: login fails on empty form"
[feature/login c3d4e5f] fix: login fails on empty form
$ git switch main
$ git merge feature/login
Merge made by the 'ort' strategy.
← main now contains your fix. The branch did its job.
Part 4 · the why

Why everyone branches

Branches are how parallel work stops being a fight.

Work without clobbering

Mid-refactor? Move to a branch. 'main' stays stable for everyone else.

Experiments are free

Try a risky idea on a branch. It fails? Delete the branch — history is untouched.

One feature = one branch

The team convention: name it after the feature (feature/login, fix/broken-nav). Finish, merge, done.

It scales to teams

Ten people, ten branches, zero 'who overwrote my file?'. GitHub turns each branch into a reviewable Pull Request.

05
Part 5 · Remote & shipping

Your laptop is not the source of truth

The real project lives on a remote repo — usually GitHub. Your laptop is one of many copies.

Part 5 · the two copies

Local vs remote (origin)

Every clone gets a default remote named 'origin' — the repo it came from.

Local = your sandbox

Fast, private, offline. You commit here as often as you like — nobody's watching.

Remote = the shared truth

The copy on GitHub that teammates, servers and deploys all agree on.

origin = a name, not a place

git push origin main = 'send my main branch to the repo I named origin'. You can have many remotes.

They drift apart

You commit locally, teammates push remotely — the copies diverge. Syncing is a daily habit, not a big event.

Part 5 · the remote loop

clone once, then pull & push

clone = 'get a copy, wire it to origin'. After that, the loop is just pull in, push out.

ops@vps — zsh
$ git clone https://github.com/you/shop.git
cd shop ← you now have a full copy + history
$ git pull
← work, commit … then:
$ git push origin main
To https://github.com/you/shop.git
main -> main
← your commits now live on GitHub, visible to everyone
Part 5 · the four verbs

clone / fetch / pull / push

Two directions: the pull side (get) and the push side (send). fetch is the quiet one; pull = fetch + apply.

CommandWhat it doesIn plain words
git clone <url>Downloads a whole repo (code + history) and remembers its originStart of every project: 'give me a copy'
git fetchDownloads new commits from origin — but changes nothing on your laptop'Show me what's new out there'
git pullfetch + merge into your current branch'Bring the new stuff into my code'
git pushUploads your commits to origin'Publish my work — everyone can see it'
Part 5 · .gitignore

What git should never see

.gitignore lists patterns to skip. git status won't even mention these files — they stay local.

.gitignore
# secrets — never, ever commit these
.env
*.db

# generated stuff — easy to rebuild
__pycache__/
node_modules/
*.log
dist/

The pattern rule: if it can be regenerated, or if it's a secret — ignore it.

Part 5 · the rule

The 'never commit' list

Once a secret is in history, it's public — history doesn't forget, and neither do attackers.

Secrets — .env, keys, tokens

API keys, passwords, tokens. .env files are the #1 leak. Anyone can read your repo history.

Databases — *.db, dumps

Databases with real user data are private by nature. Commit a sample or a schema, not the data.

Caches — __pycache__/, .pyc

Python's bytecode cache. It rebuilds itself; in git it's pure noise.

Dependencies — node_modules/

Hundreds of MB of installed libraries. npm install rebuilds it from package.json.

Part 5 · shipping

Pushing is how you ship

Every real project lives in git. The repo is the single source of truth that everything else is built from.

You (laptop)
your commits
git push →
GitHub (origin)
the full history — one truth
clone / deploy →
Everyone else
teammates' laptops
servers & the deployed app
Wrap-up · your toolkit

The ~10 commands that are 95% of git

Memorize these and you can work with any project. The rest, AI and docs cover.

CommandJob
git statusWhere am I? What changed?
git add / git commitStage and save a snapshot
git log / git diff / git showRead the past
git restoreUndo one file (or one staging)
git switch (-c) / git branchMove between parallel lines of work
git mergeCombine a branch back into main
git clone / git pull / git pushGet the copy, keep it fresh, publish work
Git is a time machine with a share button.
the mental model in one line

git init. You're in.

Every project you'll touch in this course lives in git. status → add → commit → push. That's the whole shipper's loop.