mktree Git Command Guide
The git mktree command reads standard input in non-recursive ls-tree output format and creates a tree object. It normalizes the order of tree entries, making pre-sorting unnecessary, and writes the object name of the created tree to standard output.
git mktree Syntax:
Section titled “git mktree Syntax:”git mktree [-z] [--missing] [--batch]Input Processing Options:
Section titled “Input Processing Options:”| Option | Description |
|---|---|
-z | Read NUL-terminated ls-tree -z output instead of newline-separated |
--missing | Allow missing objects (default verifies all objects exist) |
--batch | Read multiple tree specifications from stdin, one per line |
Understanding Tree Object Input Format:
Section titled “Understanding Tree Object Input Format:”ls-tree Output Format:
Section titled “ls-tree Output Format:”<mode> <type> <object> <file>100644 blob 9fceb02d0ae598e95dc970b74767f19372d61af8 file.txt100755 executable 1a2b3c4d5e6f7890abcdef1234567890abcdef script.sh040000 tree abc123def456789012345678901234567890abc subdir120000 link def456789012345678901234567890123456789 link.txt160000 commit 789012345678901234567890123456789012345 submoduleTree Entry Components:
Section titled “Tree Entry Components:”mode: File permissions (100644=regular, 100755=executable, 040000=tree, etc.)type: Object type (blob, tree, commit, link)object: SHA-1 hash of the objectfile: Filename/pathBasic Usage Examples:
Section titled “Basic Usage Examples:”Create Tree from ls-tree Output:
Section titled “Create Tree from ls-tree Output:”# Generate tree from current directory listinggit ls-tree HEAD | git mktree# Output: tree SHA-1 hash
# Create tree from specific directorygit ls-tree HEAD:src | git mktree
# Create tree with NUL terminationgit ls-tree -z HEAD | git mktree -zBuild Custom Tree Structures:
Section titled “Build Custom Tree Structures:”# Create a simple tree with two filescat > tree-input.txt << EOF100644 blob $(echo "Hello World" | git hash-object -w --stdin) hello.txt100644 blob $(echo "Git Tree" | git hash-object -w --stdin) readme.txtEOF
git mktree < tree-input.txtTree Construction with Subdirectories:
Section titled “Tree Construction with Subdirectories:”# Create nested tree structurecat > tree-structure.txt << EOF100644 blob $(echo "main file" | git hash-object -w --stdin) main.txt040000 tree $(git ls-tree HEAD:subdir | git mktree) subdirEOF
git mktree < tree-structure.txtAdvanced Tree Construction Scenarios:
Section titled “Advanced Tree Construction Scenarios:”Programmatic Tree Building:
Section titled “Programmatic Tree Building:”#!/bin/bash# Build tree objects programmatically
create_file_tree() { local tree_spec="$1"
# Process each line of tree specification while IFS='|' read -r mode type content filename; do case "$type" in "blob") # Create blob object from content local blob_sha=$(echo "$content" | git hash-object -w --stdin) echo "$mode blob $blob_sha $filename" ;; "tree") # Recursively create subtree local subtree_sha=$(create_file_tree "$content") echo "$mode tree $subtree_sha $filename" ;; esac done <<< "$tree_spec"}
# Usage exampletree_spec="100644|blob|Hello World|hello.txt100644|blob|Git Rocks|readme.txt"
create_file_tree "$tree_spec" | git mktreeRepository Restructuring:
Section titled “Repository Restructuring:”# Restructure repository layoutrestructure_tree() { local source_tree="$1" local new_structure="$2"
echo "Restructuring tree from $source_tree..."
# Get current tree contents git ls-tree "$source_tree" > current-tree.txt
# Apply restructuring rules cat current-tree.txt | \ while read mode type sha filename; do case "$filename" in *.old) # Move old files to archive echo "$mode $type $sha archive/$filename" ;; *.config) # Move config files to etc echo "$mode $type $sha etc/$filename" ;; *) # Keep other files as-is echo "$mode $type $sha $filename" ;; esac done | git mktree}
# Usagenew_tree=$(restructure_tree "HEAD" "restructured")echo "New tree: $new_tree"Batch Tree Processing:
Section titled “Batch Tree Processing:”# Process multiple tree specificationsbatch_tree_creation() { local input_file="$1"
# Read multiple tree specs separated by blank lines awk 'BEGIN { RS = "" } { print $0 "\n---" }' "$input_file" | \ while IFS='---' read -r tree_spec; do if [ -n "$tree_spec" ]; then echo "$tree_spec" | git mktree fi done}
# Usage with file containing multiple tree specsbatch_tree_creation "tree-specifications.txt"Integration with Git Workflows:
Section titled “Integration with Git Workflows:”Custom Commit Creation:
Section titled “Custom Commit Creation:”#!/bin/bash# Create commits with custom tree structures
create_custom_commit() { local parent_commit="$1" local tree_spec="$2" local commit_message="$3"
# Build tree from specification local tree_sha=$(echo "$tree_spec" | git mktree)
# Create commit object local commit_sha=$(git commit-tree "$tree_sha" -p "$parent_commit" -m "$commit_message")
echo "Created commit: $commit_sha" echo "Tree: $tree_sha"
return "$commit_sha"}
# Usagetree_spec="100644 blob $(echo 'version 2.0' | git hash-object -w --stdin) version.txt100644 blob $(echo 'Updated README' | git hash-object -w --stdin) README.md"
create_custom_commit "HEAD" "$tree_spec" "Custom commit with specific files"Repository Migration and Import:
Section titled “Repository Migration and Import:”# Import external directory structuresimport_directory_structure() { local source_dir="$1" local target_tree="$2"
echo "Importing directory structure from $source_dir..."
# Recursively build tree from directory build_tree_from_dir() { local dir="$1" local prefix="${2:-}"
find "$dir" -type f -print0 | \ while IFS= read -r -d '' file; do local rel_path="${file#$dir/}" local full_path="${prefix:+$prefix/}$rel_path"
# Determine file mode local mode="100644" if [ -x "$file" ]; then mode="100755" fi
# Create blob and output tree entry local blob_sha=$(git hash-object -w "$file") echo "$mode blob $blob_sha $full_path" done }
# Build and create tree build_tree_from_dir "$source_dir" | git mktree}
# Usageimported_tree=$(import_directory_structure "/external/project" "imported")echo "Imported tree: $imported_tree"Tree Manipulation and Surgery:
Section titled “Tree Manipulation and Surgery:”# Perform tree surgery operationstree_surgery() { local base_tree="$1" local operation="$2" local target="$3"
# Get base tree contents git ls-tree "$base_tree" > base-contents.txt
case "$operation" in "remove") # Remove specified files/directories grep -v "^.* $target$" base-contents.txt | git mktree ;; "replace") # Replace file with new content local new_blob=$(echo "$4" | git hash-object -w --stdin) sed "s|^.* $target$|100644 blob $new_blob $target|" base-contents.txt | git mktree ;; "rename") # Rename file/directory sed "s| $target$| $4|" base-contents.txt | git mktree ;; esac}
# Usage examples# Remove file: tree_surgery "HEAD" "remove" "old-file.txt"# Replace content: tree_surgery "HEAD" "replace" "config.txt" "new content"# Rename: tree_surgery "HEAD" "rename" "old-name.txt" "new-name.txt"Configuration and Customization:
Section titled “Configuration and Customization:”Tree Building Optimization:
Section titled “Tree Building Optimization:”# Optimize for large tree operationsgit config core.packedGitLimit 256mgit config core.packedGitWindowSize 32m
# Enable parallel processing for large treesexport GIT_MKTREE_PARALLEL=4
# Cache frequently used blobscache_blobs() { local content_cache="/tmp/blob-cache"
# Create blob cache for repeated content echo "$1" | git hash-object -w --stdin | tee "$content_cache"}
# Usageblob_sha=$(cache_blobs "Frequently used content")Custom Tree Validation:
Section titled “Custom Tree Validation:”# Validate tree structure before creationvalidate_tree_input() { local input_file="$1"
echo "Validating tree input..."
# Check format while read -r line; do # Parse line: mode type sha filename read -r mode type sha filename <<< "$line"
# Validate mode [[ "$mode" =~ ^[0-9]+$ ]] || { echo "Invalid mode: $mode"; return 1; }
# Validate type [[ "$type" =~ ^(blob|tree|commit)$ ]] || { echo "Invalid type: $type"; return 1; }
# Validate SHA [[ "$sha" =~ ^[0-9a-f]{40}$ ]] || { echo "Invalid SHA: $sha"; return 1; }
# Validate filename [ -n "$filename" ] || { echo "Missing filename"; return 1; }
done < "$input_file"
echo "✓ Tree input validation passed" return 0}
# Usagevalidate_tree_input "tree-spec.txt" && git mktree < tree-spec.txtPerformance Optimization:
Section titled “Performance Optimization:”# Optimize for bulk tree operationsbulk_tree_creation() { local spec_dir="$1"
# Process multiple tree specs in parallel find "$spec_dir" -name "*.tree" -print0 | \ xargs -0 -n 1 -P $(nproc) bash -c ' spec_file="$1" tree_sha=$(git mktree < "$spec_file") echo "$spec_file -> $tree_sha" ' _ {}}
# Usagebulk_tree_creation "/path/to/tree/specs"Troubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Input Format Errors:
Section titled “Input Format Errors:”# Debug input format issuescat tree-input.txt | while read line; do echo "Processing: $line" # Parse and validate each line read mode type sha file <<< "$line" echo " Mode: $mode, Type: $type, SHA: $sha, File: $file"done
# Check for common issuesgrep -v "^[0-9]* [a-z]* [0-9a-f]* " tree-input.txt # Invalid format linesObject Reference Issues:
Section titled “Object Reference Issues:”# Verify all objects existwhile read mode type sha file; do if ! git cat-file -e "$sha" 2>/dev/null; then echo "Missing object: $sha ($file)" fidone < tree-input.txt
# Use --missing to allow missing objectsgit mktree --missing < tree-input.txtEncoding and Character Issues:
Section titled “Encoding and Character Issues:”# Handle special characters in filenamesgit ls-tree -z HEAD | git mktree -z
# Convert encoding issuesiconv -f latin1 -t utf8 tree-input.txt > tree-input-utf8.txtgit mktree < tree-input-utf8.txtPerformance Issues with Large Trees:
Section titled “Performance Issues with Large Trees:”# Monitor memory usage/usr/bin/time -v git mktree < large-tree.txt
# Split large treessplit -l 1000 large-tree.txt tree-part-for part in tree-part-*; do git mktree < "$part"done
# Use system limitsulimit -v $((1024*1024*1024)) # 1GB memory limitReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Repository Backup and Restore:
Section titled “Repository Backup and Restore:”#!/bin/bash# Backup and restore repository trees
backup_tree_structure() { local commit_sha="$1" local backup_file="$2"
echo "Backing up tree structure for commit $commit_sha..."
# Recursively dump tree structure dump_tree() { local tree_sha="$1" local prefix="${2:-}"
git ls-tree "$tree_sha" | while read mode type sha filename; do local full_path="${prefix:+$prefix/}$filename"
if [ "$type" = "tree" ]; then # Recurse into subtrees dump_tree "$sha" "$full_path" else # Output leaf entries echo "$mode $type $sha $full_path" fi done }
dump_tree "$(git rev-parse "$commit_sha^{tree}")" > "$backup_file" echo "Tree structure backed up to $backup_file"}
restore_tree_structure() { local backup_file="$1"
echo "Restoring tree structure from $backup_file..."
# Build tree from backup local tree_sha=$(git mktree < "$backup_file") echo "Restored tree: $tree_sha"
# Create commit from tree local commit_sha=$(git commit-tree "$tree_sha" -m "Restored from backup") echo "Restored commit: $commit_sha"
return "$commit_sha"}
# Usagebackup_tree_structure "HEAD" "tree-backup.txt"restored_commit=$(restore_tree_structure "tree-backup.txt")Custom Build System Integration:
Section titled “Custom Build System Integration:”# Integrate with build systems for reproducible buildscreate_reproducible_tree() { local source_dir="$1" local output_tree="$2"
echo "Creating reproducible tree from $source_dir..."
# Sort files for reproducible builds find "$source_dir" -type f -print0 | \ sort -z | \ while IFS= read -r -d '' file; do local rel_path="${file#$source_dir/}" local mode="100644"
# Determine mode based on file properties if [ -x "$file" ]; then mode="100755" fi
# Create normalized blob local content=$(cat "$file" | sed 's/[[:space:]]*$//') # Trim trailing whitespace local blob_sha=$(echo "$content" | git hash-object -w --stdin)
echo "$mode blob $blob_sha $rel_path" done | git mktree > "$output_tree"
echo "Reproducible tree created: $(cat "$output_tree")"}
# Usage for reproducible buildscreate_reproducible_tree "source-code" "reproducible-tree.sha"Repository Surgery and Refactoring:
Section titled “Repository Surgery and Refactoring:”# Perform complex repository restructuringrepository_surgery() { local base_commit="$1" local surgery_spec="$2"
echo "Performing repository surgery on $base_commit..."
# Get base tree local base_tree=$(git rev-parse "$base_commit^{tree}")
# Apply surgery specifications git ls-tree "$base_tree" > original-tree.txt
# Process surgery spec file while IFS='|' read -r operation target new_value; do case "$operation" in "move") # Move file/directory sed -i "s| $target$| $new_value|" original-tree.txt ;; "remove") # Remove entry sed -i "/ $target$/d" original-tree.txt ;; "replace") # Replace content local new_blob=$(echo "$new_value" | git hash-object -w --stdin) sed -i "s|^.* $target$|100644 blob $new_blob $target|" original-tree.txt ;; esac done < "$surgery_spec"
# Create new tree local new_tree=$(git mktree < original-tree.txt)
# Create surgery commit local surgery_commit=$(git commit-tree "$new_tree" -p "$base_commit" \ -m "Repository surgery applied
Surgery specification: $surgery_spec")
echo "Surgery complete. New commit: $surgery_commit" echo "Original tree: $base_tree" echo "Modified tree: $new_tree"
return "$surgery_commit"}
# Usagesurgery_commit=$(repository_surgery "HEAD" "surgery-spec.txt")What’s the difference between git mktree and git write-tree?
Section titled “What’s the difference between git mktree and git write-tree?”git write-tree creates tree from index; git mktree creates tree from ls-tree formatted text input, allowing programmatic tree construction without index manipulation.
How do I handle subtrees with mktree?
Section titled “How do I handle subtrees with mktree?”Create subtree objects first with git mktree, then reference them in parent tree with mode 040000 and type tree.
Can mktree work with binary files?
Section titled “Can mktree work with binary files?”Yes, mktree works with any blob objects including binary files. The input format remains the same regardless of content type.
What’s the —missing option for?
Section titled “What’s the —missing option for?”Allows creation of trees referencing non-existent objects. Useful for building trees that will be completed later or for testing purposes.
How do I create trees with specific ordering?
Section titled “How do I create trees with specific ordering?”mktree automatically sorts entries, so input order doesn’t matter. This ensures consistent tree hashes regardless of input order.
Can mktree create empty trees?
Section titled “Can mktree create empty trees?”Yes, create tree with no input lines: echo "" | git mktree creates empty tree object.
What’s the performance impact of large trees?
Section titled “What’s the performance impact of large trees?”Linear with number of entries. Memory usage scales with tree size. Use —batch for multiple trees efficiently.
How do I integrate mktree with git fast-import?
Section titled “How do I integrate mktree with git fast-import?”Use mktree to create tree objects, then reference them in fast-import streams for bulk repository operations.
Can mktree work in bare repositories?
Section titled “Can mktree work in bare repositories?”Yes, operates on objects without working directory. Useful for server-side tree manipulation and bulk operations.
What’s the relationship between mktree and git update-index?
Section titled “What’s the relationship between mktree and git update-index?”mktree creates trees from text input; update-index modifies index. Use together for complex staging operations.
How do I handle file permissions with mktree?
Section titled “How do I handle file permissions with mktree?”Specify correct mode values: 100644 (regular), 100755 (executable), 120000 (symlink), 160000 (gitlink/submodule).
Can mktree create trees with duplicate filenames?
Section titled “Can mktree create trees with duplicate filenames?”No, Git trees cannot have duplicate filenames in same directory. mktree will create tree but Git will reject invalid trees.
What’s the —batch option for?
Section titled “What’s the —batch option for?”Processes multiple tree specifications from stdin, one per line. Each tree spec separated by newline, outputs one SHA per tree.
How do I troubleshoot mktree failures?
Section titled “How do I troubleshoot mktree failures?”Check input format, verify object SHAs exist (unless —missing used), ensure proper sorting. Use git cat-file to validate created trees.
Applications of the git mktree command
Section titled “Applications of the git mktree command”- Programmatic Tree Construction: Build tree objects from text specifications for automated repository operations
- Repository Surgery: Perform complex restructuring and refactoring of repository structures
- Backup and Restore: Create and restore repository tree structures programmatically
- Custom Commit Creation: Build commits with specific tree contents for specialized workflows
- Repository Migration: Migrate and transform repository structures between different layouts
- Build System Integration: Create reproducible build trees for consistent artifact generation