You’ve definitely heard of GitHub, and you’ve probably heard of GitLab — but where are they, exactly?
GitHub and GitLab are services that let you use Git (two completely different companies, by the way). Git itself is the thing doing the real work: it’s version control, which means it exists to preserve the different versions of a project as you build it.
You’ve probably made something small, broken it, and then mashed Ctrl-Z over and over trying to crawl back to the version that actually worked. What if you didn’t have to? What if you could take a copy of the whole project, make your edits over there, check whether they work, and then merge them back in?
That’s Git. Most tutorials stop at git add, git commit, git push — enough to save your code, but not how teams actually work. Let’s go further.
First, some terminology
A few words get thrown around constantly. Here’s what they actually mean:
- Repository (repo): the project itself — where your main code lives, along with all the offshoots you’re working on.
- Local repository: the copy on your own machine. Changes you make here don’t show up anywhere else until you run a few commands.
- Remote repository: the centralized copy — the one you’ve seen on GitHub. Other people can work on it with you, and you can pull from it yourself.
- Branch: think of it like a tree. The
main(ormaster) branch is the trunk — the code you know works. You copy everything from the trunk and branch off to try new code, without touching what already works.
Branches: the trunk and the offshoots
Imagine two developers editing the same file at the same time, both pushing straight to main. Every push would risk overwriting the other’s work. Chaos.
Branches fix that. A branch is an isolated copy of the codebase where you can work freely, without affecting anyone else. The typical loop looks like this:
- Start from
main(the stable, deployed branch) - Create a feature branch:
git checkout -b feature/my-change - Make commits on that branch
- Open a Pull Request to merge it back into
main - Someone reviews the code
- It gets merged
Try it
The widget below walks through those steps — create a branch, commit, open a PR, merge:
main.The commands you’ll actually run
Every Git command starts with git, so they’re easy enough to spot. Here are the ones you’ll reach for daily.
git clone
Whether it was an open-source tool or a Minecraft mod, many a young dev has stared at a GitHub page asking “now where the hell is the download button?” There isn’t one — there’s git clone.
Run git clone <url> in your CLI (command line interface) and it copies the entire repository — all the code and its history — down into a folder on your machine. Clone a repo you own, and that folder stays linked to the remote, so you can push your changes back up later.
git add .
This is usually the first command in your workflow. It adds new or changed files to the index — the staging area for what you’re about to commit. So every time you add, you’re lining changes up for the next step.
The . stages everything you’ve changed. Want to be picky? Pass a path instead:
git add . # stage everything
git add src/auth.ts # stage just one file
git rm
Need to get rid of a file? git rm <file> removes it from your working tree and the index in one move.
git commit
git commit takes everything sitting in your index and records it as a new commit at the tip of your current branch. (Technically: it creates a new commit whose parent is wherever HEAD points, then moves the branch forward to it.)
Good commit messages matter:
# Bad
git commit -m "fix stuff"
git commit -m "wip"
# Good
git commit -m "fix: handle null user in auth middleware"
git commit -m "feat: add email validation to signup form"
A useful convention is Conventional Commits: feat:, fix:, chore:, docs:, refactor:, test:. Future-you (and your teammates) will thank you.
Pull requests: merging, with a conversation
The phrasing is a little odd, but it clicks once you’ve done it. You’ve committed your changes to your branch — now you want to pull them into another branch (usually main) so the rest of the project gets them. Do this regularly and the code you’ve changed stays present going forward.
So why a request? On your own repo, you can merge as many pull requests as you want until you go blank in the face — go nuts. But the moment you’re working with other people (especially your boss), they’re going to review the request, see if it’s up to snuff, and kick it back to you with notes.
A Pull Request isn’t just a way to merge code — it’s a structured code review conversation. A good description documents:
- What changed
- Why it changed
- How to test it
It prevents wasted review time and makes your git history actually useful months later.
Merge conflicts: not scary, just math
Git keeps us from silently clobbering each other’s work — but there’s a catch. When two people change the same lines of the same file and both want to merge, Git can’t guess who’s right. It stops and makes you figure out who’s doing what, and to what.
When you open the file, you’ll see this:
<<<<<<< HEAD
const greeting = "Hello";
=======
const greeting = "Hi there";
>>>>>>> feature/new-greeting
- Everything between
<<<<<<< HEADand=======is your current branch’s version - Everything between
=======and>>>>>>>is the incoming branch’s version - Delete the markers and keep the version you want (or combine them)
Then git add the resolved file and git commit. Done — not so scary.
Your everyday cheat sheet
# Create and switch to a new branch
git checkout -b feature/my-thing
# See what branch you're on
git branch
# See uncommitted changes
git status
git diff
# Stage and commit
git add .
git commit -m "feat: add dark mode toggle"
# Push branch to remote and set upstream
git push -u origin feature/my-thing
# Pull latest changes from main
git pull origin main
# Merge main into your branch (stay up to date)
git merge main
# See log of commits
git log --oneline
# Undo last commit (keep changes)
git reset HEAD~1
What happens when you push to main directly at a job
You’ll probably be working on a team with branch protection rules. These are GitHub/GitLab settings that:
- Prevent direct pushes to
main - Require a PR with at least one approval before merging
- Require CI checks to pass before merging
This isn’t bureaucracy — it’s how production code stays stable.
The mental model
Think of main as a production train. Every feature is built in its own station (a branch). When it’s ready and reviewed, it gets loaded onto the train (merged). The train never stops for half-finished work.
That’s the whole workflow. Once this clicks, you can work on any team in the world.