Submodules
A submodule embeds one Git repository inside another as a subdirectory, pinned to a specific commit — used to vendor a dependency while keeping its own independent history and remote.
Adding a submodule
git submodule add https://github.com/example/lib.git libs/lib
git commit -m "Add lib submodule"
This creates a .gitmodules file (tracked, describes the mapping) and a
gitlink entry in the parent repo’s tree pointing at the submodule’s current
commit — the parent repo never stores the submodule’s files, only which
commit it’s pinned to.
Cloning a repo that has submodules
Plain git clone leaves submodule directories empty. Either clone with a
flag, or initialize afterward:
git clone --recurse-submodules <url>
# already cloned without it?
git submodule update --init --recursive
Updating a submodule
cd libs/lib
git fetch
git checkout <new-sha-or-branch>
cd ../..
git add libs/lib
git commit -m "Bump lib submodule"
Or, to update every submodule to the latest commit on the branch each one tracks:
git submodule update --remote --merge
Other useful commands
git submodule status # current SHA of each submodule
git submodule foreach 'git status' # run a command in every submodule
git submodule deinit libs/lib # remove the working copy, keep the config
git rm libs/lib # fully remove the submodule
Common pitfalls
- Forgetting
--recurse-submoduleson clone leaves empty directories that look broken but aren’t — rungit submodule update --init --recursive. - Detached HEAD inside the submodule is the normal state after an update — the parent repo tracks a commit, not a branch. Commit new work inside a submodule on an actual branch, or it’s easy to lose.
- Forgetting to commit the pointer bump in the parent repo after updating a submodule means everyone else still checks out the old commit.
Alternatives worth knowing about if submodules feel too heavyweight:
git subtree (built in, copies history into the parent repo instead of
pinning a pointer) and language-level package managers (npm, pub, cargo)
for anything that’s actually published as a package rather than vendored
source.