Skip to content

merge-tree Git Command Guide

The git merge-tree command performs a merge operation but does not make any new commits and does not read from or write to either the working tree or index. It enables conflict analysis, merge testing, and virtual merge operations without affecting the repository state.

Terminal window
git merge-tree [--write-tree] [<options>] <branch1> <branch2>
git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)
OptionDescription
--write-treeWrite resulting tree to object database
-zUse NUL termination for output

Deprecated Mode Options (—trivial-merge):

Section titled “Deprecated Mode Options (—trivial-merge):”
OptionDescription
--trivial-mergeUse deprecated trivial merge mode
ParameterDescription
<branch1>First branch/commit to merge
<branch2>Second branch/commit to merge
<base-tree>Base tree for deprecated mode
Input: Two branches/commits to merge
Output: Tree object representing merged result
Conflict information if conflicts occur
Behavior: Performs merge without touching index or working tree
Can write resulting tree to object database
Shows conflicts that would occur in actual merge
Input: Base tree, branch1 tree, branch2 tree
Output: Merged tree object or conflict information
Note: This mode is deprecated in favor of --write-tree
Terminal window
# Test merge between two branches
git merge-tree main feature-branch
# Test merge with tree output
git merge-tree --write-tree main feature-branch
# Test merge between specific commits
git merge-tree HEAD~5 HEAD~3
Terminal window
# Check for conflicts before merging
if git merge-tree main feature-branch >/dev/null 2>&1; then
echo "✓ Clean merge possible"
git merge main feature-branch
else
echo "⚠ Conflicts would occur"
echo "Resolve conflicts manually or use different strategy"
fi
Terminal window
# Generate merged tree object
merged_tree=$(git merge-tree --write-tree main feature-branch | tail -1)
echo "Merged tree: $merged_tree"
# Use merged tree for further operations
git show "$merged_tree"
#!/bin/bash
# Comprehensive pre-merge conflict analysis
analyze_potential_merge() {
local branch1="$1"
local branch2="$2"
echo "=== Merge Analysis: $branch1 vs $branch2 ==="
# Get merge base
merge_base=$(git merge-base "$branch1" "$branch2")
echo "Merge base: $merge_base"
# Test merge
if merge_result=$(git merge-tree "$branch1" "$branch2" 2>/dev/null); then
echo "✓ Clean merge possible"
echo "Result tree: $(echo "$merge_result" | tail -1)"
return 0
else
echo "⚠ Conflicts detected"
# Analyze conflict details
echo "Conflict analysis:"
git merge-tree "$branch1" "$branch2" | head -20
return 1
fi
}
# Usage
analyze_potential_merge "main" "feature-x"
Terminal window
# Test multiple branch combinations
test_multiple_merges() {
local branches=("feature-a" "feature-b" "feature-c" "hotfix-1")
local base_branch="develop"
echo "=== Batch Merge Testing ==="
for branch in "${branches[@]}"; do
echo "Testing merge: $base_branch vs $branch"
if git merge-tree "$base_branch" "$branch" >/dev/null 2>&1; then
echo "$branch: Clean merge"
else
echo "$branch: Conflicts detected"
fi
done
# Test pairwise combinations
echo "=== Pairwise Testing ==="
for ((i=0; i<${#branches[@]}; i++)); do
for ((j=i+1; j<${#branches[@]}; j++)); do
branch1="${branches[i]}"
branch2="${branches[j]}"
if git merge-tree "$branch1" "$branch2" >/dev/null 2>&1; then
echo "$branch1 + $branch2: Compatible"
else
echo "$branch1 + $branch2: Conflicts"
fi
done
done
}
test_multiple_merges
Terminal window
# Perform virtual merges for analysis
virtual_merge_analysis() {
local source_branch="$1"
local target_branch="$2"
# Get merge base
base=$(git merge-base "$target_branch" "$source_branch")
# Perform virtual merge
virtual_result=$(git merge-tree "$target_branch" "$source_branch")
if [ $? -eq 0 ]; then
merged_tree=$(echo "$virtual_result" | tail -1)
echo "Virtual merge successful: $merged_tree"
# Analyze what would change
echo "Files that would change:"
git diff --name-only "$target_branch" "$merged_tree"
# Show diffstat
git diff --stat "$target_branch" "$merged_tree"
else
echo "Virtual merge shows conflicts"
echo "Conflict details:"
echo "$virtual_result"
fi
}
virtual_merge_analysis "feature-auth" "main"
#!/bin/bash
# Pre-merge validation in CI pipeline
validate_merge_in_ci() {
local source_branch="$1"
local target_branch="$2"
echo "=== CI Merge Validation ==="
# Test merge without affecting repository
if git merge-tree "$target_branch" "$source_branch" >/dev/null 2>&1; then
echo "✓ Merge would succeed"
# Get merge statistics
merged_tree=$(git merge-tree --write-tree "$target_branch" "$source_branch" | tail -1)
changes_count=$(git diff --name-only "$target_branch" "$merged_tree" | wc -l)
echo "Files that would change: $changes_count"
# Check for large changes
if [ "$changes_count" -gt 100 ]; then
echo "⚠ Large merge detected ($changes_count files)"
echo "Consider splitting into smaller merges"
fi
return 0
else
echo "✗ Merge would fail with conflicts"
# Show conflict details
git merge-tree "$target_branch" "$source_branch"
# Fail the build
exit 1
fi
}
# Usage in CI
validate_merge_in_ci "${CI_MERGE_REQUEST_SOURCE_BRANCH}" "${CI_MERGE_REQUEST_TARGET_BRANCH}"
Terminal window
# Choose merge strategy based on merge-tree analysis
select_merge_strategy() {
local source="$1"
local target="$2"
# Test different strategies
strategies=("recursive" "resolve" "octopus")
echo "=== Strategy Analysis ==="
for strategy in "${strategies[@]}"; do
echo "Testing strategy: $strategy"
# Test with strategy (if supported)
if git merge-tree "$target" "$source" >/dev/null 2>&1; then
echo "$strategy: Compatible"
else
echo "$strategy: Conflicts"
fi
done
# Recommend strategy
if git merge-tree "$target" "$source" >/dev/null 2>&1; then
echo "Recommendation: Use standard merge"
else
echo "Recommendation: Use interactive merge with mergetool"
fi
}
select_merge_strategy "feature-complex" "main"
Terminal window
# Monitor merge health across repository
monitor_merge_health() {
local branches=$(git branch -r | grep -v HEAD | head -10)
echo "=== Repository Merge Health ==="
# Test merges between active branches
for branch in $branches; do
clean_branch=$(echo "$branch" | sed 's|origin/||')
if [ "$clean_branch" != "HEAD" ] && git rev-parse --verify "$clean_branch" >/dev/null 2>&1; then
echo "Testing merge: main vs $clean_branch"
if git merge-tree main "$clean_branch" >/dev/null 2>&1; then
echo "$clean_branch: Healthy"
else
echo "$clean_branch: Conflicts"
fi
fi
done
}
monitor_merge_health
Terminal window
# Control merge-tree output format
git merge-tree --write-tree main feature-branch
# Use NUL termination for scripting
git merge-tree -z main feature-branch | xargs -0 process-tree
# Parse merge-tree output
git merge-tree main feature-branch | while read type sha path; do
echo "Type: $type, SHA: $sha, Path: $path"
done
Terminal window
# Optimize for large repositories
git config merge.renameLimit 999999
git config diff.renameLimit 999999
# Use merge-tree for performance testing
time git merge-tree main large-feature-branch >/dev/null
# Cache merge results for repeated testing
MERGE_CACHE="/tmp/merge-cache-$(echo "$1-$2" | sha1sum | cut -d' ' -f1)"
git merge-tree "$1" "$2" > "$MERGE_CACHE" 2>&1
Terminal window
# Check if branches exist
git rev-parse --verify branch1
git rev-parse --verify branch2
# Check repository integrity
git fsck --unreachable | head -10
# Verify commit objects
git cat-file -t $(git rev-parse branch1)
Terminal window
# Time merge operations
time git merge-tree main feature-branch >/dev/null
# Check repository size impact
du -sh .git/
git merge-tree --write-tree main feature-branch >/dev/null
du -sh .git/
# Optimize for large merges
git config pack.threads 0 # Auto-detect CPU
Terminal window
# Parse merge-tree output correctly
git merge-tree main feature-branch | while IFS=$'\t' read -r mode type sha path; do
echo "Mode: $mode, Type: $type, SHA: $sha, Path: $path"
done
# Handle special characters in paths
git merge-tree -z main feature-branch | xargs -0 -I {} echo "File: {}"
#!/bin/bash
# Validate merges before deployment
validate_deployment_merge() {
local release_branch="$1"
local production_branch="${2:-main}"
echo "=== Deployment Merge Validation ==="
# Test merge
if git merge-tree "$production_branch" "$release_branch" >/dev/null 2>&1; then
echo "✓ Release can be deployed safely"
# Get merge statistics
merged_tree=$(git merge-tree --write-tree "$production_branch" "$release_branch" | tail -1)
file_count=$(git diff --name-only "$production_branch" "$merged_tree" | wc -l)
echo "Files to be changed: $file_count"
# Check for high-risk changes
if git diff --name-only "$production_branch" "$merged_tree" | grep -q "config/database"; then
echo "⚠ Database configuration changes detected"
echo "Manual review required"
fi
return 0
else
echo "✗ Deployment would cause conflicts"
echo "Cannot deploy $release_branch to $production_branch"
return 1
fi
}
# Usage
validate_deployment_merge "release/v3.2.1" "production"
Terminal window
# Automated merge analysis for code review
automated_code_review() {
local pr_branch="$1"
local base_branch="${2:-main}"
echo "=== Automated Code Review ==="
# Test merge
if merge_result=$(git merge-tree "$base_branch" "$pr_branch" 2>/dev/null); then
echo "✓ No merge conflicts detected"
# Analyze changes
merged_tree=$(echo "$merge_result" | tail -1)
echo "=== Change Analysis ==="
echo "Files modified: $(git diff --name-only "$base_branch" "$merged_tree" | wc -l)"
echo "Lines added: $(git diff --stat "$base_branch" "$merged_tree" | tail -1 | awk '{print $4}')"
echo "Lines deleted: $(git diff --stat "$base_branch" "$merged_tree" | tail -1 | awk '{print $6}')"
# Check for review requirements
if git diff --name-only "$base_branch" "$merged_tree" | grep -q "\.md$"; then
echo "⚠ Documentation changes detected - review required"
fi
if git diff --name-only "$base_branch" "$merged_tree" | grep -q "security"; then
echo "⚠ Security-related changes - security review required"
fi
else
echo "✗ Merge conflicts detected"
echo "Code review cannot proceed until conflicts resolved"
return 1
fi
}
automated_code_review "feature/new-api" "develop"
Terminal window
# Analyze impact of repository restructuring
analyze_restructure_impact() {
local restructure_branch="$1"
local main_branch="${2:-main}"
echo "=== Repository Restructure Analysis ==="
# Test merge
if git merge-tree "$main_branch" "$restructure_branch" >/dev/null 2>&1; then
echo "✓ Restructure merge possible"
# Analyze structural changes
merged_tree=$(git merge-tree --write-tree "$main_branch" "$restructure_branch" | tail -1)
echo "=== Structural Impact ==="
# Check for moved/renamed files
moved_files=$(git diff --name-status "$main_branch" "$merged_tree" | grep -E "^[RD]" | wc -l)
echo "Files moved/renamed: $moved_files"
# Check for new directories
new_dirs=$(git diff --name-only "$main_branch" "$merged_tree" | xargs dirname | sort | uniq | wc -l)
echo "New directories: $new_dirs"
# Check for deleted files
deleted_files=$(git diff --name-only "$main_branch" "$merged_tree" | wc -l)
echo "Files deleted: $deleted_files"
# Generate migration guide
if [ "$moved_files" -gt 0 ] || [ "$deleted_files" -gt 0 ]; then
echo "=== Migration Guide ==="
echo "The following changes require attention:"
git diff --name-status "$main_branch" "$merged_tree" | grep -E "^[RD]" | \
while read status file; do
echo " $status: $file"
done
fi
else
echo "✗ Restructure would cause conflicts"
return 1
fi
}
analyze_restructure_impact "restructure/monorepo-split" "main"

What’s the difference between merge-tree and git merge?

Section titled “What’s the difference between merge-tree and git merge?”

git merge performs actual merge and modifies repository; git merge-tree performs virtual merge for analysis without touching repository state.

Can merge-tree work with more than two branches?

Section titled “Can merge-tree work with more than two branches?”

No, merge-tree handles two branches at a time. For multiple branches, use git merge with octopus strategy or test pairwise combinations.

Writes the resulting merged tree to Git’s object database, creating a tree object that represents the merge result for further analysis.

How do I handle merge-tree output in scripts?

Section titled “How do I handle merge-tree output in scripts?”

Parse the output format: each line shows mode, type, SHA, and path. Use -z option for NUL-terminated output when paths contain special characters.

What’s the performance advantage of merge-tree?

Section titled “What’s the performance advantage of merge-tree?”

Very fast since it doesn’t touch index or working tree. Useful for large repositories where actual merge would be expensive to test.

Yes, supports rename detection like git merge. Configure with git config merge.renameLimit for performance tuning.

How do I use merge-tree with Git LFS repositories?

Section titled “How do I use merge-tree with Git LFS repositories?”

Works normally - LFS pointers are Git objects like any other. merge-tree analyzes the Git repository structure, not LFS server content.

What’s the relationship between merge-tree and merge-base?

Section titled “What’s the relationship between merge-tree and merge-base?”

merge-tree uses merge-base internally to find common ancestors. merge-base provides the base commit, merge-tree performs the actual merge simulation.

Yes, operates on Git objects without needing working directory. Perfect for server-side merge analysis and CI/CD pipelines.

How do I handle merge-tree in automated environments?

Section titled “How do I handle merge-tree in automated environments?”

Use exit codes for conflict detection, parse output for conflict analysis, combine with —write-tree for result object generation.

What’s the deprecated —trivial-merge mode?

Section titled “What’s the deprecated —trivial-merge mode?”

Old mode that took three tree objects as arguments. Replaced by modern —write-tree mode that takes branch/commit references.

Yes, outputs conflict information in standard Git format when conflicts occur, showing which files have conflicts and conflict types.

How do I use merge-tree for merge strategy testing?

Section titled “How do I use merge-tree for merge strategy testing?”

Test different merge strategies by configuring git config merge.* settings before running merge-tree to see how they affect merge results.

What’s the storage impact of —write-tree?

Section titled “What’s the storage impact of —write-tree?”

Creates tree object in Git’s object database. Minimal storage overhead for testing and analysis purposes.

Yes, handles submodule changes like git merge. Shows submodule conflicts and updates in merge result.

Applications of the git merge-tree command

Section titled “Applications of the git merge-tree command”
  1. Pre-merge Conflict Detection: Test potential merges for conflicts before executing actual merges
  2. CI/CD Pipeline Integration: Validate merge viability in automated build and deployment processes
  3. Merge Strategy Analysis: Test different merge approaches and strategies without repository modification
  4. Repository Health Monitoring: Analyze merge relationships and potential conflicts across branches
  5. Automated Code Review: Support automated code review processes with merge conflict analysis
  6. Deployment Planning: Validate deployment merges and analyze impact before production deployment