git submodule โ Embedding Repositories
What is a Submodule?โ
A submodule is a Git repository embedded inside another Git repository. The parent repository stores a reference to a specific commit of the submodule โ not the submodule's files directly. This lets you include shared libraries, infrastructure configs, or third-party code while tracking them independently.
Adding a Submoduleโ
# Commit the addition
git commit -m "chore: add shared-proto and infra-config as submodules"
This creates:
- A
libs/shared-proto/directory (the submodule content) - A
.gitmodulesfile tracking all submodules:
[submodule "libs/shared-proto"]
path = libs/shared-proto
url = [email protected]:your-org/shared-proto.git
branch = main
Cloning a Repository with Submodulesโ
# Clone and initialise all submodules in one step (recommended)
# If you already cloned without submodules
git submodule update --init --recursive
Updating Submodulesโ
Update all submodules to their tracked commitโ
git submodule update --recursive
Pull latest changes from submodule's remote branchโ
# Update all submodules to the latest commit on their tracked branch
git submodule update --remote --recursive
# Update a single submodule
git submodule update --remote libs/shared-proto
After pulling the parent repo (colleagues may have updated submodule refs)โ
git pull
git submodule update --init --recursive
Working Inside a Submoduleโ
# Enter the submodule
cd libs/shared-proto
# It is a fully independent Git repository
git log --oneline
git switch -c fix/update-proto
# Make changes, commit, push...
git push origin fix/update-proto
# Return to parent
cd ../..
# The parent repo now shows the submodule as "modified"
git status
# modified: libs/shared-proto (new commits)
# Stage and commit the updated submodule reference
git add libs/shared-proto
git commit -m "chore: bump shared-proto to v2.1.0"
Removing a Submoduleโ
# Step 1: Remove from .gitmodules
git submodule deinit -f libs/shared-proto
# Step 2: Remove from .git/modules cache
rm -rf .git/modules/libs/shared-proto
# Step 3: Remove the tracked directory
git rm -f libs/shared-proto
# Step 4: Commit
git commit -m "chore: remove shared-proto submodule"
Useful Commands Summaryโ
| Command | Meaning |
|---|---|
git submodule add <url> <path> | Add a new submodule |
git submodule update --init --recursive | Initialise and fetch all submodules |
git submodule update --remote | Pull latest from submodule's remote branch |
git submodule status | Show current commit of each submodule |
git submodule foreach git pull | Pull latest in all submodules |
git submodule deinit <path> | Unregister a submodule |
Submodules are powerful but add operational complexity โ especially for CI/CD pipelines and teammates unfamiliar with the workflow. For sharing Java libraries across services, consider publishing to a private Maven/Gradle repository (Nexus, GitHub Packages, Artifactory) instead. Reserve submodules for cases where you genuinely need to co-develop the shared code alongside the parent project.
Interview Questions (Senior Level)โ
- How do you decide between submodules and package registries for shared code?
- What CI/CD controls are required for stable submodule workflows?
- How do you prevent detached-head confusion in submodule contributors?
- What rollback strategy do you use when a submodule bump breaks production?
Short answer guide:
- Prefer package distribution unless co-development is required.
- Pin commits, enforce recursive init/update, and validate refs in CI.
- Train on branch workflow inside submodule repos.
- Revert pointer commits quickly and test compatibility matrices.
Explain when submodules are justified and what CI controls make them reliable.
Treating submodules like normal directories and forgetting pointer commit management.