Skip to content

ls-tree Git Command Guide

The git ls-tree command lists the contents of a given tree object, similar to /bin/ls -a but for Git tree objects. It shows file modes, types, object hashes, and filenames, enabling detailed examination of repository structure at any commit.

Terminal window
git ls-tree [-d] [-r] [-t] [-l] [-z]
[--name-only] [--name-status] [--object-only] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
<tree-ish> [<path>...]
OptionDescription
-dShow only directories
-rRecurse into subdirectories
-tSort by tree/file type
-lShow file size
-zUse NUL line termination
--name-onlyShow only filenames
--name-statusShow filename and status
--object-onlyShow only object hashes
--full-nameShow full path from repository root
--full-treeIgnore current working directory
--abbrev[=<n>]Abbreviate object hashes
--format=<format>Custom output format
ParameterDescription
<tree-ish>Tree object, commit, or branch to examine
<path>...Specific paths to show (relative to tree-ish)
Terminal window
# Show root tree contents
git ls-tree HEAD
# Show specific commit tree
git ls-tree v1.0.0
# Show current index tree
git ls-tree --name-only HEAD
Terminal window
# Show only directories
git ls-tree -d HEAD
# Show only files (not directories)
git ls-tree HEAD | grep -v "^040000"
# Show file sizes
git ls-tree -l HEAD
Terminal window
# Recurse into all subdirectories
git ls-tree -r HEAD
# Show specific subdirectory
git ls-tree HEAD src/
# Show multiple paths
git ls-tree HEAD src/ tests/ docs/
Terminal window
# Show object hashes only
git ls-tree --object-only HEAD
# Show abbreviated hashes
git ls-tree --abbrev=8 HEAD
# Show full paths
git ls-tree --full-name HEAD
Terminal window
# Compare trees between commits
git ls-tree HEAD src/ > current-tree.txt
git ls-tree HEAD~1 src/ > previous-tree.txt
diff current-tree.txt previous-tree.txt
# Find new files in current commit
comm -23 <(git ls-tree HEAD~1 --name-only) <(git ls-tree HEAD --name-only)
Terminal window
# Count files by type
git ls-tree -r HEAD | awk '{print $2}' | sort | uniq -c | sort -rn
# Find all executable files
git ls-tree -r HEAD | awk '$1 ~ /100755/ {print $4}'
# Find all symlinks
git ls-tree -r HEAD | awk '$2 == "commit" {print $4}'
Terminal window
# Directory structure overview
git ls-tree --name-only HEAD | xargs -I {} dirname {} | sort | uniq -c | sort -rn
# Deepest directory paths
git ls-tree -r --name-only HEAD | awk -F/ '{print NF-1 ": " $0}' | sort -rn | head -10
# File extension distribution
git ls-tree -r --name-only HEAD | grep -E "\.[a-zA-Z0-9]+$" | sed 's/.*\.//' | sort | uniq -c | sort -rn
#!/bin/bash
# Comprehensive repository analysis
echo "=== REPOSITORY STRUCTURE ==="
git ls-tree -r --name-only HEAD | wc -l && echo "total files"
echo "=== FILE TYPES ==="
git ls-tree -r HEAD | awk '{print $2}' | sort | uniq -c | sort -rn
echo "=== LARGEST FILES ==="
git ls-tree -r -l HEAD | awk '$5 > 1000000 {print $5 ": " $6}' | sort -rn | head -5
echo "=== RECENTLY MODIFIED ==="
git ls-tree -r HEAD | while read mode type hash size path; do
echo "$(git log -1 --format=%ci "$hash" 2>/dev/null || echo "unknown") $path"
done | sort -r | head -10
Terminal window
# Verify tree object integrity
tree_hash=$(git rev-parse HEAD^{tree})
echo "Tree hash: $tree_hash"
# List tree contents
git ls-tree "$tree_hash" | wc -l && echo "entries"
# Verify all objects exist
git ls-tree -r "$tree_hash" | while read mode type hash path; do
if ! git cat-file -e "$hash" 2>/dev/null; then
echo "Missing object: $hash ($path)"
fi
done
Terminal window
# Compare directory contents between commits
compare_trees() {
local commit1="$1"
local commit2="$2"
local path="$3"
echo "=== Changes in $path between $commit1 and $commit2 ==="
comm -23 \
<(git ls-tree "$commit1" "$path" | awk '{print $4}' | sort) \
<(git ls-tree "$commit2" "$path" | awk '{print $4}' | sort)
}
# Usage
compare_trees HEAD~1 HEAD src/
Terminal window
# Limit depth for large repos
git ls-tree HEAD | head -50
# Process specific subdirectories
git ls-tree HEAD src/ | wc -l
# Use name-only for faster processing
git ls-tree --name-only HEAD | grep "\.js$" | wc -l
Terminal window
# Process files in batches
git ls-tree -r --name-only HEAD | split -l 1000 - file-batch-
# Process each batch
for batch in file-batch-*; do
echo "Processing batch: $batch"
cat "$batch" | xargs process-files
done
Terminal window
# Check if commit exists
git cat-file -t HEAD
# Verify tree hash
git rev-parse HEAD^{tree}
# Check repository integrity
git fsck --unreachable | head -10
Terminal window
# Check object accessibility
git cat-file -t $(git ls-tree HEAD | head -1 | awk '{print $3}')
# Verify repository permissions
ls -la .git/objects/
Terminal window
# Handle filename encoding
git ls-tree HEAD | iconv -f utf-8 -t utf-8
# Check for problematic filenames
git ls-tree -z HEAD | xargs -0 -I {} echo "'{}'"
Terminal window
# Time tree operations
time git ls-tree -r HEAD > /dev/null
# Use specific paths for speed
git ls-tree HEAD src/ | wc -l
# Cache results for repeated queries
git ls-tree --name-only HEAD > /tmp/tree-cache.txt
#!/bin/bash
# Analyze project structure
echo "=== PROJECT STATISTICS ==="
# Total files by type
echo "Files by type:"
git ls-tree -r HEAD | awk '{print $2}' | sort | uniq -c | sort -rn
# Source code files
src_files=$(git ls-tree -r --name-only HEAD | grep -E "\.(c|cpp|java|py|js|ts|go|rs)$" | wc -l)
echo "Source files: $src_files"
# Documentation files
docs=$(git ls-tree -r --name-only HEAD | grep -E "\.(md|txt|rst|doc)$" | wc -l)
echo "Documentation files: $docs"
# Configuration files
config=$(git ls-tree -r --name-only HEAD | grep -E "(config|conf|ini|yaml|yml|json|toml)$" | wc -l)
echo "Configuration files: $config"
Terminal window
# Find dependency files
deps=$(git ls-tree -r --name-only HEAD | grep -E "(package\.json|requirements\.txt|Gemfile|Cargo\.toml|go\.mod)$")
echo "Dependency files found:"
echo "$deps"
# Check for lock files
locks=$(git ls-tree -r --name-only HEAD | grep -E "(package-lock\.json|yarn\.lock|Pipfile\.lock|Gemfile\.lock|Cargo\.lock)")
if [ -n "$locks" ]; then
echo "Lock files present (good for reproducible builds):"
echo "$locks"
else
echo "No lock files found - consider adding for reproducible builds"
fi
#!/bin/bash
# Security-focused repository analysis
echo "=== SECURITY SCAN ==="
# Check for sensitive files that shouldn't be tracked
sensitive_patterns=(
"\.env"
"\.key"
"\.pem"
"password"
"secret"
"credential"
)
for pattern in "${sensitive_patterns[@]}"; do
found=$(git ls-tree -r --name-only HEAD | grep -i "$pattern" | wc -l)
if [ "$found" -gt 0 ]; then
echo "WARNING: Found $found files matching '$pattern'"
git ls-tree -r --name-only HEAD | grep -i "$pattern"
fi
done
# Check file permissions
echo "=== FILE PERMISSIONS ==="
git ls-tree -r HEAD | awk '$1 !~ /^(100644|100755|120000|160000)/ {print "Unusual permissions: " $1 " " $4}'

How does ls-tree differ from git ls-files?

Section titled “How does ls-tree differ from git ls-files?”

git ls-files shows index contents; git ls-tree shows tree object contents. ls-tree examines historical or specific commit trees, ls-files shows current index state.

No, shows tree entries (metadata). Use git show to view actual file content, or git cat-file -p for blob content.

What’s the relationship between tree objects and commits?

Section titled “What’s the relationship between tree objects and commits?”

Each commit points to a tree object representing repository state. Tree objects contain file/blob references and subdirectories.

How do I examine a specific file in historical commit?

Section titled “How do I examine a specific file in historical commit?”

Use git ls-tree to see file metadata, then git show : to see file content.

What’s the performance impact of -r (recursive) option?

Section titled “What’s the performance impact of -r (recursive) option?”

Recursive traversal examines entire repository tree - expensive for large repositories. Use specific paths when possible for better performance.

Can ls-tree work with remote repositories?

Section titled “Can ls-tree work with remote repositories?”

No, operates on local tree objects. Use git fetch to get remote trees, then examine with ls-tree, or use git ls-remote for remote reference inspection.

How do I interpret the mode field in ls-tree output?

Section titled “How do I interpret the mode field in ls-tree output?”

Mode shows file type and permissions: 100644 (regular file), 100755 (executable), 120000 (symlink), 160000 (submodule), 040000 (directory).

What’s the difference between —name-only and —object-only?

Section titled “What’s the difference between —name-only and —object-only?”

—name-only shows filenames only; —object-only shows object hashes only. Both suppress other metadata for focused output.

No, shows current tree structure. Use git log —follow —name-status to detect renames across commits, or git diff for recent changes.

Use -z for NUL termination with filenames containing spaces. Parse output carefully - format may change between Git versions.

Ignores current working directory context, treating paths as relative to tree root. Useful when tree-ish doesn’t represent current working directory state.

Can ls-tree show information about submodules?

Section titled “Can ls-tree show information about submodules?”

Yes, shows submodule entries with mode 160000 and commit hash. Use git submodule status for detailed submodule information.

How do I compare tree contents between commits?

Section titled “How do I compare tree contents between commits?”

Use comm or diff with git ls-tree output: comm -23 <(git ls-tree HEAD —name-only) <(git ls-tree HEAD~1 —name-only) shows new files.

What’s the relationship between ls-tree and git read-tree?

Section titled “What’s the relationship between ls-tree and git read-tree?”

ls-tree examines tree contents; read-tree updates index with tree contents. ls-tree is read-only, read-tree modifies repository state.

Yes, tags point to commits which point to trees. Use git ls-tree to examine tree at tagged commit.

Use head/tail for limiting: git ls-tree -r HEAD | head -100. Use specific paths: git ls-tree HEAD src/ instead of entire repository.

Controls hash abbreviation length. Default shows full 40-character SHA-1. Use —abbrev=8 for shorter, more readable output.

No, that’s git ls-files —eol functionality. ls-tree shows tree object metadata, not working directory file properties.

How do I use ls-tree for repository archaeology?

Section titled “How do I use ls-tree for repository archaeology?”

Examine historical trees: git ls-tree to see repository structure at that point in time, useful for understanding project evolution.

What’s the difference between tree-ish and commit-ish?

Section titled “What’s the difference between tree-ish and commit-ish?”

Both work with ls-tree, but tree-ish refers specifically to tree objects while commit-ish refers to any object resolving to commit (which has tree).

  1. Repository Structure Analysis: Examine directory and file organization at any commit
  2. Historical Investigation: Understand repository state and file locations at specific points in time
  3. Content Validation: Verify file existence and metadata in tree objects
  4. Build System Integration: Generate file lists for compilation or packaging processes
  5. Security Auditing: Identify file types and locations for security scanning
  6. Migration Planning: Analyze repository structure for refactoring or reorganization projects