Introduction
git log walks the commit graph from a starting point (default: HEAD) backwards through parents, printing each commit. It is the primary tool for exploring project history.
Basic usage
git log
git log --oneline
git log --oneline --graph --decorate --all
The last form is the swiss-army view: a compact graph of every branch with refs decorated.
Filtering by date, author, message
git log --since="2 weeks ago"
git log --until=2025-01-01
git log --author="Ada"
git log --grep="bugfix"
git log -S "deprecated_function" # pickaxe: when did a string appear?
-S is invaluable for archaeology: it finds commits that change the number of occurrences of a string in any file.
Showing diffs
git log -p # full patch per commit
git log --stat # files changed plus +/- counts
git log --shortstat # summary line only
git log -p -- path/to/file # only commits touching a path
Custom formats
--pretty=format: accepts placeholders. A useful one-liner:
git log --pretty=format:"%h %an %ad %s" --date=short
%h abbreviated hash, %an author name, %ad author date, %s subject. See git help log for the full list.
Limits and ranges
git log -n 5 # last 5 commits
git log main..feature # commits on feature not on main
git log main...feature # symmetric difference
git log feature ^main # same as main..feature
Following file renames
Git does not record renames, it detects them. To follow history across a rename:
git log --follow -- path/to/file
Useful aliases
A handful of git log aliases pay for themselves in the first week. Two especially good ones:
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.recent "log --since='2 weeks ago' --author=$(git config user.email)"
git lg gives the bird's-eye graph; git last shows what just happened; git recent answers "what have I worked on lately?". Add an alias for any log invocation you type more than twice.
Reverse and limit
By default git log walks newest to oldest. Sometimes (release notes, code archaeology) you want the opposite, paired with a clean format:
git log --reverse --oneline v1.0.0..v1.1.0
git log --reverse --pretty=format:"* %s (%h)" v1.0.0..HEAD > CHANGELOG.draft
This is also where pickaxe and path filters earn their keep: git log --reverse -S "old_api" -- src/ shows the chronological history of a string's appearance and disappearance, perfect for tracing deprecations.
Common mistakes
Reading only HEAD's history and missing commits on other branches; pass --all to see them. Confusing --author (a regex on the author field) with a literal exact match; quote the pattern carefully. Using git log file instead of git log -- file: the -- separator disambiguates paths from refs, especially if a branch and a file share a name. Finally, expecting git log to show deleted commits after a force-reset; use git reflog for that. git log only walks reachable history.