git status answers "what state am I in?" and git log answers "how did we get here?" — the two reading commands you will run more than all others combined. Learning their useful forms turns history from a wall of hashes into a working index.
status: the present tense #
$ git status
On branch main
Changes to be committed: # staged (git add ran)
modified: src/app.js
Changes not staged for commit: # tracked, changed after staging
modified: src/blog.js
Untracked files: # git has never seen these
scripts/new-build.py
Everything in status is one of those three areas. The short form -s compresses it — M staged, M unstaged, ?? untracked:
$ git status -s
M src/app.js
M src/blog.js
?? scripts/new-build.py
$ git status -sb # adds the branch and its tracking state
log: the past tense #
Plain git log is verbose. The two forms most people settle on:
$ git log --oneline -5
f3e2d1c fix: correct cache headers on media
b2c3d4e feat: paginate journal index
$ git log --oneline --graph --all -10
* f3e2d1c (HEAD -> main) fix: ...
| * 9a8b7c (feature/toc) wip: ...
|/
The graph form makes branches visible — which commit is on which line of development — and --all includes branches beyond the current one.
Filtering history #
| Goal | Command |
|---|---|
| One file's history | git log --oneline -- src/blog.js |
| Commits touching a function | git log -L :renderIndex:src/blog.js |
| By author | git log --author="ana" |
| Since a date | git log --since="2 weeks ago" |
| Content changes | git log -p -3 (patch per commit) |
| Commits containing a string | git log -S "cache-control" |
-S — the pickaxe — finds commits that added or removed a string anywhere in the codebase: the answer to "when did this stop working" before bisect even starts.
status discipline #
The habit that prevents most accidents: run git status before every staging decision and after every operation that moves history. It is free, instant, and the antidote to committing the wrong files or reviewing changes you forgot to stage.
The changes behind the hashes come from add and commit; what the remote has is a fetch away. The Git series continues.
