After 6 months working with a codebase with over 3,000 commits from many contributors, I realized that default git log is nearly useless. Scrolling through hundreds of lines to find a colleague’s commit from last week — nobody has time for that. This post covers the options I use daily in production, not a comprehensive list from the docs.
The Problem with Default git log
Running git log with no arguments gives you a wall of commits in reverse chronological order. The default format takes up 5–6 lines per commit, the information isn’t concise, and there’s no way to see which branch is merging into which.
Three common approaches when you want to dig into commit history:
- GUI tools like GitKraken, Sourcetree — visual but unusable in the terminal and can’t be integrated into scripts
- GitHub/GitLab UI — convenient but internet-dependent, and you can’t view local branches that haven’t been pushed
- git log with options — runs anywhere, scriptable, faster
I’ve tried all three. I came back to the terminal for one specific reason: I needed to write a script that analyzes weekly commits for team progress reports. Only git log could do that without installing anything extra.
Filtering Commits by Author
The option I use most — especially during sprint reviews when I need to see a specific team member’s work:
# Filter by name or email
git log --author="Nguyen Van A"
git log --author="[email protected]"
# Regex works too — find everyone named Nguyen
git log --author="Nguyen"
# Combined: my commits from the last 2 weeks
git log --author="$(git config user.name)" --since="2 weeks ago"
--author matches by regex, not exact string. If your team has someone named “An” and “Anh”, --author="An" will catch both. Use email or add anchors like ^An$ for precision.
Filtering by Time
Git understands many different formats — from ISO dates to natural English. Both work:
# Relative time
git log --since="3 days ago"
git log --after="1 week ago"
git log --until="yesterday"
git log --before="2024-01-01"
# Specific time range
git log --since="2024-06-01" --until="2024-06-30"
# View this week's commits from the entire team
git log --since="monday" --format="%h %an %s"
--since and --after are aliases. Same with --until and --before. I prefer the --since/--until pair because it reads more naturally when combining both in one command.
Filtering by Commit Content and File
There are two ways to search — the right one depends on what you’re looking for.
Search by Commit Message
# --grep: search in commit message
git log --grep="fix" --grep="bug" # OR (default)
git log --grep="fix" --grep="auth" --all-match # AND
# Case-insensitive
git log --grep="hotfix" -i
# Find commits related to the login feature
git log --grep="login\|auth\|authentication" -i --format="%h %s"
Search by Code Changes
# -S: find commits that added or removed this string (pickaxe)
git log -S "password_hash"
git log -S "def calculate_tax"
# -G: search by regex in diff
git log -G "api_key.*=.*['\"]" --all
# Find who deleted this function
git log -S "def send_notification" --patch
-S finds commits where the number of occurrences of that string changed (added or removed). -G finds commits whose diff contains the regex. When tracing who removed a function, -S is more precise — it only reports commits that actually changed the occurrence count, not every commit that has that line in the diff.
Filter by File or Directory
# Commits that touched a specific file
git log -- src/auth.py
git log -- "*.sql" # wildcards need quoting
# Commits in a directory
git log -- src/api/
# Combined with other filters
git log --since="1 month ago" --author="Anh" -- migrations/
# View actual changes in that file per commit
git log -p -- config/settings.py
The -- before a path tells git this is a file/folder, not a branch name. Leaving it out usually still works — but if a filename matches a branch name, it breaks without warning.
Visualizing Branches with –graph and –pretty
This is where I tackle the problem I run into most: staring at git log output and still not understanding which branch merged into which.
Basics with –graph
# Simple graph
git log --graph --oneline --decorate
# View all branches
git log --graph --oneline --decorate --all
Output looks like this:
* a3f2c1d (HEAD -> main) fix: auth token expiry
* b1e9f8a Merge pull request #42 from feature/login
|\
| * c7d4e23 feat: implement JWT refresh
| * 9a1b5f0 feat: login endpoint
|/
* 4f8c2d1 refactor: extract user service
Custom Format with –pretty
The default format is too verbose. Here’s what I use daily:
# Compact format with color
git log --graph --pretty=format:"%C(yellow)%h%Creset %C(cyan)%an%Creset %C(green)(%ar)%Creset %s" --all
# More complete format for reports
git log --pretty=format:"%H|%an|%ae|%ad|%s" --date=short
Commonly used placeholders in --pretty=format::
%h— short hash,%H— full hash%an— author name,%ae— author email%ar— relative date (“3 days ago”),%ad— absolute date%s— commit message subject%C(color)— set color,%Creset— reset color
Aliases So You Don’t Have to Type Every Time
These three have been in my ~/.gitconfig for a long time:
# Add to ~/.gitconfig
git config --global alias.lg "log --graph --pretty=format:'%C(yellow)%h%Creset -%C(auto)%d%Creset %s %C(green)(%ar) %C(cyan)<%an>%Creset' --all"
git config --global alias.ll "log --oneline --decorate --all --graph"
git config --global alias.lw "log --pretty=format:'%C(yellow)%h%Creset %s %C(green)(%ar)%Creset' --date=relative"
# Then just use
git lg
git ll
Analyzing Real Project Progress
My team has 8 people. Every Friday, this script runs automatically to compile a sprint report:
#!/bin/bash
# weekly-report.sh
echo "=== Sprint Report: $(date +'%Y-%m-%d') ==="
echo ""
echo "--- Commit count by author ---"
git log --since="1 week ago" --format="%an" | sort | uniq -c | sort -rn
echo ""
echo "--- Files changed most ---"
git log --since="1 week ago" --name-only --format="" | sort | uniq -c | sort -rn | head -10
echo ""
echo "--- Commit timeline ---"
git log --since="1 week ago" --format="%ad %an: %s" --date=format:"%a %H:%M" --reverse
The “Files changed most” section turned out to be more useful than I expected. The most-touched files are usually where problems are brewing — or where two people are working in parallel without knowing it. Since we started using this report, merge conflicts on the team have dropped noticeably: everyone checks what others are working on before starting a new task.
Combining Filters: Real-World Examples
# Find my commits in June, Python files only, related to the database
git log \
--author="$(git config user.name)" \
--since="2024-06-01" --until="2024-06-30" \
--grep="db\|database\|migration" -i \
-- "*.py" \
--oneline
# Debug: view all changes to a function over the past 3 months
git log -G "def process_payment" --since="3 months ago" --patch -- payments/
# Audit: who committed directly to main without going through a PR
git log main --no-merges --since="1 month ago" --format="%h %an %s"
When to Use What
A summary from real-world experience — not theory:
- Quick debug:
git log --oneline --graph --all— see the entire branch tree in 2 seconds - Find who changed what:
git log --author --since -- path/to/file - Trace a bug:
git log -S "suspicious_function" --patch— see exactly where the code changed - Sprint reports:
git log --format --sincepiped tosort | uniq -c - Review a PR before merging:
git log main..feature-branch --oneline
GUI tools still have their place when explaining things to newcomers or visually reviewing line-by-line diffs. But when you need to filter by person, time, file, and content — all at once — the terminal is faster and doesn’t require clicking.

