Skip to content

rev-list Git Command Guide

The git rev-list command lists commit objects in reverse chronological order by following parent links from given commits. It performs set operations on commits and is the underlying engine for many Git commands that work with commit ranges and history traversal.

Terminal window
git rev-list [<options>] <commit>... [--] [<path>...]
OptionDescription
-n <number>, --max-count=<number>Limit number of commits
--skip=<number>Skip number of commits
--since=<date>, --after=<date>Show commits after date
--until=<date>, --before=<date>Show commits before date
--author=<pattern>Limit to commits by author
--committer=<pattern>Limit to commits by committer
--grep=<pattern>Search commit messages
OptionDescription
--parentsInclude parent information
--childrenInclude children information
--left-rightMark which side of symmetric diff
--cherry-markMark equivalent commits
--cherry-pickOmit equivalent commits
--boundaryOutput excluded boundary commits
OptionDescription
--onelineAbbreviated commit info
--pretty=<format>Pretty print with format
--headerShow commit headers
--timestampShow raw timestamp
--relative-dateShow relative dates
OptionDescription
-- <path>...Show only commits affecting paths
--followFollow file renames
--no-mergesDon’t show merge commits
--mergesShow only merge commits
--first-parentFollow only first parent
--not <commit>Exclude commits reachable from
OptionDescription
--bisectMark commits for bisection
--bisect-varsShow bisect variables
--walk-reflogsWalk reflog instead of commit history
--countCount commits instead of listing
--graphShow commit graph
ParameterDescription
<commit>...Starting commits for traversal
<path>...Limit to commits affecting paths
Commit Range Syntax:
├── A..B: Commits in B but not in A
├── ^A B: Commits reachable from B but not A
├── A...B: Symmetric difference (in A or B but not both)
├── --not A: Exclude commits reachable from A
└── --all: Include all references
Visual Representation:
A---B---C---D (main)
\
E---F (feature)
main..feature: E, F
feature..main: (empty)
main...feature: C, D, E, F
Traversal Rules:
├── Start from given commits
├── Follow parent pointers backwards
├── Include all reachable commits
├── Exclude commits marked with ^
├── Apply filters and limits
└── Output in reverse chronological order
Example Traversal:
git rev-list A B ^C
= (commits reachable from A OR B) MINUS (commits reachable from C)
Path Filtering:
├── Only commits that modify specified paths
├── Follows file renames with --follow
├── Can combine with commit ranges
├── Useful for file-specific history
└── More efficient than git log -- <path>
Terminal window
# List recent commits
git rev-list HEAD
# List commits with limit
git rev-list -n 10 HEAD
# List commits with parents
git rev-list --parents HEAD
# Count commits
git rev-list --count HEAD
Terminal window
# Commits in feature but not main
git rev-list main..feature
# Symmetric difference
git rev-list main...feature
# Exclude specific commits
git rev-list HEAD ^abc123
# Multiple starting points
git rev-list branch1 branch2 ^main
Terminal window
# Commits from last week
git rev-list --since="1 week ago" HEAD
# Commits before specific date
git rev-list --until="2023-01-01" HEAD
# Commits between dates
git rev-list --since="2023-01-01" --until="2023-12-31" HEAD
Terminal window
# Commits by specific author
git rev-list --author="John Doe" HEAD
# Commits matching message pattern
git rev-list --grep="fix" HEAD
# Combine filters
git rev-list --author="Jane" --grep="bug" --since="1 month ago" HEAD
Terminal window
# Commits affecting specific file
git rev-list HEAD -- file.txt
# Commits affecting directory
git rev-list HEAD -- src/
# Multiple paths
git rev-list HEAD -- file1.txt file2.txt
# Follow renames
git rev-list --follow HEAD -- renamed-file.txt
Terminal window
# Only merge commits
git rev-list --merges HEAD
# Exclude merge commits
git rev-list --no-merges HEAD
# First parent only (ignore merged branches)
git rev-list --first-parent HEAD
# Show merge boundaries
git rev-list --boundary main..feature
Terminal window
# Show commit relationships
git rev-list --parents HEAD
# Show left-right marks for ranges
git rev-list --left-right main...feature
# Cherry pick analysis
git rev-list --cherry-mark upstream...topic
# Count commits between points
git rev-list --count main..feature
Terminal window
# Mark commits for bisection
git rev-list --bisect bad-commit..good-commit
# Show bisect variables
git rev-list --bisect-vars bad-commit..good-commit
# Custom bisect range
git rev-list --bisect HEAD~100..HEAD
Terminal window
# Configure default behavior
git config log.date relative # Relative dates
git config log.follow true # Follow renames
git config log.showSignature false # Hide signatures
# Configure pretty formats
git config pretty.oneline "%h %s" # One line format
git config pretty.short "%h %s%n%b" # Short format
# Configure search patterns
git config grep.patternType fixed # Exact matches
git config grep.extendedRegexp true # Extended regex
Terminal window
# Use --count for counting only
git rev-list --count HEAD # Faster than wc -l
# Limit output for large repos
git rev-list -n 100 HEAD
# Use --since for time ranges
git rev-list --since="1 month ago" HEAD
# Combine filters efficiently
git rev-list --author="John" --grep="fix" --since="1 week ago" HEAD
Terminal window
# Avoid full history traversal
git rev-list -n 50 HEAD # Limit results
# Use specific starting points
git rev-list v1.0..HEAD # Limited range
# Cache results when possible
git rev-list --all | head -1000 > commit-cache.txt
# Use --no-walk for specific commits
git rev-list --no-walk HEAD~10..HEAD
#!/bin/bash
# Analyze commits for release
release_commit_analysis() {
local previous_tag="$1"
local current_head="${2:-HEAD}"
echo "Analyzing commits since $previous_tag"
# Count total commits
total_commits=$(git rev-list --count "$previous_tag..$current_head")
echo "Total commits: $total_commits"
# Count merge commits
merge_commits=$(git rev-list --merges --count "$previous_tag..$current_head")
echo "Merge commits: $merge_commits"
# Count authors
authors=$(git rev-list --pretty="%an" "$previous_tag..$current_head" | grep "^[^commit]" | sort | uniq -c | sort -nr)
echo "Top contributors:"
echo "$authors" | head -5
# Check for large commits
echo "Commits with many changes:"
git rev-list --pretty="%h %s" "$previous_tag..$current_head" |
while read -r line; do
hash=$(echo "$line" | cut -d' ' -f1)
changes=$(git show --stat "$hash" | tail -1 | awk '{print $4+$6}')
if [ "$changes" -gt 100 ]; then
echo "$line ($changes changes)"
fi
done
}
release_commit_analysis "v1.0.0"
Terminal window
# Analyze commits for code review
code_review_analysis() {
local branch="$1"
local base="${2:-main}"
echo "Code review analysis for $branch vs $base"
# Find new commits
commits=$(git rev-list "$base..$branch")
echo "Commits to review: $(echo "$commits" | wc -l)"
# Check for WIP commits
wip_commits=$(echo "$commits" | xargs git show --pretty="%s" | grep -i "wip\|work\|temp" | wc -l)
if [ "$wip_commits" -gt 0 ]; then
echo "⚠ Found $wip_commits WIP commits"
fi
# Check commit message quality
empty_messages=$(echo "$commits" | xargs git show --pretty="%s" | grep -E "^.{0,10}$" | wc -l)
if [ "$empty_messages" -gt 0 ]; then
echo "⚠ Found $empty_messages commits with short messages"
fi
# Check for large commits
for commit in $commits; do
files=$(git show --name-only "$commit" | tail -n +2 | wc -l)
if [ "$files" -gt 20 ]; then
echo "⚠ Large commit $commit affects $files files"
fi
done
echo "Analysis complete"
}
code_review_analysis "feature/new-ui" "develop"
Terminal window
# Generate repository statistics
repo_statistics() {
echo "Repository Statistics"
# Total commits
total_commits=$(git rev-list --all --count)
echo "Total commits: $total_commits"
# Commits by author
echo "Commits by author:"
git rev-list --all --pretty="%an" | grep "^[^commit]" | sort | uniq -c | sort -nr | head -10
# Commits by month
echo "Commits by month:"
git rev-list --all --pretty="%ai" | cut -d- -f1-2 | sort | uniq -c | sort -nr | head -12
# Most active periods
echo "Most active days:"
git rev-list --all --pretty="%ai" | cut -d' ' -f1 | sort | uniq -c | sort -nr | head -10
# Branch analysis
echo "Branch commit counts:"
for branch in $(git branch --all | sed 's|* ||' | sed 's|remotes/||'); do
if git rev-parse --verify "$branch" >/dev/null 2>&1; then
count=$(git rev-list --count "$branch" 2>/dev/null || echo "0")
echo "$branch: $count commits"
fi
done | sort -t: -k2 -nr | head -10
}
repo_statistics

Performance Issues with Large Repositories:

Section titled “Performance Issues with Large Repositories:”
Terminal window
# Optimize for large repos
large_repo_revlist() {
echo "Optimizing rev-list for large repository"
# Use --no-walk for specific commits
git rev-list --no-walk HEAD~1000..HEAD
# Limit output
git rev-list -n 100 HEAD
# Use since/until for time ranges
git rev-list --since="1 month ago" HEAD
# Avoid full history traversal
git rev-list --all | head -10000
}
large_repo_revlist
Terminal window
# Handle memory constraints
memory_efficient_revlist() {
echo "Memory-efficient rev-list operations"
# Process in batches
git rev-list HEAD | xargs -n 1000 echo
# Use streaming output
git rev-list --oneline HEAD | head -10000
# Avoid storing large result sets
git rev-list --count HEAD # Just count
# Use --no-objects for commit-only info
git rev-list --no-objects HEAD
}
memory_efficient_revlist
Terminal window
# Debug complex commit ranges
debug_commit_ranges() {
local range="$1"
echo "Debugging range: $range"
# Show what the range includes
echo "Included commits:"
git rev-list "$range" | head -10
# Show boundaries
echo "Boundary commits:"
git rev-list --boundary "$range"
# Show left-right marks
echo "Left-right marks:"
git rev-list --left-right "$range" | head -10
# Verify range syntax
if ! git rev-list "$range" >/dev/null 2>&1; then
echo "Invalid range syntax"
exit 1
fi
}
debug_commit_ranges "main..feature"
Terminal window
# Handle path filtering problems
debug_path_filtering() {
local path="$1"
echo "Debugging path filtering for: $path"
# Check if path exists in history
if ! git log --oneline -- "$path" | head -1 >/dev/null 2>&1; then
echo "Path not found in repository history"
return 1
fi
# Show commits affecting path
git rev-list HEAD -- "$path" | head -10
# Check for renames
git rev-list --follow HEAD -- "$path" | head -10
# Compare with git log
log_count=$(git log --oneline -- "$path" | wc -l)
revlist_count=$(git rev-list HEAD -- "$path" | wc -l)
echo "git log count: $log_count"
echo "rev-list count: $revlist_count"
}
debug_path_filtering "src/main.js"
Terminal window
# Debug filtering problems
debug_filtering() {
local filter="$1"
local value="$2"
echo "Debugging $filter filtering for: $value"
case "$filter" in
"author")
git rev-list --pretty="%an <%ae>" HEAD | grep -i "$value" | head -5
;;
"grep")
git rev-list --grep="$value" HEAD | head -5
;;
"since")
git rev-list --since="$value" HEAD | head -5
;;
"until")
git rev-list --until="$value" HEAD | head -5
;;
esac
}
debug_filtering "author" "john"
#!/bin/bash
# Security audit using rev-list
security_audit() {
local since="${1:-1.month.ago}"
local audit_file="security-audit-$(date +%Y%m%d).txt"
echo "Security Audit Report - $(date)" > "$audit_file"
echo "Period: $since" >> "$audit_file"
echo "=================================" >> "$audit_file"
# Find commits by external contributors
echo "External contributor commits:" >> "$audit_file"
git rev-list --since="$since" --pretty="%h %an <%ae> %s" HEAD |
grep -v "@company.com" | head -20 >> "$audit_file"
# Find large commits (potential security issues)
echo -e "\nLarge commits (potential review needed):" >> "$audit_file"
git rev-list --since="$since" HEAD | while read -r commit; do
changes=$(git show --stat "$commit" | tail -1 | awk '{print $4+$6}')
if [ "$changes" -gt 500 ]; then
echo "$commit: $changes changes" >> "$audit_file"
fi
done
# Check for sensitive file modifications
echo -e "\nSensitive file modifications:" >> "$audit_file"
git rev-list --since="$since" HEAD -- "*.key" "*.pem" "*.secret" |
while read -r commit; do
echo "Sensitive files in: $commit" >> "$audit_file"
git show --name-only "$commit" | grep -E "\.(key|pem|secret)$" >> "$audit_file"
done
# Check for emergency commits
echo -e "\nEmergency/hotfix commits:" >> "$audit_file"
git rev-list --since="$since" --grep="emergency\|hotfix\|urgent" HEAD |
xargs git show --oneline >> "$audit_file"
echo "Security audit complete: $audit_file"
}
security_audit "2 weeks ago"
Terminal window
# Calculate development velocity
development_velocity() {
local period="${1:-1.month}"
local output_file="velocity-report-$(date +%Y%m%d).json"
echo "Calculating development velocity for $period"
# Total commits
total_commits=$(git rev-list --since="$period" --count HEAD)
# Commits by author
authors=$(git rev-list --since="$period" --pretty="%an" HEAD |
grep "^[^commit]" | sort | uniq -c | sort -nr |
awk '{print "{\"author\":\""$2"\",\"commits\":"$1"}"}' | paste -sd, -)
# Daily activity
daily_activity=$(git rev-list --since="$period" --pretty="%ai" HEAD |
cut -d' ' -f1 | sort | uniq -c |
awk '{print "{\"date\":\""$2"\",\"commits\":"$1"}"}' | paste -sd, -)
# Branch activity
branch_commits=$(for branch in $(git branch --all | sed 's|* ||'); do
if git rev-parse --verify "$branch" >/dev/null 2>&1; then
count=$(git rev-list --since="$period" --count "$branch" 2>/dev/null || echo 0)
echo "{\"branch\":\"$branch\",\"commits\":$count}"
fi
done | paste -sd, -)
# Generate JSON report
cat > "$output_file" << EOF
{
"period": "$period",
"total_commits": $total_commits,
"authors": [$authors],
"daily_activity": [$daily_activity],
"branch_activity": [$branch_commits],
"generated_at": "$(date -Iseconds)"
}
EOF
echo "Velocity report generated: $output_file"
echo "Total commits in period: $total_commits"
}
development_velocity "3 months ago"
Terminal window
# Integrate with CI/CD testing
ci_commit_testing() {
local base_commit="$1"
local head_commit="${2:-HEAD}"
echo "Testing commits from $base_commit to $head_commit"
# Get commits to test
commits_to_test=$(git rev-list "$base_commit..$head_commit")
echo "Found $(echo "$commits_to_test" | wc -l) commits to test"
# Test each commit individually
failed_commits=()
for commit in $commits_to_test; do
echo "Testing commit $commit..."
# Checkout commit
if git checkout -q "$commit"; then
# Run tests
if ! run-tests.sh; then
echo "✗ Tests failed for $commit"
failed_commits+=("$commit")
else
echo "✓ Tests passed for $commit"
fi
else
echo "✗ Could not checkout $commit"
failed_commits+=("$commit")
fi
done
# Return to original commit
git checkout -q "$head_commit"
# Report results
if [ ${#failed_commits[@]} -eq 0 ]; then
echo "✓ All commits passed testing"
return 0
else
echo "✗ Failed commits: ${failed_commits[*]}"
return 1
fi
}
ci_commit_testing "main" "feature/new-feature"
Terminal window
# Analyze repository history patterns
repository_archaeology() {
echo "Repository Archaeology Report"
echo "============================"
# Find oldest commit
oldest=$(git rev-list --reverse HEAD | head -1)
oldest_date=$(git show -s --format=%ci "$oldest")
echo "Oldest commit: $oldest ($oldest_date)"
# Find largest commits
echo -e "\nLargest commits by changes:"
git rev-list HEAD | while read -r commit; do
stats=$(git show --stat "$commit" | tail -1)
insertions=$(echo "$stats" | awk '{print $4}' | tr -d '+')
deletions=$(echo "$stats" | awk '{print $6}' | tr -d '-')
total=$((insertions + deletions))
echo "$commit: $total changes (+$insertions -$deletions)"
done | sort -t: -k2 -nr | head -10
# Find most active periods
echo -e "\nMost active months:"
git rev-list --pretty="%ai" HEAD | cut -d- -f1-2 | sort | uniq -c | sort -nr | head -12
# Find commit message patterns
echo -e "\nCommon commit message patterns:"
git rev-list --pretty="%s" HEAD | head -1000 |
sed 's/^[[:space:]]*//' | cut -d' ' -f1 | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -nr | head -20
# Find authors over time
echo -e "\nAuthor activity timeline:"
git rev-list --pretty="%ai %an" HEAD | awk '{print $1, $2, $3}' |
sort | uniq -c | sort -k2,3 | head -20
}
repository_archaeology
Terminal window
# Analyze potential merge conflicts
conflict_analysis() {
local branch1="$1"
local branch2="$2"
echo "Analyzing potential conflicts between $branch1 and $branch2"
# Find commits unique to each branch
branch1_commits=$(git rev-list "$branch2..$branch1")
branch2_commits=$(git rev-list "$branch1..$branch2")
echo "$branch1 unique commits: $(echo "$branch1_commits" | wc -l)"
echo "$branch2 unique commits: $(echo "$branch2_commits" | wc -l)"
# Find files modified by both branches
branch1_files=$(echo "$branch1_commits" | xargs git show --name-only | grep "^[^commit]" | sort | uniq)
branch2_files=$(echo "$branch2_commits" | xargs git show --name-only | grep "^[^commit]" | sort | uniq)
# Find overlapping files
overlapping_files=$(comm -12 <(echo "$branch1_files") <(echo "$branch2_files"))
if [ -n "$overlapping_files" ]; then
echo -e "\nPotentially conflicting files:"
echo "$overlapping_files"
# Analyze conflict risk
high_risk_files=$(echo "$overlapping_files" | while read -r file; do
branch1_changes=$(echo "$branch1_commits" | xargs git show -- "$file" 2>/dev/null | wc -l)
branch2_changes=$(echo "$branch2_commits" | xargs git show -- "$file" 2>/dev/null | wc -l)
echo "$file: $branch1_changes vs $branch2_changes changes"
done | sort -t: -k2 -nr | head -5)
echo -e "\nHigh-risk files:"
echo "$high_risk_files"
else
echo "No overlapping file modifications found"
fi
}
conflict_analysis "main" "feature/large-refactor"

What’s the difference between rev-list and log?

Section titled “What’s the difference between rev-list and log?”

git rev-list outputs raw commit hashes for scripting, while git log provides formatted, human-readable output. rev-list is faster and more suitable for automation.

How do I get commits between two branches?

Section titled “How do I get commits between two branches?”

Use git rev-list branch1..branch2 for commits in branch2 but not branch1. Use branch1…branch2 for symmetric difference (commits in either but not both).

Yes, use -n to limit commits, —since for time ranges, or —author for author filtering.

Use —count option: git rev-list —count . This is more efficient than piping to wc -l.

What’s the difference between A..B and A…B?

Section titled “What’s the difference between A..B and A…B?”

A..B shows commits reachable from B but not A. A…B shows commits reachable from either A or B but not both (symmetric difference).

How do I find commits affecting specific files?

Section titled “How do I find commits affecting specific files?”

Use git rev-list . Add —follow to track renames.

Yes, use —merges to show only merge commits, or —no-merges to exclude them.

Use —since=“1 week ago” for commits after date, —until=“2023-01-01” for commits before date.

—first-parent follows only the first parent of merge commits, ignoring merged branch history. Useful for understanding mainline development.

Yes, —bisect marks commits for bisection, —bisect-vars shows variables for bisect automation.

Use —author="" where pattern can be name, email, or partial match.

—boundary outputs the commits at the boundary of the range that would normally be excluded, useful for understanding range limits.

Yes, use —grep="" to search commit messages using regular expressions.

How do I get relative dates with rev-list?

Section titled “How do I get relative dates with rev-list?”

Use —pretty=“%ar %h %s” for relative dates, or configure log.relativeDate.

—cherry-mark marks commits that are equivalent (same diff) between two branches, useful for identifying duplicate work.

Yes, —walk-reflogs walks reflog entries instead of commit history, useful for analyzing reference changes.

How do I get commit parents with rev-list?

Section titled “How do I get commit parents with rev-list?”

Use —parents to include parent commit hashes in output.

—left-right marks commits with < (left side) or > (right side) for ranges, showing which branch they belong to.

Can rev-list be used for performance monitoring?

Section titled “Can rev-list be used for performance monitoring?”

Yes, combine with time commands to benchmark repository operations and identify performance bottlenecks.

  1. Commit Range Analysis: Analyze differences between branches and commits
  2. Repository Statistics: Generate metrics about development activity and patterns
  3. Automated Testing: Test specific commit ranges in CI/CD pipelines
  4. Code Review Automation: Analyze commits for review requirements and quality checks
  5. Security Auditing: Identify suspicious commits and track changes to sensitive files
  6. Development Velocity: Measure team productivity and contribution patterns