Git History & Inspection
History inspection: who changed what, when, and why.
History Inspection
# WHO CHANGED WHAT
git blame file.txt # Line-by-line blame
git blame -L 10,20 file.txt # Lines 10-20 only
git blame -L '/function/,/^}/' file.txt # By pattern
git blame --since="2 weeks ago" file.txt # Recent changes only
# BLAME OPTIONS
git blame -w file.txt # Ignore whitespace
git blame -M file.txt # Detect moved lines
git blame -C file.txt # Detect copied lines
git blame -e file.txt # Show emails
# FILE HISTORY
git log --follow -- file.txt # Track renames
git log -p -- file.txt # With diffs
git log --stat -- file.txt # With stats
git log --oneline -- file.txt # Compact
# FIND WHEN CONTENT ADDED
git log -S "searchstring" --oneline # Commits adding/removing string
git log -G "regex" --oneline # By regex
git log -p -S "searchstring" # With diffs
# FIND WHEN BUG INTRODUCED
git bisect start
git bisect bad HEAD # Current is bad
git bisect good v1.0 # Known good version
# Git checkouts middle commit
# Test, then:
git bisect good # or git bisect bad
# Repeat until found
git bisect reset # Return to HEAD
# AUTOMATED BISECT
git bisect start HEAD v1.0
git bisect run ./test-script.sh
# Script exits 0 = good, 1-127 (except 125) = bad
# 125 = skip this commit
# COMMIT CONTENT
git show abc1234 # Full commit with diff
git show abc1234 --stat # Just stats
git show abc1234:path/to/file # File at that commit
git show abc1234^:path/to/file # File at parent commit
# COMPARE COMMITS
git diff abc1234 def5678 # Between commits
git diff abc1234..def5678 # Same
git diff abc1234...def5678 # Since common ancestor
Advanced Log Patterns
# LOG RANGE QUERIES
git log main..feature # Commits on feature not on main
git log feature..main # Commits on main not on feature
git log main...feature # Symmetric difference (unique to each)
# LOG BY AUTHOR/DATE
git log --author="Evan" --oneline # Filter by author
git log --since="2 weeks ago" --oneline # Time-based
git log --after="2024-01-01" --before="2024-02-01" # Date range
# LOG FORMAT
git log --pretty=format:"%h %ad %s" --date=short # Custom format
git log --pretty=format:"%h %an: %s" # Hash, author, subject
git log --graph --all --oneline # ASCII branch graph
# LOG DIFF FILTERS
git log --diff-filter=A -- '*.adoc' # Files added
git log --diff-filter=D -- '*.adoc' # Files deleted
git log --diff-filter=M -- '*.adoc' # Files modified
# LOG MERGE ANALYSIS
git log --merges --oneline # Only merge commits
git log --no-merges --oneline # Exclude merge commits
git log --first-parent --oneline # Follow first parent only
# SHORTLOG (summary by author)
git shortlog -sn # Commit count by author
git shortlog -sn --since="1 month ago" # Recent contributors
git shortlog -sne # Include emails
# DIFF STATS
git diff --stat HEAD~10..HEAD # Stats for last 10 commits
git diff --shortstat HEAD~10..HEAD # One-line summary
git diff --numstat HEAD~10..HEAD # Machine-readable stats
Infrastructure Repository History
# FIND WHEN CONFIG CHANGED
cd ~/atelier/_bibliotheca/domus-infra-ops
git log -S "vault-01" --oneline -- '*.adoc'
# Shows commits adding/removing vault-01 reference
# FIND IP ADDRESS CHANGES
git log -S "10.50.1.60" --oneline
# Track when this IP was introduced/changed
# TRACE RUNBOOK EVOLUTION
git log --oneline --follow -- docs/asciidoc/modules/ROOT/pages/runbooks/vault-ssh-ca.adoc
# BLAME FOR DOCUMENTATION
git blame docs/asciidoc/modules/ROOT/pages/runbooks/k3s-deployment.adoc | head -30
# See who wrote each line
# FIND BROKEN COMMIT
# Build started failing - find when:
git bisect start
git bisect bad HEAD
git bisect good HEAD~20
# Test build at each step
git bisect run make 2>&1 | tail -1 | grep -q "Site built"
# COMPARE DOCUMENTATION VERSIONS
git diff HEAD~10 -- docs/asciidoc/antora.yml
# What attributes changed?
# REVIEW RECENT CHANGES
git log --oneline --since="1 week ago" -- docs/
# All documentation changes this week
# SEARCH ACROSS HISTORY
git log -p -S "certmgr-01" --all -- '*.adoc'
# Find all changes involving old hostname
# MULTI-REPO HISTORY CHECK
for repo in domus-infra-ops domus-ise-linux domus-captures; do
echo "=== $repo ==="
git -C ~/atelier/_bibliotheca/$repo log --oneline --since="1 day ago"
done
# CHANGELOG GENERATION
git log --oneline --since="2024-02-01" --until="2024-03-01" -- docs/
# Generate monthly changelog
History Inspection Gotchas
# WRONG: Blaming without ignoring whitespace
git blame file.txt
# Shows reformatting commits, not meaningful changes
# CORRECT: Ignore whitespace changes
git blame -w file.txt
# Shows who wrote the actual logic
# WRONG: Using log -S with regex characters
git log -S "foo()" --oneline
# The () may not match literally
# CORRECT: Use -G for regex, -S for literal
git log -S "foo()" --oneline # Literal string match
git log -G "foo\(\)" --oneline # Regex match
# WRONG: Bisect without resetting
git bisect start
git bisect bad HEAD
git bisect good v1.0
# ... find the bug ...
# Forget to reset!
# Now on detached HEAD
# CORRECT: Always reset after bisect
git bisect reset # Return to original HEAD
# WRONG: Searching without --follow for renamed files
git log -- old-filename.txt
# Misses history before the rename
# CORRECT: Use --follow to track renames
git log --follow -- current-filename.txt
# WRONG: Comparing without fetching first
git log origin/main..HEAD
# Stale remote data!
# CORRECT: Fetch then compare
git fetch origin
git log origin/main..HEAD
# WRONG: Assuming blame shows original author
git blame file.txt
# May show whoever reformatted, not who wrote logic
# CORRECT: Use -C to detect copies, -M for moves
git blame -C -M file.txt
Quick Reference
# BLAME
git blame file.txt # Who changed each line
git blame -w -C file.txt # Ignore whitespace, detect copies
git blame -L 10,20 file.txt # Specific lines
# LOG SEARCH
git log -S "text" --oneline # Find text in history
git log -G "regex" --oneline # Regex search
git log --author="name" --oneline # By author
git log --since="1 week" --oneline # By date
# FILE HISTORY
git log --follow -- file.txt # Track renames
git log -p -- file.txt # With diffs
git show abc1234:path/to/file # File at commit
# BISECT
git bisect start # Start binary search
git bisect bad HEAD # Mark current as bad
git bisect good v1.0 # Mark known good
git bisect reset # Always reset after!
# COMPARE
git diff abc1234..def5678 # Between commits
git diff abc1234...def5678 # Since common ancestor
git log main..feature --oneline # Commits unique to feature
# STATS
git shortlog -sn # Commits per author
git diff --stat HEAD~10..HEAD # Changed files summary
See Also
-
Rewriting — reset, revert, amend, interactive rebase
-
Basics — log fundamentals
-
Filter-Repo — repository surgery