Progress:
TIER 1 · MODULE 33· Basics

git submodule

Powerful, fragile, often the wrong answer. Know when it isn't.

🎯 What & why

Pin one Git repo as a subdirectory inside another, locked at a specific commit. Powerful when used right; a frequent source of confusion when not.

🧠 Mental model

A submodule is recorded as a special tree entry: gitlink pointing at a commit SHA in another repo. The parent doesn't store the submodule's contents — it stores 'this directory is the contents of repo X at commit Y.' .gitmodules records the submodule URL and path.

🛠️ Synopsis

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>...]

🎚️ Switches & options

FlagWhat it does
add <url> [<path>]Add a submodule.
update --init --recursiveInitialize and clone all submodules (run after a clone).
foreach <cmd>Run <cmd> in every submodule.
deinit <path>Remove a submodule's working tree.

📦 Subcommands

add <url> [<path>] — Add a submodule at <path> (default: derived from URL).
$ git submodule add https://example.com/lib.git vendor/lib
init [<path>...] — Register submodules listed in .gitmodules into .git/config.
$ git submodule init
update [--init] [--recursive] [<path>...] — Clone submodules and check out their pinned commits.
$ git submodule update --init --recursive
status [--recursive] [<path>...] — Show each submodule's commit and dirty state.
$ git submodule status
sync [--recursive] [<path>...] — Re-read URLs from .gitmodules into local config.
$ git submodule sync
foreach [--recursive] <cmd> — Run <cmd> in every submodule's working tree.
$ git submodule foreach 'git pull --ff-only'
deinit [-f] (--all | <path>...) — Unregister and remove a submodule's working tree.
$ git submodule deinit -f vendor/lib
set-url <path> <newurl> — Change the URL recorded in .gitmodules.
$ git submodule set-url vendor/lib git@new.host:lib.git

💡 Use cases

🧪 Examples

Add a submodule.
$ git submodule add https://example.com/lib.git vendor/lib
After cloning a repo with submodules:
$ git clone --recurse-submodules <url>
# or, after the fact:
$ git submodule update --init --recursive
Pull the submodule's tip.
$ git submodule update --remote vendor/lib

🎓 Recommendations

🪤 Common pitfalls

🔗 Related modules

📝 Quiz

Hit each option, then Check answers. Score is recorded; Next is always open.