The frustration list
Submodules are powerful but trip new users repeatedly. This page catalogs the most common failures and the recipes that fix them.
Empty submodule directory
You cloned the parent but the subdir is empty. Initialize and update:
git submodule update --init --recursive
Detached HEAD edits lost
You edited inside a submodule, committed, then ran git submodule update in the parent. The update reset the submodule to the recorded SHA, abandoning your work on a detached HEAD. Recover with git reflog inside the submodule.
cd third_party/lib
git reflog
git checkout -b rescue HEAD@{1}
Always create a branch inside a submodule before editing.
URL changed upstream
If the submodule's remote URL moves, edit .gitmodules, then sync local config:
git submodule sync --recursive
git submodule update --init --recursive
Removing a submodule
There is no single "remove" command. The clean recipe:
git submodule deinit -f third_party/lib
git rm -f third_party/lib
rm -rf .git/modules/third_party/lib
git commit -m "Remove lib submodule"
Modified content but no diff
Parent shows the submodule as modified though you did not edit it. The submodule HEAD has moved (a fetch, checkout, or build script). Either commit the new SHA in the parent or reset the submodule:
git submodule update --recursive # restore recorded SHA
# or
git add third_party/lib && git commit -m "Bump lib"
Push order matters
If you commit the parent referencing a SHA you have not pushed in the submodule, collaborators cannot resolve the reference. Enforce safety:
git config --global push.recurseSubmodules on-demand
Shallow submodules
For CI, use shallow clones to save time:
git submodule update --init --recursive --depth 1
Common mistakes
Treating submodules like normal subdirectories — they are not, every Git command stops at the boundary unless you pass --recurse-submodules. Mixing branch-tracking submodules with pinned-SHA workflows leads to confusion; pick one model per project. Forgetting that git status in the parent only summarizes submodule state — run it inside the submodule for details.
Related
See "Submodules: adding and updating" for the basics, and "Subtrees: a simpler alternative to submodules" when the pain outweighs the benefit.