Viewing history: log, diff, show
Navigate the commit timeline to find when a line changed, who changed it, and exactly what the change was.
What you'll learn
- git log and its high-value flags for filtering and formatting
- Reading a single commit with git show and understanding short SHAs
- The three faces of git diff: working tree, staged, and commit-to-commit
Before you start
Every commit in a Git repository is a permanent snapshot with a unique identifier called a SHA (or hash) — a 40-character string like a3f8c21d.... You’ll almost always abbreviate it to the first 7 characters, which Git calls a short SHA: a3f8c21. These short SHAs are stable enough for everyday use and appear throughout the tools below.
HEAD is a special pointer that always points to the commit you’re currently on — usually the tip of the branch you have checked out. Think of it as “you are here” on a map.
git log — the commit timeline
Run git log in any repository and you’ll see the full commit history, most recent first. The default output is verbose. These flags turn it into something useful.
One line per commit
git log --oneline
e4b9f31 Fix null-to-empty conversion in user serializer
a3f8c21 Add pagination to /api/users endpoint
71dc409 Bump requests to 2.31.0
c0182de Initial project scaffold
Each line is a short SHA followed by the commit message subject. Fast to scan.
See branches and merges at a glance
git log --graph --oneline --all
* e4b9f31 (HEAD -> main) Fix null-to-empty conversion in user serializer
* a3f8c21 Add pagination to /api/users endpoint
| * 9b3aa17 (origin/feature/dark-mode) Add dark mode toggle
|/
* 71dc409 Bump requests to 2.31.0
* c0182de Initial project scaffold
The --all flag shows every branch, not just the current one. --graph draws the ASCII branch lines.
Limit to the last N commits
git log -n 5 --oneline
Show files changed per commit
git log --stat --oneline
e4b9f31 Fix null-to-empty conversion in user serializer
src/serializers/user.py | 3 ++-
tests/test_user_api.py | 9 +++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
--stat adds a summary of which files changed and by how many lines. Useful for quickly spotting which commit touched a file you care about.
Show the full diff for every commit
git log -p --oneline
This streams the patch (the actual line-by-line diff) for each commit. Combine with -n 5 to keep output manageable.
Filter by time
git log --since="2 weeks ago" --oneline
git log --since="2026-05-01" --oneline
Filter by author
git log --author="Alice" --oneline
Matches a substring of the author name or email.
Filter by file
git log -- src/serializers/user.py
Only commits that touched that specific file. The -- separator tells Git that what follows is a path, not a branch name.
The commit graph — HEAD and the chain
Commits form a linked list pointing backward in time. HEAD tracks whichever commit is current. When you make a new commit, HEAD advances automatically.
git show — inspect one commit
Once git log gives you a SHA, use git show to read that commit in full:
git show e4b9f31
commit e4b9f31d7a2c084f1b3e6d8950c2a1447f83bb91
Author: Alice Chen <alice@example.com>
Date: Thu Jun 5 14:22:10 2026 +0530
Fix null-to-empty conversion in user serializer
The downstream parser treats "" and null differently. Preserve null
from the DB rather than coercing to empty string.
diff --git a/src/serializers/user.py b/src/serializers/user.py
index 7c3a021..f4d19e8 100644
--- a/src/serializers/user.py
+++ b/src/serializers/user.py
@@ -18,7 +18,7 @@ class UserSerializer:
def serialize(self, user):
return {
"id": user.id,
- "bio": user.bio or "",
+ "bio": user.bio,
}
Lines starting with - were removed; lines with + were added. The surrounding unchanged lines give context.
You can also show only one file from a commit:
git show e4b9f31 -- src/serializers/user.py
git diff — three distinct comparisons
git diff means different things depending on what you pass to it. Mixing these up is a common source of confusion.
Working tree vs staging area (what you haven’t staged yet)
git diff
Shows changes in your files that you have not yet staged with git add.
Staging area vs last commit (what will go into your next commit)
git diff --staged
Shows the diff between what’s staged and what was in the last commit. This is exactly what will be recorded when you run git commit.
Commit vs commit
git diff a3f8c21 e4b9f31
Compare any two commits directly. Useful for reviewing what changed across a range of work. You can also use branch names:
git diff main feature/dark-mode
Or compare a commit to HEAD:
git diff a3f8c21 HEAD
git blame — who last touched each line
git blame annotates every line of a file with the commit SHA, author, and date that last modified that line:
git blame src/serializers/user.py
c0182de3 (Bob Kumar 2026-04-10 09:14:02 +0530 14) def serialize(self, user):
c0182de3 (Bob Kumar 2026-04-10 09:14:02 +0530 15) return {
c0182de3 (Bob Kumar 2026-04-10 09:14:02 +0530 16) "id": user.id,
e4b9f31d (Alice Chen 2026-06-05 14:22:10 +0530 17) "bio": user.bio,
c0182de3 (Bob Kumar 2026-04-10 09:14:02 +0530 18) }
Line 17 was last changed by Alice in commit e4b9f31d — and you now know exactly which commit to git show to read the full explanation. This is the answer to “who is responsible for this line and why?”
Putting it together — the debugging workflow
When something breaks:
git log --oneline -- path/to/file— find which commits touched that file.git show <sha>— read the full diff and commit message for the suspicious commit.git blame path/to/file— if you’re not sure which commit, blame shows exactly which line came from where.git diff <old-sha> <new-sha>— compare two points in time if you want to see the cumulative change across multiple commits.