For the dev who knows the vocabulary but has never built the mental model. We'll go slow. No walls of text — just diagrams and clear analogies.
That's the whole secret. A folder on your Mac becomes a repo (short for repository) the moment it has a hidden .git/ subfolder inside it. That hidden folder is the project's memory — every save, every branch, every author of every change. Remove .git/ and the folder becomes just files again.
Look at your own folders. ls -la ~/lab/projects/playground/ shows no .git/ — so playground is not a repo yet. But ls -la ~/lab/projects/migration/ shows .git/ right there — that one IS a repo. Same folders, different status. That hidden directory is the entire difference.
Every time you save your work with git commit -m "...", git takes a snapshot of every file in the repo at that moment and stamps it with a label. Each snapshot has a message (the words you wrote), an author (you, by email), a parent (the snapshot before it), and a unique hash — a 40-character ID like 8d4d8650abc....
The repo's history is just a chain of these snapshots. Newest one is called HEAD.
This is the one that trips everyone. A branch is not a folder. Not a copy of files. It's literally just a sticky note pointing at a commit. The note name is the branch name. When you commit, the note moves forward to the new commit automatically.
Make a new branch (git checkout -b dev) and you've just stuck a second note on the same commit. From here, main and dev can move independently. That's how you get "parallel versions" of your project: each branch is a different lineage of commits with its own sticky note.
Cloudflare Pages and Coolify both watch a specific branch. "When the main sticky note moves, redeploy the live site." Other branches can move freely without affecting production. That's where the whole dev/staging/prod pattern comes from — and we'll dive in fully in Lesson 4.
GitHub is just a server that holds a copy of your .git/. When you git push, you send your local commits up. When you git pull, you bring GitHub's commits down. That's the whole loop.
A push physically travels: your Mac → over HTTPS or SSH → GitHub's servers → GitHub's storage. GitHub then sends webhooks to anything watching the repo (Cloudflare Pages, Coolify) saying "new commits on main, come get them." Those services pull, build, and deploy — automatically.
A .gitignore is a plain text file at the root of your repo listing patterns of files git should never track. It's how you keep secrets out, build artifacts out, OS junk out, and giant generated folders out. Without it, your repo bloats and your .env ends up on GitHub.
node_modules/
.env
.env.local
.DS_Store
*.log
dist/
.cache/
"Should I .gitignore my CLAUDE.md and .claude/ folder?" No. They're useful context, and if your repo is private no one external sees them. If the repo is public, they're still fine — many indie devs ship their .claude/ setup publicly so others can reuse it. The only files you must rigorously keep out are secrets: .env, .mcp.json, anything with API keys or tokens.
A submodule is a way to embed one repo inside another. Sounds clean — you'd think: "I'll put each game in its own repo, and have playground link to them as submodules."
Don't. Submodules are notorious — they don't auto-update, clones need an extra --init flag, push order matters, and collaborators trip over them constantly. The whole modern web ecosystem has migrated away from them. There are three better answers for your situation, depending on what you want:
One repo. All sub-experiments live inside. Push once, deploy once. Lowest cost. We'll dig into this in Lesson 3.
Each sub-game lives in its own repo + its own deploy URL. Playground's portal page just embeds them via <iframe src="...">. Clean isolation, but harder to share state.
Each sub-game in its own repo. A build script downloads their latest release into playground/games/ before deploy. More machinery, more flexibility. Usually overkill until you have collaborators.
When Josh runs gh repo clone lovebuilt/playground on his Mac, GitHub sends him a fresh copy of the entire .git/ folder. Git then materializes every file from the latest commit on main into his working directory. Everything not in .gitignore shows up.
That includes CLAUDE.md, the .claude/skills/ folder, your plans/, your AGENTS.md — all of it. Josh opens Claude Code in the cloned folder, and his Claude sees the same context yours does.
gh is GitHub's own command-line tool. We verified you're authed as lovebuilt already. Most repo operations don't need the GitHub website at all once you know these:
.git/ inside.