Basics: The Daily Loop

This chapter teaches you the daily loop: stage changes, commit them, read history, and see what's different between where you are and where you've been.

The Cycle

Every session with git looks the same:

edit files → git status → git add → git commit → git log

Repeat until you ship. Learn each step well and 80% of git becomes muscle memory.

git status: What's Going On?

git status is the command you run most. It tells you where everything is.

git status
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   README.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        NEW_IDEA.md

no changes added to commit (use "git add" and/or "git commit -a")

Three categories:

  • Changes not staged for commit: you edited a tracked file but haven't run git add on those changes yet.
  • Changes to be committed: you did.
  • Untracked files: files git has never seen.

When you run git status and see nothing surprising, you're ready to commit or switch branches.

The short form is git status -s:

git status -s
 M README.md
?? NEW_IDEA.md

Two letters per file: the left is the index status, the right is the working tree status. M is modified, A is added, D is deleted, ?? is untracked.

git add: Stage Changes

git add moves changes into the staging area. You're not committing yet; you're building the next commit.

git add README.md        # stage one file
git add src/             # stage everything under src/
git add .                # stage everything in the current directory
git add -u               # stage modifications and deletions of tracked files (not new files)
git add -A               # stage everything, everywhere in the repo

The difference between git add . and git add -A catches people: . respects your current directory; -A doesn't.

git add -p: Partial Staging

You edited a file in two places but only want one change in this commit. Use -p for interactive staging:

git add -p README.md

Git shows each chunk (hunk) of the diff and asks what to do:

Stage this hunk [y,n,q,a,d,s,e,?]?

y stage it, n skip it, s split the hunk into smaller pieces, e edit the hunk manually, q quit. Once you're fluent with -p, your commits get a lot cleaner.

git restore: Undo in the Working Tree

Discard an unstaged change:

git restore README.md

The file goes back to the last committed version. Unstaged changes are gone. No warning. There's no way to get them back. Be sure.

Unstage a file (keep your changes, but take it out of the next commit):

git restore --staged README.md

In pre-2.23 git, both of these were spelled git checkout. git restore is clearer; use it.

git commit: Record It

Once your staged changes look right, commit them:

git commit -m "fix typo in README"

-m is the message. Keep it short. Chapter 12 covers message conventions in detail.

For a longer message, run git commit without -m and git opens your editor. The first line is the subject; blank line; then a body of any length. Write full sentences in the body explaining why, not what.

Fix rate limit off-by-one in login endpoint

The counter was compared with > instead of >=, which let one extra
request through per window. This caused bursts from one client to
briefly evade the limit.

Fixes #342.

That's a good commit message. You'll thank past-you six months from now when git blame lands on this line.

The All-in-One Commit

git commit -a stages all modifications and deletions of tracked files and commits in one shot. It skips new files. Handy when you're certain about what's changed:

git commit -am "tidy error messages"

If your change involves new files, -a isn't enough; git add them first.

git log: Read the Graph

git log walks the commit graph backwards from HEAD.

git log
commit 3f1a22c... (HEAD -> main)
Author: Ada Lovelace <ada@example.com>
Date:   Sun Apr 19 10:15:02 2026 +0000

    first commit

One commit per screen is verbose. Most people live in --oneline:

git log --oneline
3f1a22c (HEAD -> main) first commit

Add --graph to draw the branch shape as ASCII:

git log --oneline --graph --all
* 9b2f11a (HEAD -> feature/login) add login form
* 7a3e8c0 add auth scaffolding
| * 4d2c1b1 (main) fix typo
|/
* 3f1a22c first commit

Set this as an alias; you'll run it hundreds of times a day. Chapter 11 covers aliases.

--stat shows which files each commit touched and how much:

git log --stat

Useful filters:

git log --since="2 weeks ago"
git log --author="Ada"
git log --grep="rate limit"           # search commit messages
git log -- path/to/file               # history touching this file
git log -p -- path/to/file            # same, with diffs

git diff: What Changed?

git diff has four common modes. Knowing which one you want matters.

git diff                        # working tree vs staged (what you haven't added yet)
git diff --staged               # staged vs last commit (what will be in the next commit)
git diff HEAD                   # working tree vs last commit (everything uncommitted)
git diff main feature/login     # difference between two branches
git diff <sha1> <sha2>          # between two commits
git diff <sha1>..<sha2>         # same thing

The default side-by-side format gets hard to read on long diffs. A few alternatives:

git diff --word-diff
git diff --stat
git diff --color-words

If you have a GUI tool you prefer, configure it as difftool and use git difftool instead.

git show: Look at a Commit

git show <sha> prints the commit message and the diff the commit introduced:

git show 3f1a22c

Useful variations:

git show HEAD              # last commit
git show HEAD~1            # commit before last
git show HEAD~5            # five commits back
git show main              # tip of main
git show HEAD -- README.md # just this file's changes in that commit

HEAD~N means "N commits back along the first parent". You'll use this notation a lot.

.gitignore: Files Git Should Not See

Not every file belongs in the repo. Build artifacts, editor swap files, OS junk, secrets. Put patterns in .gitignore:

# .gitignore
*.log
node_modules/
dist/
.env
.DS_Store

One pattern per line. Patterns work on paths relative to the .gitignore (so node_modules/ in the repo root ignores node_modules/ anywhere beneath).

Already-tracked files keep being tracked even if they match a .gitignore pattern. If you added a file by accident:

git rm --cached .env         # stop tracking, keep the file on disk

A good starting .gitignore per language lives at github.com/github/gitignore. Copy one.

Common Pitfalls

Committing without reading git status. You shipped half of what you meant to commit. Read the output.

git add . at the repo root after generating files. A dist/ directory full of compiled JS ends up tracked. Check git status before you commit.

Using git checkout in tutorials. It still works but carries too many meanings. Use git switch for branches and git restore for files.

Long commit subjects. If the subject line is over ~72 characters, break it. Many tools truncate at 72.

Committing secrets. If you committed a password, API key, or private key, rewrite history immediately (Chapter 8) and rotate the secret. Removing it in a later commit is not enough.

Next Steps

Continue to 03-branches.md to work on more than one thing at a time.