Skip to content

modules Git Command Guide

The git submodule command manages external Git repositories embedded within a parent Git repository as submodules. Submodules allow you to include other Git repositories as subdirectories while maintaining their independent version control history.

Terminal window
git submodule [--quiet] [--cached]
git submodule [--quiet] add [<options>] [--] <repository> [<path>]
git submodule [--quiet] status [--cached] [--recursive] [--] [<path>...]
git submodule [--quiet] init [--] [<path>...]
git submodule [--quiet] deinit [-f|--force] (--all|[--] <path>...)
git submodule [--quiet] update [<options>] [--] [<path>...]
git submodule [--quiet] set-branch [<options>] [--] <path>
git submodule [--quiet] set-url [--] <path> <newurl>
git submodule [--quiet] summary [<options>] [--] [<path>...]
git submodule [--quiet] foreach [--recursive] <command>
git submodule [--quiet] sync [--recursive] [--] [<path>...]
git submodule [--quiet] absorbgitdirs [--] [<path>...]
OptionDescription
--quiet, -qSuppress output messages
--cachedUse commit stored in index instead of working tree
CommandDescription
add <repo> [<path>]Add a submodule to the repository
status [<path>...]Show submodule status
init [<path>...]Initialize submodule configuration
deinit [<path>...]Unregister submodules
update [<path>...]Update submodules to specified commits
sync [<path>...]Synchronize submodule URLs
CommandDescription
set-branch <path>Set default branch for submodule
set-url <path> <url>Change submodule URL
summary [<path>...]Show commit summary between submodule and superproject
foreach <command>Execute command in each submodule
absorbgitdirs [<path>...]Move git directories into submodules
Parent Repository (Superproject)
├── .gitmodules (configuration file)
├── submodule/ (submodule directory)
│ ├── .git (gitlink - points to submodule commit)
│ └── [submodule files]
└── .git/modules/submodule/ (actual submodule repository)
Gitlink: Special entry in parent tree pointing to submodule commit
Submodule: Actual Git repository stored in .git/modules/
Directory: Working directory checked out to specific commit
[submodule "path/to/submodule"]
path = path/to/submodule
url = https://github.com/user/repo.git
branch = main
ignore = dirty
fetchRecurseSubmodules = on-demand
Terminal window
# Add submodule at specific path
git submodule add https://github.com/user/library.git libs/library
# Add submodule with custom path
git submodule add https://github.com/user/theme.git themes/custom
# Add submodule from relative path
git submodule add ../shared/components.git src/components
# Add submodule with specific branch
git submodule add -b develop https://github.com/user/api.git services/api
Terminal window
# Initialize all submodules
git submodule init
# Initialize specific submodules
git submodule init libs/library themes/custom
# Initialize and update in one step
git submodule update --init
Terminal window
# Update all submodules to committed versions
git submodule update
# Update specific submodules
git submodule update libs/library
# Update with recursive submodule fetching
git submodule update --recursive
# Update to latest remote commits
git submodule update --remote
Terminal window
# Show submodule status
git submodule status
# Show cached status (index vs HEAD)
git submodule status --cached
# Show recursive status
git submodule status --recursive
# Show summary of changes
git submodule summary
#!/bin/bash
# Complete submodule development workflow
setup_submodule_development() {
local submodule_path="$1"
echo "Setting up development environment for $submodule_path"
# Initialize and update
git submodule init "$submodule_path"
git submodule update "$submodule_path"
# Enter submodule and set up development
cd "$submodule_path"
# Create development branch if needed
if ! git branch | grep -q "develop"; then
git checkout -b develop
else
git checkout develop
fi
# Set up tracking
git branch --set-upstream-to=origin/develop develop
cd -
echo "Development environment ready for $submodule_path"
}
# Usage
setup_submodule_development "libs/mylib"
Terminal window
# Sync submodule URLs after repository move
git submodule sync
# Sync specific submodule
git submodule sync libs/library
# Sync recursively
git submodule sync --recursive
# Update URLs in .gitmodules
git submodule sync --recursive
git add .gitmodules
git commit -m "Update submodule URLs"
Terminal window
# Set default branch for submodule
git submodule set-branch --branch develop libs/library
# Set branch for specific submodule
git submodule set-branch --default libs/library
# Update to branch tip
git submodule update --remote libs/library
Terminal window
# Change submodule URL
git submodule set-url libs/library https://new-url.com/library.git
# Update .gitmodules file
git add .gitmodules
git commit -m "Update submodule URL for library"
# Sync URL changes
git submodule sync libs/library
#!/bin/bash
# CI/CD pipeline for projects with submodules
ci_submodule_setup() {
echo "Setting up submodules for CI/CD"
# Shallow clone with submodules
git submodule init
git submodule update --depth 1
# Verify submodule integrity
if ! git submodule status | grep -q "^-"; then
echo "✓ All submodules properly initialized"
else
echo "✗ Some submodules not properly initialized"
exit 1
fi
# Run submodule-specific tests
git submodule foreach 'echo "Testing $name" && make test || exit 1'
}
# Usage in CI
ci_submodule_setup
Terminal window
# Manage releases with submodules
create_release_with_submodules() {
local version="$1"
echo "Creating release v$version with submodule updates"
# Update all submodules to latest
git submodule foreach 'git checkout main && git pull'
# Update submodule references
git add .
git commit -m "Update submodules for release v$version"
# Create release tag
git tag -a "v$version" -m "Release v$version
Includes updated submodules:
$(git submodule status | sed 's/^/- /')"
# Push changes and tags
git push origin main
git push origin "v$version"
echo "Release v$version created with updated submodules"
}
# Usage
create_release_with_submodules "2.1.0"
Terminal window
# Handle submodules in team environments
team_submodule_workflow() {
local submodule_path="$1"
local feature_branch="$2"
echo "Setting up team workflow for $submodule_path"
# Ensure submodule is initialized
git submodule init "$submodule_path"
git submodule update "$submodule_path"
# Create feature branch in submodule
cd "$submodule_path"
git checkout -b "$feature_branch"
git push -u origin "$feature_branch"
cd -
# Update parent repository
git add "$submodule_path"
git commit -m "Update $submodule_path to feature branch $feature_branch"
echo "Team workflow setup complete"
echo "Submodule feature branch: $feature_branch"
}
# Usage
team_submodule_workflow "libs/ui" "feature/dark-mode"
# Comprehensive .gitmodules configuration
[submodule "libs/core"]
path = libs/core
url = https://github.com/company/core-lib.git
branch = main
ignore = dirty
fetchRecurseSubmodules = on-demand
update = checkout
[submodule "themes/default"]
path = themes/default
url = ../themes/default.git
branch = stable
ignore = all
fetchRecurseSubmodules = no
Terminal window
# Configure ignore behavior
# In .gitmodules:
[submodule "libs/library"]
ignore = none # Check all submodule changes
ignore = dirty # Ignore work tree changes
ignore = untracked # Ignore untracked files
ignore = all # Ignore all changes
Terminal window
# Different update strategies
git config submodule.libs/library.update checkout # Default
git config submodule.libs/library.update rebase # Rebase local changes
git config submodule.libs/library.update merge # Merge changes
git config submodule.libs/library.update none # Manual updates only
Terminal window
# Optimize submodule operations
git config submodule.fetchJobs 4 # Parallel fetching
git config submodule.alternateLocation /cache/git # Shared object cache
git config submodule.alternateErrorStrategy ignore # Ignore cache misses
# Shallow clone submodules
git submodule update --depth 1
# Disable recursive operations for performance
git config submodule.recurse false
Terminal window
# Check submodule status
git submodule status
# Output shows '-' for uninitialized submodules
# Initialize and update
git submodule init problematic/submodule
git submodule update problematic/submodule
# Or initialize all
git submodule update --init
Terminal window
# Check if submodule is in detached HEAD
cd libs/library
git branch -v
# No '*' indicates detached HEAD
# Fix by checking out a branch
git checkout main
cd -
# Update parent repository
git add libs/library
git commit -m "Fix submodule branch reference"
Terminal window
# Check URL mismatch
git submodule status
# Shows '+' for URL mismatches
# Sync URLs
git submodule sync
# Update .gitmodules if needed
git add .gitmodules
git commit -m "Sync submodule URLs"
Terminal window
# Handle nested submodules
git submodule update --recursive
# Check nested status
git submodule status --recursive
# Initialize nested submodules
git submodule foreach --recursive git submodule init
git submodule foreach --recursive git submodule update
Terminal window
# Check submodule permissions
ls -la .git/modules/libs/library/
# Fix permissions
chmod -R 755 .git/modules/libs/library/
# Handle SSH key issues
git config submodule.libs/library.url git@github.com:user/repo.git
#!/bin/bash
# Migrate monorepo to submodule architecture
monorepo_to_submodules() {
local monorepo_dir="$1"
local components=("api" "web" "mobile" "shared")
echo "Migrating monorepo to submodule architecture"
# Create separate repositories for each component
for component in "${components[@]}"; do
echo "Creating repository for $component"
# Create new repository
mkdir -p "../${component}-repo"
cd "../${component}-repo"
git init --bare
cd -
# Extract component history
git subtree push --prefix="$component" "../${component}-repo" main
# Add as submodule
git submodule add "../${component}-repo" "$component"
done
# Remove original directories
for component in "${components[@]}"; do
git rm -r "$component"
done
# Commit submodule structure
git add .
git commit -m "Migrate to submodule architecture
Converted components to separate repositories:
$(printf -- '- %s\n' "${components[@]}")"
echo "Migration complete"
}
# Usage
monorepo_to_submodules "/path/to/monorepo"
Terminal window
# Manage enterprise components with submodules
enterprise_component_management() {
local component_name="$1"
local component_repo="$2"
local component_path="$3"
echo "Adding enterprise component: $component_name"
# Add submodule with enterprise configuration
git submodule add "$component_repo" "$component_path"
# Configure enterprise settings
cat >> .gitmodules << EOF
[submodule "$component_path"]
path = $component_path
url = $component_repo
branch = enterprise
ignore = dirty
fetchRecurseSubmodules = on-demand
EOF
# Set up component-specific configuration
mkdir -p "config/components/$component_name"
cat > "config/components/$component_name/config.yml" << EOF
component: $component_name
repository: $component_repo
path: $component_path
version: enterprise
security-policy: strict
compliance: sox
EOF
# Initialize and configure
git submodule init "$component_path"
git submodule update "$component_path"
# Set up monitoring
git submodule set-branch --branch enterprise "$component_path"
# Commit configuration
git add .gitmodules "config/components/$component_name/"
git commit -m "Add enterprise component: $component_name
Component Details:
- Repository: $component_repo
- Path: $component_path
- Branch: enterprise
- Security: strict compliance"
echo "Enterprise component $component_name added successfully"
}
# Usage
enterprise_component_management "payment-gateway" \
"git@enterprise.com:components/payment-gateway.git" \
"services/payment"
Terminal window
# Integrate open source libraries as submodules
integrate_open_source_library() {
local library_name="$1"
local library_repo="$2"
local library_version="$3"
echo "Integrating open source library: $library_name"
# Add as submodule
git submodule add "$library_repo" "libs/$library_name"
# Configure for stability
cat >> .gitmodules << EOF
[submodule "libs/$library_name"]
path = libs/$library_name
url = $library_repo
branch = $library_version
ignore = all
fetchRecurseSubmodules = no
EOF
# Initialize and pin to specific version
git submodule init "libs/$library_name"
git submodule update "libs/$library_name"
# Pin to specific commit/tag
cd "libs/$library_name"
if git tag | grep -q "^$library_version$"; then
git checkout "tags/$library_version"
elif git branch -r | grep -q "origin/$library_version"; then
git checkout "$library_version"
git pull origin "$library_version"
else
git checkout "$library_version"
fi
cd -
# Update parent reference
git add "libs/$library_name"
git commit -m "Integrate $library_name library v$library_version
Library: $library_name
Repository: $library_repo
Version: $library_version
License: [check library license]
Security: [verify library security]"
echo "Library $library_name v$library_version integrated"
}
# Usage
integrate_open_source_library "logging-lib" \
"https://github.com/open-source/logging-lib.git" \
"v2.1.0"

What’s the difference between submodules and git subtree?

Section titled “What’s the difference between submodules and git subtree?”

Submodules reference external repositories with separate history; subtree merges external repository history into main repository, losing external repository independence.

Use git submodule deinit path/to/submodule, then git rm path/to/submodule, and remove from .gitmodules. Also remove .git/modules/submodule directory.

Yes, submodules can be nested. Use —recursive flag for operations on nested submodules. Be cautious as this increases complexity.

How do I update all submodules to latest versions?

Section titled “How do I update all submodules to latest versions?”

Use git submodule update —remote to update all submodules to latest remote commits, or git submodule foreach git pull origin main to update each submodule.

What happens if a submodule repository is deleted?

Section titled “What happens if a submodule repository is deleted?”

Submodule becomes unusable. Always ensure submodule repositories are accessible. Consider mirroring critical submodules.

Yes, but changes are separate from parent repository. Commit in submodule first, then update parent repository reference with git add submodule-path.

Resolve conflicts in submodule first, then update parent repository. Use git submodule update —merge to handle submodule merge conflicts.

What’s the impact of submodules on repository size?

Section titled “What’s the impact of submodules on repository size?”

Submodules don’t increase repository size significantly (only gitlinks). Actual submodule repositories are cloned separately, so disk usage depends on clone strategy.

Yes, submodules can use Git LFS independently. LFS configuration is per-repository, so each submodule manages its own large files.

How do I migrate from submodules to a different approach?

Section titled “How do I migrate from submodules to a different approach?”

Use git submodule deinit —all && git rm .gitmodules to remove all submodules, then add code directly or use different dependency management.

What’s the relationship between submodules and monorepos?

Section titled “What’s the relationship between submodules and monorepos?”

Submodules provide loose coupling between components; monorepos provide tight coupling. Choose based on team size, release cadence, and organizational structure.

Can I use submodules with GitHub/GitLab features?

Section titled “Can I use submodules with GitHub/GitLab features?”

Yes, platforms provide submodule support in web interfaces, showing submodule status and allowing navigation to submodule repositories.

Configure SSH keys or personal access tokens for submodule repositories. Use git config submodule.repo.url with authenticated URLs.

What’s the performance impact of many submodules?

Section titled “What’s the performance impact of many submodules?”

Each submodule requires separate network operations. Use shallow clones, parallel fetching, and consider consolidating related submodules.

Can submodules be used in CI/CD pipelines?

Section titled “Can submodules be used in CI/CD pipelines?”

Yes, but requires careful setup. Use git submodule update —init —recursive in CI, and cache submodule repositories for performance.

Use git submodule status —recursive for comprehensive status, check .git/modules/ for submodule repositories, and verify .gitmodules configuration.

  1. Dependency Management: Manage external library and component dependencies with independent version control
  2. Monorepo Decomposition: Break large monorepos into manageable, independently versioned components
  3. Cross-Team Collaboration: Enable different teams to work on shared components while maintaining isolation
  4. Open Source Integration: Incorporate external open source libraries while tracking specific versions
  5. Enterprise Architecture: Support microservices and component-based architectures with proper versioning
  6. Release Management: Coordinate releases across multiple interdependent repositories