New: Try Voli The Bear, Fast package manager (and not only) for Windows

Try it in Practice →

Updated Jul 10, 2026 Edit on GitHub

The Everyday Commands - What Each One Really Does

In Phase 1 you learned the five ideas: commits are snapshots, branches are sticky-note labels, HEAD is "you are here," your work lives in three places, and the remote is another copy. Now we put them to work - the same commands you already type, but you'll know what each one is actually doing to those five things.

In a hurry? The cheat-card is right below. Want it to stick? Read the section under each command - that's where the "what just happened" lives.

The cheat-card

Command What it really does
git status What's changed, what's staged, what branch you're on. Your dashboard - run it constantly.
git add Move a file's current state into the staging area (the box for your next commit).
git commit Save a snapshot of everything staged, with a message. A save point you can return to.
git log The history of snapshots - who saved what, when, and why.
git diff The exact lines that changed (working vs staged vs last commit).
git branch List / create / delete the sticky-note labels that point at commits.
git switch / checkout Move HEAD ("you are here") to another branch or commit. switch is the modern, safer name.
git merge Combine another branch's commits into your current branch.
git fetch Download the remote's new commits but DON'T touch your files. Only look.
git pull fetch + merge: download remote commits and apply them now.
git push Upload your commits to the remote so others get them.
git stash Shelve uncommitted changes for a clean tree; pop them back later.

git status - your dashboard

Looks at all three places from Phase 1 - working directory, staging box, last commit - and reports how they differ, plus your current branch. Read-only; changes nothing. Run it constantly: before you add, before you commit, any time you're unsure what state you're in.

$ git status
On branch main
Changes to be committed:
  modified:   checkout.js
Changes not staged for commit:
  modified:   cart.js
Untracked files:
  notes.txt

What just happened: All three places at once. checkout.js is in the staging box (goes in your next commit). cart.js has edits not in the box yet. notes.txt is "untracked" - Git has never seen it and ignores it until you add it.

The gotcha. There isn't one, and that's the point - status never changes anything, so run it as often as you like. When in doubt, git status.

git add - put changes in the box

Copies the current state of a file into the staging box - it saves nothing to history, it's packing the box, not taping it shut. Reach for it right before committing, to choose exactly what goes in: edit ten files, commit only three, keep unrelated changes out of the snapshot.

$ git add checkout.js
$ git status
On branch main
Changes to be committed:
  modified:   checkout.js

What just happened: checkout.js moved into the box. Nothing is in history yet - you've only decided what the next snapshot will include.

The gotcha. add captures the file as it is right now. Edit it again afterward and those new edits aren't in the box - the file shows as both staged and not staged (you met this in Phase 1); git add it again to fix that. Many people reflexively run git add ., which boxes up everything - convenient, and also how stray files and stray debug code sneak into commits. Know what you're adding.

git commit - tape the box shut

Takes everything in the staging box and turns it into a permanent snapshot, whose parent is wherever HEAD is, then slides your branch's sticky note forward onto it (all five Phase 1 ideas in one command). Reach for it at every meaningful checkpoint - commits are free, make them often.

$ git commit -m "Fix tax rounding at checkout"
[main a1b2c3d] Fix tax rounding at checkout
 1 file changed, 3 insertions(+), 1 deletion(-)

What just happened: Git sealed the box into commit a1b2c3d, recorded its parent, and slid the main label onto it. The summary line is Git being friendly about what changed versus the parent.

The gotcha. commit only saves what's in the box - edited a file but forgot to add it? It won't be in the commit, and Git won't warn you (run git status first; see why it's a habit?). Also: git commit with no -m drops you into a text editor for the message. If that's Vim and you're trapped, type :q! and press Enter to escape without committing.

git log - the history of snapshots

Walks backward from HEAD, following each commit's parent pointer, and lists the snapshots it finds - how you read the chain from Phase 1. Reach for it to see what happened and when, or to find a commit's hash to point another command at.

$ git log --oneline
a1b2c3d (HEAD -> main) Fix tax rounding at checkout
9f2a1c7 Add login button
3e4f5a6 Initial commit

What just happened: Each line is a commit, newest first. --oneline squeezes each to its short hash and message. (HEAD -> main) on the top one marks the "you are here" arrow and the main label, both on the newest commit.

The gotcha. Plain git log can drop you into a full-screen pager - press q to quit. Two lifesavers: git log --oneline for the compact view, and git log --oneline --graph --all to see your branches drawn as a tree, the best way to make sense of a tangled history.

git diff - show me the actual lines

Compares two of your three places and shows the exact line-by-line changes between them - by default, working files against the staging box. Reach for it right before you add or commit, to review what you're about to include.

$ git diff
diff --git a/cart.js b/cart.js
@@ -14,7 +14,7 @@
-  const total = price
+  const total = price * quantity

What just happened: The change in cart.js that is not yet staged: one line removed, one added - the diff between your working file and the box.

The gotcha. This confuses everyone: once you git add a file, plain git diff shows nothing for it, because diff compares working-vs-box and add made them identical. Your change isn't gone, it's in the box - use git diff --staged to see what's there. Remember it as: plain diff = "not added yet," diff --staged = "added, about to commit."

git branch - manage the sticky notes

Lists, creates, or deletes branch labels. Creating one drops a new sticky note on your current commit - it does not move you onto it. Reach for it to start a new line of work or see what branches exist.

$ git branch
* main
  feature-login
$ git branch feature-cart

What just happened: The first command listed your branches (* marks the one you're on); the second created feature-cart on your current commit. You're still on main - creating a branch doesn't move you.

The gotcha. git branch feature-cart creates the branch but does not switch to it - people expect to "be on" the new branch and start committing, then find their commits landed on main. To create and switch in one step, use git switch -c feature-cart (next command).

git switch (and git checkout) - move "you are here"

Moves HEAD onto a different branch and updates your working files to match that branch's commit. switch is the modern, purpose-built command; checkout is the older one that also does several unrelated jobs. Reach for it every time you change what you're working on.

$ git switch -c feature-cart
Switched to a new branch 'feature-cart'

What just happened: -c created the feature-cart label and moved HEAD onto it in one step. Your next commit slides its sticky note forward, leaving main where it was.

The gotcha. checkout is overloaded - the same command switches branches, restores files, and detaches HEAD depending on how you call it. That's why git checkout . has erased people's work (it can mean "throw away my changes"). Modern Git split those jobs: git switch for branches, git restore for files - prefer them. Also: if uncommitted changes would be overwritten by a switch, Git blocks you - commit or stash first (see stash below).

git merge - combine two branches

Joins another branch's commits into your current one. If your branch hasn't moved since the other split off, Git slides your label forward ("fast-forward"); otherwise it creates a merge commit with two parents, stitching the histories together. Reach for it to bring a finished feature branch into main.

$ git switch main
$ git merge feature-cart
Updating a1b2c3d..f6g7h8i
Fast-forward
 cart.js | 24 ++++++++++++++++++

What just happened: Because main hadn't moved, this was a fast-forward - Git slid main's label up to feature-cart's commit. No merge commit needed; the histories were already in a straight line.

The gotcha. When both branches changed the same lines, Git can't decide which to keep and stops with a merge conflict. That's not you doing something wrong - it's Git refusing to guess. Phase 3 walks through resolving one calmly.

git fetch - download, but look before you leap

Downloads new commits from the remote into your local bookmark of its branches (like origin/main) without touching your own branches or files - "show me what's out there, don't change anything." Reach for it when you want to see what teammates pushed before deciding to integrate it.

$ git fetch
remote: Enumerating objects: 5, done.
From github.com:acme/shop
   a1b2c3d..b2c3d4e  main -> origin/main
$ git log --oneline main..origin/main
b2c3d4e Add promo banner

What just happened: Git downloaded the new commit and updated origin/main - your bookmark of the remote's main. Your own main hasn't moved. The second command lists what origin has that you don't.

The gotcha. fetch is safe because it doesn't touch your files - but that's also why people forget they've fetched and wonder why nothing looks different. Fetching updates your knowledge of the remote; merging (or pulling) is what brings those commits into your branch.

git pull - fetch and merge in one step

Two things back-to-back: git fetch, then git merge - a convenience combo. Reach for it when you want your branch caught up and expect the merge to be clean.

$ git pull
Updating a1b2c3d..b2c3d4e
Fast-forward
 banner.js | 18 ++++++++++++++

What just happened: Git fetched the "Add promo banner" commit and immediately fast-forwarded your main onto it. One command, fully synced.

The gotcha. Because pull merges automatically, it can drop you straight into a merge conflict (or a surprise merge commit) when you and the remote have both moved. Many people prefer git fetch, look, then merge deliberately - staying in control of when the merge happens. If a pull leaves you mid-conflict, Phase 3 has you.

git push - send your commits up

Uploads commits you have but the remote doesn't, and moves the remote's branch label forward to match yours - the mirror image of fetch. Reach for it to share your work: back it up, open a pull request, let teammates see it.

$ git push
Enumerating objects: 5, done.
To github.com:acme/shop.git
   b2c3d4e..c3d4e5f  main -> main
$ git push -u origin feature-cart

What just happened: The first push sent your commits and advanced origin's main. The second is what you run the first time you push a new branch: -u origin feature-cart creates the branch on the remote and links your local branch to it, so future push/pull need no arguments.

The gotcha. If the remote has commits you don't, Git rejects the push (fetch first) rather than bury history you haven't seen - pull, then push again. And a warning for later: git push --force overrides that safety and can erase your teammates' commits. Never force-push a shared branch. (The safe way to rewrite history is its own topic - guide #2.)

git stash - shelve it for a minute

Takes your uncommitted changes (staged and unstaged), saves them on a stack, and reverts your working directory to a clean state matching the last commit. Later, you pop them back. Reach for it when you're mid-change and need a clean tree right now - an urgent fix, or a pull without committing half-finished work.

$ git stash
Saved working directory and index state WIP on feature-cart: a1b2c3d
$ git switch main          # clean tree, so the switch is allowed
$ # ...do the urgent thing, then come back...
$ git switch feature-cart
$ git stash pop

What just happened: stash swept your in-progress edits onto a shelf, handing you a clean working directory so Git allowed the switch. stash pop later put those edits right back.

The gotcha. The stash is a stack, and it's easy to forget what's on it - stash twice, change context for a week, and you've got mystery shelves. Use git stash list to see them, and prefer git stash pop (applies and removes) so they don't pile up. For anything you want to keep more than a few hours, a real commit on a branch is safer than a stash.


You now speak Git

Every command above was moving the same five things from Phase 1: taking snapshots (commit), sliding labels (branch, merge, push), moving "you are here" (switch), shuffling work between the three places (add, diff, stash), or syncing copies (fetch, pull, push). None of it was magic - tools acting on a model you now understand.

Which means you're ready for the part that used to be terrifying: Phase 3 - When It Breaks, where things go wrong and you fix them without breaking a sweat.

Watch it animated: merging two branches


← Phase 1: The Mental Model · Guide overview · Phase 3: When It Breaks →

Try it yourself

Run commands and watch the history graph build - try commit -m "first", branch dev, checkout dev, commit -m "work", checkout main, then merge dev:

Before the quiz: without looking back, say (or jot down) the core idea of this phase in your own words.

Check your understanding 2 questions

1. How does `git fetch` differ from `git pull`?

2. After you `git add` a file, plain `git diff` shows nothing for it because...