Skip to content

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.

Terminal window
git mktree [-z] [--missing] [--batch]
OptionDescription
-zRead NUL-terminated ls-tree -z output instead of newline-separated
--missingAllow missing objects (default verifies all objects exist)
--batchRead multiple tree specifications from stdin, one per line
<mode> <type> <object> <file>
100644 blob 9fceb02d0ae598e95dc970b74767f19372d61af8 file.txt
100755 executable 1a2b3c4d5e6f7890abcdef1234567890abcdef script.sh
040000 tree abc123def456789012345678901234567890abc subdir
120000 link def456789012345678901234567890123456789 link.txt
160000 commit 789012345678901234567890123456789012345 submodule
mode: File permissions (100644=regular, 100755=executable, 040000=tree, etc.)
type: Object type (blob, tree, commit, link)
object: SHA-1 hash of the object
file: Filename/path
Terminal window
# Generate tree from current directory listing
git ls-tree HEAD | git mktree
# Output: tree SHA-1 hash
# Create tree from specific directory
git ls-tree HEAD:src | git mktree
# Create tree with NUL termination
git ls-tree -z HEAD | git mktree -z
Terminal window
# Create a simple tree with two files
cat > tree-input.txt << EOF
100644 blob $(echo "Hello World" | git hash-object -w --stdin) hello.txt
100644 blob $(echo "Git Tree" | git hash-object -w --stdin) readme.txt
EOF
git mktree < tree-input.txt
Terminal window
# Create nested tree structure
cat > tree-structure.txt << EOF
100644 blob $(echo "main file" | git hash-object -w --stdin) main.txt
040000 tree $(git ls-tree HEAD:subdir | git mktree) subdir
EOF
git mktree < tree-structure.txt
#!/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 example
tree_spec="100644|blob|Hello World|hello.txt
100644|blob|Git Rocks|readme.txt"
create_file_tree "$tree_spec" | git mktree
Terminal window
# Restructure repository layout
restructure_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
}
# Usage
new_tree=$(restructure_tree "HEAD" "restructured")
echo "New tree: $new_tree"
Terminal window
# Process multiple tree specifications
batch_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 specs
batch_tree_creation "tree-specifications.txt"
#!/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"
}
# Usage
tree_spec="100644 blob $(echo 'version 2.0' | git hash-object -w --stdin) version.txt
100644 blob $(echo 'Updated README' | git hash-object -w --stdin) README.md"
create_custom_commit "HEAD" "$tree_spec" "Custom commit with specific files"
Terminal window
# Import external directory structures
import_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
}
# Usage
imported_tree=$(import_directory_structure "/external/project" "imported")
echo "Imported tree: $imported_tree"
Terminal window
# Perform tree surgery operations
tree_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"
Terminal window
# Optimize for large tree operations
git config core.packedGitLimit 256m
git config core.packedGitWindowSize 32m
# Enable parallel processing for large trees
export GIT_MKTREE_PARALLEL=4
# Cache frequently used blobs
cache_blobs() {
local content_cache="/tmp/blob-cache"
# Create blob cache for repeated content
echo "$1" | git hash-object -w --stdin | tee "$content_cache"
}
# Usage
blob_sha=$(cache_blobs "Frequently used content")
Terminal window
# Validate tree structure before creation
validate_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
}
# Usage
validate_tree_input "tree-spec.txt" && git mktree < tree-spec.txt
Terminal window
# Optimize for bulk tree operations
bulk_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"
' _ {}
}
# Usage
bulk_tree_creation "/path/to/tree/specs"
Terminal window
# Debug input format issues
cat 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 issues
grep -v "^[0-9]* [a-z]* [0-9a-f]* " tree-input.txt # Invalid format lines
Terminal window
# Verify all objects exist
while read mode type sha file; do
if ! git cat-file -e "$sha" 2>/dev/null; then
echo "Missing object: $sha ($file)"
fi
done < tree-input.txt
# Use --missing to allow missing objects
git mktree --missing < tree-input.txt
Terminal window
# Handle special characters in filenames
git ls-tree -z HEAD | git mktree -z
# Convert encoding issues
iconv -f latin1 -t utf8 tree-input.txt > tree-input-utf8.txt
git mktree < tree-input-utf8.txt
Terminal window
# Monitor memory usage
/usr/bin/time -v git mktree < large-tree.txt
# Split large trees
split -l 1000 large-tree.txt tree-part-
for part in tree-part-*; do
git mktree < "$part"
done
# Use system limits
ulimit -v $((1024*1024*1024)) # 1GB memory limit
#!/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"
}
# Usage
backup_tree_structure "HEAD" "tree-backup.txt"
restored_commit=$(restore_tree_structure "tree-backup.txt")
Terminal window
# Integrate with build systems for reproducible builds
create_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 builds
create_reproducible_tree "source-code" "reproducible-tree.sha"
Terminal window
# Perform complex repository restructuring
repository_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"
}
# Usage
surgery_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.

Create subtree objects first with git mktree, then reference them in parent tree with mode 040000 and type tree.

Yes, mktree works with any blob objects including binary files. The input format remains the same regardless of content type.

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.

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.

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.

Processes multiple tree specifications from stdin, one per line. Each tree spec separated by newline, outputs one SHA per tree.

Check input format, verify object SHAs exist (unless —missing used), ensure proper sorting. Use git cat-file to validate created trees.

  1. Programmatic Tree Construction: Build tree objects from text specifications for automated repository operations
  2. Repository Surgery: Perform complex restructuring and refactoring of repository structures
  3. Backup and Restore: Create and restore repository tree structures programmatically
  4. Custom Commit Creation: Build commits with specific tree contents for specialized workflows
  5. Repository Migration: Migrate and transform repository structures between different layouts
  6. Build System Integration: Create reproducible build trees for consistent artifact generation