Powerful, fragile, often the wrong answer. Know when it isn't.
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.
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.
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>...]| Flag | What it does |
|---|---|
add <url> [<path>] | Add a submodule. |
update --init --recursive | Initialize and clone all submodules (run after a clone). |
foreach <cmd> | Run <cmd> in every submodule. |
deinit <path> | Remove a submodule's working tree. |
<path> (default: derived from URL).$ git submodule add https://example.com/lib.git vendor/lib.gitmodules into .git/config.$ git submodule init$ git submodule update --init --recursive$ git submodule status.gitmodules into local config.$ git submodule sync<cmd> in every submodule's working tree.$ git submodule foreach 'git pull --ff-only'$ git submodule deinit -f vendor/lib.gitmodules.$ git submodule set-url vendor/lib git@new.host:lib.git$ git submodule add https://example.com/lib.git vendor/lib$ git clone --recurse-submodules <url>
# or, after the fact:
$ git submodule update --init --recursive$ git submodule update --remote vendor/libgit subtree or a package manager. Reach for submodules only when you need Git-level pinning.submodule.recurse=true so commands recurse by default.--recurse-submodules on clone leaves you with empty submodule directories.Hit each option, then Check answers. Score is recorded; Next is always open.