log, and the flags that make it useful
-S is the one people do not know and then use forever: it searches the changes, not the messages. "When did this function get deleted?" is one command.
git log # full entries, newest first
git log --oneline # one line each: short id, refs, subject
git log --oneline --graph --all # every branch, drawn
git log -3 # the last three
git log --author=Ulvi
git log --since="2 weeks ago"
git log -- src/app.js # only commits that touched this file
git log -S "unit_price" # commits where that text appeared or disappeared
What a commit actually holds
That is the whole thing: a pointer to a tree (the snapshot), zero or more parents, who wrote it and when, who committed it and when, and the message. The id is the SHA-1 of exactly those bytes — change one character of the message and every commit after it gets a new id too.
$ git cat-file -p HEAD
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
parent 23fd5c39421cd8b4e20350dea0eb1165a25f3e9f
author You <you@example.com> 1700000060 +0000
committer You <you@example.com> 1700000060 +0000
Add the fitting notes
The author wrote the change; the committer created this commit object. They differ when someone applies your patch, and after a rebase — which is why a rebased commit keeps its original author date and gets a new committer date.
Naming a commit without typing forty characters
HEAD # where you are
HEAD~1 # its parent (HEAD~ for short)
HEAD~3 # three back, first parent each time
HEAD^2 # the SECOND parent — only a merge has one
main # the commit that branch points at
832dbe3 # any unambiguous prefix of the id
v1.2 # a tag
git rev-parse HEAD~2
git show HEAD~2 --oneline
show and diff
git show HEAD # the commit and its changes
git show 832dbe3:price-list.md # a file AS IT WAS in that commit
git diff # working tree vs index — what is not staged
git diff --staged # index vs HEAD — what the next commit will contain
git diff main..feature # everything on feature that is not on main
git diff main...feature # …since they diverged (the one CI uses)
Who wrote this line, and why
The useful move is blame → take the commit id → git show it. The message and the rest of the change usually explain the line that made no sense, which is the best argument there is for writing decent messages.
git blame price-list.md # every line, with the commit that last touched it
git log -p -- price-list.md # the whole story of one file, with diffs