Git, one command per page
The twenty-eight commands that cover everything you do every day.
Know the command. Lose the fear.
Git, one command per page
The twenty-eight commands that cover everything you do every day.
Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).
Command behaviour verified against the official Git documentation: git-scm.com/docs
Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.
© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.
Edition 1.0 · stevehodgkiss.net
Contents
Everyday
The six commands that carry a normal day, and what each one really moves.
- 01git status
- 02git add
- 03git commit
git status shows the three zones of a repository and what sits in each: working directory changes, staged changes, and the last commit. It changes nothing. Run it before acting.
git status
Let's say something feels off and your hand hovers over a scary command. Don't. git status first, every time: it shows what's changed, what's staged, and which branch you're on, and it touches nothing.
Most Git disasters start with a command typed into a situation the person had not looked at. The three zones it reports, working directory, staging area, last commit, are the mental model behind every other page in this book. Ten seconds of looking beats an hour of repairing.
Look before you touch.
git status
git add moves changes from the working directory into the staging area. You stage exactly what you mean, then commit exactly what you staged.
git add
Let's say you fixed a bug and, in the same files, left three debugging lines. `git add .` stages all of it, and the debugging lines ship. The dot is how junk gets into commits.
git add takes the file names you mean, one by one. The staging area is your shopping basket: fill it deliberately, check it with `git diff --staged`, then pay with a commit. The commit then contains exactly what you chose.
Stage what you mean. Not everything you touched.
git add app.js
git commit records the staged changes as a permanent snapshot with a message. Snapshots never change on their own; the message is written for whoever debugs later.
git commit
Let's say you commit with the message "fix" because you're in a hurry. In six months, someone finds that commit in a search, and "fix" tells them nothing. That someone is usually you.
A commit is a permanent snapshot plus a note to the future. The snapshot never changes, so make the note earn its place: what changed, and why. Small commits beat big ones too, because a small truthful commit can be reverted or cherry-picked on its own.
Write the message for six-months-from-now you.
git commit -m "Fix login timeout on slow connections"
Branches
Branches are labels, not copies. Once that lands, the scary commands stop being scary.
- 01git branch
- 02git merge
git branch lists, creates, or deletes branches. A branch is just a movable label pointing at a commit. Creating one copies nothing.
git branch
Let's say you avoid branching because it sounds like duplicating the whole project. It isn't. A branch is a sticky note on one commit, and it moves when you commit while it's the current branch.
That's the entire mechanism. Creating a branch is instant, deleting one is instant, and a hundred branches cost nothing. The fear of branching is the most expensive misunderstanding in Git. Branch per idea, and ideas stop colliding.
A branch is a label with confidence.
git branch feature/login
git merge joins two lines of history into a new merge commit with two parents. History is preserved exactly as it happened.
git merge
Let's say the feature is done and needs to come back to main. `git merge feature/login` creates one new commit with two parents, and the whole true story stays in history: the branch, the parallel work, the moment they joined.
Conflicts happen when both lines touched the same lines. Git marks them in the files, you pick, you commit. It's editing, not surgery. Merge is the safe default for shared branches, because it adds history instead of replacing it.
Merge tells the truth about what happened.
git merge feature/login
git push uploads your commits to the remote. It is rejected if the remote moved first. --force-with-lease overwrites only if the remote is where you last saw it.
git push
Let's say your push bounces with "non-fast-forward". That's not an error, it's protection: someone moved the remote, and pushing would erase their work. Fetch, integrate, push again.
The dangerous override is `--force`, which overwrites regardless. Use `--force-with-lease`, which refuses if the remote isn't where you last saw it, so a teammate's afternoon survives your rebase cleanup. Plain --force after no fetch is how shared branches die. A clean push history is boring, and boring is right.
If you must force, force with a lease.
git push origin main
Fixing mistakes
The undo family: which tool for which mistake, and the safety net underneath all of them.
- 01git reset
- 02git reflog
git reset moves the current branch back to an earlier commit. Soft keeps the changes staged, mixed keeps them unstaged, hard throws them away.
git reset
Let's say you committed twice and want them as one. `git reset --soft HEAD~1` moves the branch back one commit and leaves the changes staged, ready to re-commit. That's the everyday use.
The three modes are three dials: soft keeps everything staged, mixed (the default) unstages but keeps the files, hard rewrites your working directory too. And the golden rule: reset is for commits that live nowhere but your machine. If it's pushed, revert instead.
Soft squashes. Hard discards. Pushed means revert.
git reset --soft HEAD~1
git reflog records every move of HEAD, even the ones no branch remembers. Almost nothing in Git is truly gone until the reflog is pruned.
git reflog
Let's say you ran `git reset --hard` on the wrong branch and an afternoon of work vanished from every branch. Breathe. git reflog lists every place HEAD has ever been, including the commit you just fell off of.
Find the entry before the disaster, then `git reset --hard HEAD@{1}` or branch straight at the hash. Entries survive for months by default. The only real loss is work never committed or stashed. In Git, lost usually means mislaid.
The work is almost never gone.
git reflog