--- name: git-submodules description: > Use when managing Git submodules — the full lifecycle of a nested repository inside a superproject — including phrasings that never say the word, such as "add a dependency repo" or "vendor this repo inside ours". Not multiple checkouts of one repo -> `git-worktrees`. Not the superproject's own remotes -> `git-remotes`. metadata: version: "1.0.2" category: git source_keys: - git-scm-submodule-docs --- ## Gotchas - **`update` leaves the submodule in detached HEAD.** Branch inside the submodule before editing, or the work is unreachable once the pointer moves. - **Push the submodule before the superproject.** The superproject stores only a SHA, and one missing from the submodule's remote breaks every collaborator's `update`. - **`--recursive` is never the default.** Subcommands stop one level deep, so nested submodules go stale silently. - **`git rm` leaves `.git/modules//` behind.** Nothing cleans it up, and it blocks re-adding a submodule there. ## Working rules Run `rtk git` from the superproject root. Enter the submodule directory only for commits and pushes that belong to the submodule's own history — the two repositories have independent histories, and the same command from the wrong directory writes to the wrong one. Before committing a superproject pointer, run `rtk git submodule status --recursive`. Prefixes: `-` not initialized, `+` working tree differs from the recorded commit, `U` merge conflict. Add `--cached` to read the SHAs the superproject index will record rather than the working-tree state. A `-dirty` suffix means uncommitted changes inside the submodule, and committing the pointer over them pins a state nobody else can reproduce. To run one command across every submodule: `rtk git submodule foreach --recursive ''`. Inside ``, Git sets `$name`, `$sm_path`, `$displaypath`, `$sha1` and `$toplevel`; append `|| :` to continue past a failure instead of aborting the traversal. `$sm_path` and `$displaypath` name the same directory from different vantage points — if which one you want is not obvious, read the variable table in `references/setup-and-update.md` before writing the command. ## Dispatch Read only the row that matches the request. | Task | Reference | |---|---| | Clone a superproject with submodules; add, initialize, update or re-pin one; run a command across all of them with `foreach` | `references/setup-and-update.md` | | Change where a submodule points — `sync`, `set-url`, `set-branch`, a local mirror override, `absorbgitdirs`, or any `.gitmodules` / `.git/config` key | `references/urls-and-config.md` | | Remove a submodule, or `deinit` one without removing it | `references/removal.md` | Removal and `deinit` are destructive: state what will be deleted and get confirmation before executing. ## Output format ```yaml operation: status: message: details: - : conflicts: [, ...] next_step: ```