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