Skip to main content

Submodules & Subtrees

Quick Summary

Submodules and subtrees let you include one Git repository inside another. Submodules keep the nested repo as a separate entity (linked by reference). Subtrees merge the nested repo's code directly into your project. Both solve the same problem — sharing code across repositories — but with very different trade-offs.


Submodules

A submodule is a pointer to a specific commit in another repository.

Adding a Submodule

git submodule add git@github.com:donnyaw/shared-lib.git libs/shared
git commit -m "Add shared-lib submodule"

This creates:

  • libs/shared/ — directory with the submodule content
  • .gitmodules — configuration file mapping paths to URLs

Cloning a Repo with Submodules

# Clone and initialize submodules in one step
git clone --recurse-submodules git@github.com:donnyaw/project.git

# Or after a regular clone
git submodule init
git submodule update

Updating Submodules

# Pull latest from submodule's remote
cd libs/shared
git pull origin main
cd ../..

# Commit the updated submodule reference
git add libs/shared
git commit -m "Update shared-lib to latest"

Removing a Submodule

git submodule deinit libs/shared
git rm libs/shared
rm -rf .git/modules/libs/shared
git commit -m "Remove shared-lib submodule"

Subtrees

A subtree copies the external repo's content directly into your project tree.

Adding a Subtree

git subtree add --prefix=libs/shared git@github.com:donnyaw/shared-lib.git main --squash
git commit -m "Add shared-lib as subtree"

Updating a Subtree

git subtree pull --prefix=libs/shared git@github.com:donnyaw/shared-lib.git main --squash

Pushing Changes Back

git subtree push --prefix=libs/shared git@github.com:donnyaw/shared-lib.git main

Comparison

AspectSubmodulesSubtrees
StoragePointer (reference)Full copy in tree
Clone behaviorRequires --recurse-submodulesJust works (normal clone)
ComplexityHigher (extra commands)Lower (standard Git)
Offline workNeed to init/updateAlways available
Contributing backcd into submodule, commit/pushgit subtree push
HistorySeparate (linked repo)Merged into main repo
Best forLarge, independent reposSmall, tightly-coupled shared code

When to Use Each

ScenarioRecommendation
Shared library used by many projectsSubmodule
Vendor/third-party code you rarely updateSubtree
You want contributors to "just clone and build"Subtree
You need independent version control for the nested repoSubmodule
Small utility that changes infrequentlySubtree

Best Practices

  • Prefer subtrees for simplicity — they don't require extra setup from contributors
  • Use submodules for large, independent projects — keeps repo sizes manageable
  • Always use --squash with subtrees — avoids cluttering your history with the external repo's full history
  • Document submodule setup in your README — many developers forget --recurse-submodules

What's Next

  1. Hooks & Automation — Run scripts automatically on Git events
  2. Troubleshooting — Fix common Git problems