name-rev Git Command Guide
The git name-rev command finds symbolic names suitable for human digestion for revisions given in any format parsable by git rev-parse. It helps make commit references more meaningful by associating them with branch names, tags, or relative positions.
git name-rev Syntax:
Section titled “git name-rev Syntax:”git name-rev [--tags] [--refs=<pattern>] [--exclude=<pattern>] [--all] [--annotate-stdin] [<commit-ish>...]Reference Selection Options:
Section titled “Reference Selection Options:”| Option | Description |
|---|---|
--tags | Only use tags to name commits (no branches) |
--refs=<pattern> | Only use refs matching shell pattern |
--exclude=<pattern> | Exclude refs matching pattern |
--no-refs | Clear previous ref patterns |
Input/Output Options:
Section titled “Input/Output Options:”| Option | Description |
|---|---|
--all | List all commits with their names |
--annotate-stdin | Read commits from stdin, write to stdout |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<commit-ish>... | Commits to find names for |
Understanding Name Resolution:
Section titled “Understanding Name Resolution:”Symbolic Name Types:
Section titled “Symbolic Name Types:”Branch names: master, develop, feature-xTag names: v1.0.0, v2.1.0Relative refs: master~5, develop^2Undefined: <commit-hash> (undefined)Name Resolution Process:
Section titled “Name Resolution Process:”1. Find closest named reference (branch/tag)2. Calculate relative distance3. Generate human-readable name4. Format: ref~distance or ref^distanceBasic Usage Examples:
Section titled “Basic Usage Examples:”Name Single Commit:
Section titled “Name Single Commit:”# Find name for specific commitgit name-rev abc123def456
# Output: abc123def456 master~5
# Find name for HEADgit name-rev HEAD
# Output: HEAD masterName Multiple Commits:
Section titled “Name Multiple Commits:”# Name several commitsgit name-rev HEAD~3 HEAD~5 HEAD~10
# Output:# HEAD~3 master~3# HEAD~5 master~5# HEAD~10 master~10Use Tags Only:
Section titled “Use Tags Only:”# Use only tags for naminggit name-rev --tags abc123def456
# Output: abc123def456 v1.0.0~5Filter References:
Section titled “Filter References:”# Use only release branchesgit name-rev --refs="release/*" abc123def456
# Use only feature branchesgit name-rev --refs="feature/*" abc123def456
# Exclude certain refsgit name-rev --exclude="temp/*" abc123def456Advanced Name Resolution Scenarios:
Section titled “Advanced Name Resolution Scenarios:”Annotate Commit Lists:
Section titled “Annotate Commit Lists:”# Annotate all commits in rangegit log --oneline main..feature | \while read hash msg; do name=$(git name-rev --name-only "$hash") echo "$hash $name: $msg"done
# Process commit streamgit rev-list --all | head -20 | \xargs git name-rev | \while read hash name; do echo "Commit $hash is known as $name"doneStdin Annotation:
Section titled “Stdin Annotation:”# Annotate commits from stdinecho "abc123def456" | git name-rev --annotate-stdin
# Process multiple commitscat commit-list.txt | git name-rev --annotate-stdin
# Combine with other toolsgit rev-parse HEAD~10..HEAD | git name-rev --annotate-stdinComprehensive Repository Analysis:
Section titled “Comprehensive Repository Analysis:”# Analyze all commits with namesgit name-rev --all | head -20
# Find commits without namesgit name-rev --all | grep "undefined" | head -10
# Count named vs unnamed commitstotal=$(git rev-list --all | wc -l)named=$(git name-rev --all | grep -v "undefined" | wc -l)unnamed=$((total - named))
echo "Total commits: $total"echo "Named commits: $named"echo "Unnamed commits: $unnamed"Branch Relationship Analysis:
Section titled “Branch Relationship Analysis:”# Compare branch relationshipsanalyze_branches() { local branch1="$1" local branch2="$2"
echo "=== Branch Analysis: $branch1 vs $branch2 ==="
# Find common ancestor base=$(git merge-base "$branch1" "$branch2") base_name=$(git name-rev --name-only "$base")
echo "Common ancestor: $base ($base_name)"
# Show branch tips tip1=$(git rev-parse "$branch1") tip1_name=$(git name-rev --name-only "$tip1")
tip2=$(git rev-parse "$branch2") tip2_name=$(git name-rev --name-only "$tip2")
echo "$branch1 tip: $tip1 ($tip1_name)" echo "$branch2 tip: $tip2 ($tip2_name)"
# Show divergence ahead1=$(git rev-list --count "$base..$branch1") ahead2=$(git rev-list --count "$base..$branch2")
echo "$branch1 ahead by: $ahead1 commits" echo "$branch2 ahead by: $ahead2 commits"}
analyze_branches "main" "develop"Integration with Development Workflows:
Section titled “Integration with Development Workflows:”Commit History Enhancement:
Section titled “Commit History Enhancement:”#!/bin/bash# Enhanced commit log with names
enhanced_log() { local count="${1:-10}"
git log --oneline -"$count" | \ while read hash msg; do name=$(git name-rev --name-only "$hash") printf "%s %-15s %s\n" "$hash" "($name)" "$msg" done}
# Usageenhanced_log 20Release Tracking:
Section titled “Release Tracking:”# Track commits relative to releasestrack_releases() { echo "=== Release Tracking ==="
# Get all tags git tag --sort=-version:refname | head -5 | \ while read tag; do hash=$(git rev-parse "$tag") echo "Tag: $tag ($hash)"
# Show recent commits relative to this tag git log --oneline "$tag~5..$tag" | \ while read commit_hash msg; do name=$(git name-rev --name-only "$commit_hash") echo " $commit_hash ($name): $msg" done echo "" done}
track_releasesCI/CD Pipeline Integration:
Section titled “CI/CD Pipeline Integration:”# Use in CI for better commit identificationci_commit_info() { local commit_hash="$1"
echo "=== CI Commit Information ===" echo "Commit: $commit_hash"
# Get symbolic name symbolic_name=$(git name-rev --name-only "$commit_hash") echo "Symbolic name: $symbolic_name"
# Determine branch/tag context if [[ "$symbolic_name" == *"tags/"* ]]; then echo "Context: Tag release" tag_name=$(echo "$symbolic_name" | sed 's/.*tags\///') echo "Tag: $tag_name" elif [[ "$symbolic_name" == *"remotes/"* ]]; then echo "Context: Remote branch" branch=$(echo "$symbolic_name" | sed 's/.*remotes\///') echo "Remote branch: $branch" else echo "Context: Local branch" echo "Branch: $symbolic_name" fi
# Get commit details author=$(git show --no-patch --format="%an <%ae>" "$commit_hash") date=$(git show --no-patch --format="%ad" "$commit_hash")
echo "Author: $author" echo "Date: $date"}
# Usage in CIci_commit_info "$CI_COMMIT_SHA"Repository Health Monitoring:
Section titled “Repository Health Monitoring:”# Monitor repository naming healthmonitor_naming_health() { echo "=== Repository Naming Health ==="
# Check for unnamed commits unnamed_count=$(git name-rev --all | grep -c "undefined") total_count=$(git rev-list --all | wc -l)
echo "Total commits: $total_count" echo "Unnamed commits: $unnamed_count"
if [ "$unnamed_count" -gt 0 ]; then percentage=$((unnamed_count * 100 / total_count)) echo "Unnamed percentage: $percentage%"
if [ "$percentage" -gt 50 ]; then echo "⚠ Warning: High percentage of unnamed commits" echo "Consider creating more branches/tags for better traceability" fi fi
# Check branch/tag coverage branch_count=$(git branch -r | wc -l) tag_count=$(git tag | wc -l)
echo "Remote branches: $branch_count" echo "Tags: $tag_count"
# Show most recent unnamed commits if [ "$unnamed_count" -gt 0 ]; then echo "" echo "Recent unnamed commits:" git log --oneline --all | head -20 | \ while read hash msg; do name=$(git name-rev --name-only "$hash") if [[ "$name" == *"undefined"* ]]; then echo " $hash: $msg" fi done fi}
monitor_naming_healthConfiguration and Optimization:
Section titled “Configuration and Optimization:”Reference Pattern Configuration:
Section titled “Reference Pattern Configuration:”# Configure reference patternsgit config name-rev.refs "refs/heads/*" # Only branchesgit config name-rev.refs "refs/tags/*" # Only tagsgit config name-rev.refs "refs/remotes/*" # Remote branches
# Multiple patternsgit config --add name-rev.refs "refs/heads/main"git config --add name-rev.refs "refs/tags/v*"
# Exclude patternsgit config name-rev.exclude "refs/heads/temp/*"git config name-rev.exclude "refs/heads/old/*"Performance Tuning:
Section titled “Performance Tuning:”# Optimize for large repositoriesgit config name-rev.compute "auto" # Auto-compute namesgit config name-rev.compute "always" # Always computegit config name-rev.compute "never" # Never compute
# Cache name resolutionsexport GIT_NAME_REV_CACHE="${HOME}/.git-name-rev-cache"
# Parallel processing for large reposname_rev_parallel() { local commits_file="$1"
# Process in parallel batches split -l 100 "$commits_file" batch-
for batch in batch-*; do git name-rev --annotate-stdin < "$batch" & done
wait
# Combine results cat batch-* rm batch-*}
# Usagegit rev-list --all > all-commits.txtname_rev_parallel all-commits.txtTroubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Undefined Names:
Section titled “Undefined Names:”# Check why commit has no namedebug_undefined_commit() { local commit="$1"
echo "Debugging undefined commit: $commit"
# Check if commit exists if ! git cat-file -t "$commit" >/dev/null 2>&1; then echo "Error: Commit does not exist" return 1 fi
# Check available refs echo "Available branches:" git branch --contains "$commit"
echo "Available tags:" git tag --contains "$commit"
# Check if commit is reachable if git merge-base --is-ancestor "$commit" HEAD 2>/dev/null; then echo "Commit is reachable from HEAD" else echo "Commit is not reachable from HEAD" fi
# Manual name resolution echo "Manual resolution:" # Find closest branch git branch -r --contains "$commit" | head -1 # Find closest tag git describe --tags --contains "$commit" 2>/dev/null || echo "No containing tag"}
debug_undefined_commit "abc123def456"Performance Issues:
Section titled “Performance Issues:”# Profile name resolutiontime git name-rev HEAD~1000
# Check repository size impactecho "Repository refs: $(find .git/refs -type f | wc -l)"echo "Packed refs: $(wc -l .git/packed-refs 2>/dev/null || echo 0)"
# Optimize ref storagegit pack-refs --allgit for-each-ref --format="%(refname)" | git name-rev --stdinPattern Matching Issues:
Section titled “Pattern Matching Issues:”# Debug pattern matchingtest_patterns() { local commit="$1"
echo "Testing patterns for commit: $commit"
# Test different patterns for pattern in "refs/heads/*" "refs/tags/*" "refs/remotes/*"; do result=$(git name-rev --refs="$pattern" "$commit" 2>/dev/null | grep -v "^$commit") if [ -n "$result" ]; then echo "Pattern $pattern: $result" else echo "Pattern $pattern: no match" fi done}
test_patterns "abc123def456"Stdin Processing Issues:
Section titled “Stdin Processing Issues:”# Debug stdin processingdebug_stdin_processing() { echo "Testing stdin processing..."
# Test with sample input echo -e "HEAD\nHEAD~5\nabc123def456" | \ while read commit; do echo "Processing: $commit" name=$(git name-rev --name-only "$commit" 2>/dev/null || echo "error") echo "Result: $name" done}
debug_stdin_processingReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Commit Archaeology:
Section titled “Commit Archaeology:”#!/bin/bash# Analyze historical commits with names
commit_archaeology() { local target_commit="$1"
echo "=== Commit Archaeology: $target_commit ==="
# Get symbolic name symbolic_name=$(git name-rev --name-only "$target_commit") echo "Symbolic name: $symbolic_name"
# Find related branches echo "Related branches:" git branch -r --contains "$target_commit" | sed 's/^/ /'
# Find related tags echo "Related tags:" git tag --contains "$target_commit" | sed 's/^/ /'
# Show commit context echo "Commit context:" git show --no-patch --format="Author: %an <%ae>%nDate: %ad%nSubject: %s" "$target_commit"
# Show position in branches echo "Position in branches:" git branch -r | while read branch; do if git merge-base --is-ancestor "$target_commit" "$branch" 2>/dev/null; then distance=$(git rev-list --count "$target_commit..$branch") echo " $branch: $distance commits ahead" fi done}
# Usagecommit_archaeology "abc123def456"Repository Visualization:
Section titled “Repository Visualization:”# Create visual representation of repositoryvisualize_repository() { echo "=== Repository Visualization ==="
# Get recent commits with names git log --oneline -20 | \ while read hash msg; do name=$(git name-rev --name-only "$hash") # Create simple ASCII visualization if [[ "$name" == *"master"* ]] || [[ "$name" == *"main"* ]]; then marker="*" elif [[ "$name" == *"tags/"* ]]; then marker="T" else marker="o" fi
printf "%s %s %-15s %s\n" "$marker" "$hash" "($name)" "$msg" done
echo "" echo "Legend: * main/master, T tag, o other branch"}
visualize_repositoryAutomated Release Notes:
Section titled “Automated Release Notes:”# Generate release notes with commit namesgenerate_release_notes() { local from_tag="$1" local to_tag="${2:-HEAD}"
echo "=== Release Notes: $from_tag to $to_tag ==="
# Get commits between tags git log --oneline "$from_tag..$to_tag" | \ while read hash msg; do name=$(git name-rev --name-only "$hash") category=$(categorize_commit "$msg") echo " $category: $msg ($name)" done | \ sort | \ awk -F: ' { category[$1] = category[$1] $2 ": " $3 "\n" } END { for (cat in category) { print "## " cat print category[cat] } } '}
categorize_commit() { local msg="$1"
if [[ "$msg" =~ ^feat: ]]; then echo "Features" elif [[ "$msg" =~ ^fix: ]]; then echo "Bug Fixes" elif [[ "$msg" =~ ^docs: ]]; then echo "Documentation" elif [[ "$msg" =~ ^refactor: ]]; then echo "Refactoring" else echo "Other" fi}
# Usagegenerate_release_notes "v1.0.0" "v2.0.0"What’s the difference between git name-rev and git describe?
Section titled “What’s the difference between git name-rev and git describe?”git name-rev finds symbolic names for any commit; git describe finds the most recent tag reachable from a commit, with distance information.
How do I find the symbolic name for a specific commit?
Section titled “How do I find the symbolic name for a specific commit?”Use git name-rev
Can name-rev work with abbreviated hashes?
Section titled “Can name-rev work with abbreviated hashes?”Yes, git name-rev accepts any commit reference that git rev-parse can understand, including abbreviated hashes.
What’s the impact of —tags option?
Section titled “What’s the impact of —tags option?”Limits name resolution to tags only, ignoring branches. Useful when you want tag-based naming instead of branch-based.
How do I use name-rev with git log?
Section titled “How do I use name-rev with git log?”Pipe git log output to git name-rev —annotate-stdin, or use git log with custom formatting that includes symbolic names.
Can name-rev resolve names for merge commits?
Section titled “Can name-rev resolve names for merge commits?”Yes, merge commits get names based on their relationship to named refs, showing which branch they belong to.
What’s the performance impact of name-rev —all?
Section titled “What’s the performance impact of name-rev —all?”Can be slow on large repositories as it processes all commits. Use selectively or combine with other filtering options.
How do I handle name-rev in scripts?
Section titled “How do I handle name-rev in scripts?”Use —name-only for clean output, check exit codes, and handle “undefined” results for commits without symbolic names.
Can name-rev work with remote refs?
Section titled “Can name-rev work with remote refs?”Yes, includes remote branches in name resolution. Use —refs=“refs/remotes/*” to limit to remote refs only.
What’s the relationship between name-rev and git symbolic-ref?
Section titled “What’s the relationship between name-rev and git symbolic-ref?”git symbolic-ref shows the target of symbolic refs; git name-rev finds human-readable names for commit objects.
How do I customize name-rev reference patterns?
Section titled “How do I customize name-rev reference patterns?”Use —refs and —exclude options to control which references are considered for name resolution.
Can name-rev work in bare repositories?
Section titled “Can name-rev work in bare repositories?”Yes, operates on refs and commit objects regardless of working directory presence.
What’s the difference between name-rev and branch —contains?
Section titled “What’s the difference between name-rev and branch —contains?”git name-rev finds the closest named reference; git branch —contains shows all branches containing a commit.
How do I troubleshoot “undefined” name-rev results?
Section titled “How do I troubleshoot “undefined” name-rev results?”Check if commit is reachable from named refs, verify repository has branches/tags, and ensure refs are properly packed.
Applications of the git name-rev command
Section titled “Applications of the git name-rev command”- Commit Reference Enhancement: Make commit hashes more human-readable by associating them with branch/tag names
- Repository Analysis: Analyze commit relationships and branch structures with meaningful names
- Debugging Support: Aid in debugging by providing context for commit references
- Historical Research: Study repository evolution with named commit references
- CI/CD Integration: Provide meaningful commit identification in automated pipelines
- Documentation Generation: Create human-readable commit references for documentation and reports