Three statements were false against the git in use (2.39.5), each verified by
running it.
`git rebase --autosquash HEAD~N` without `-i` is a silent no-op: git prints
"Successfully rebased", the `fixup!` commit survives with the same SHA, and
rewrite-history.md presented that as the preferred flow with `-i` as an optional
review step. The agent reports the squash as done and the `fixup!` subject then
trips this repo's own commit-msg gate. `-i` is now the command, not the alternative.
"Fetch never modifies a local branch, so it is always safe to run" — new text on
this branch — is false: `git fetch origin main:probe` fast-forwarded the local
branch, and a `+` prefix force-updates it, losing commits. The claim is scoped to
the no-refspec form.
`git worktree add --orphan` does not exist before Git 2.42; on 2.39.5 it is
`error: unknown option 'orphan'`, exit 129. The same file gives a version floor for
`--recurse-submodules` three sections earlier. Floor added, with a fallback that
was tested before being documented.
git-workflow claimed "every request resolves to exactly one of these six" while
rebase, reset and stash were owned by no skill — `git reset` appeared nowhere in
the plugin, old tree or new — so "undo my last commit" routed nowhere. The claim is
gone, the router gains rows for all three, and the procedures now exist: plain
rebase with `--onto` and conflict handling, a reset mode table gated on `--hard`,
and stash save/pop/list/drop. `--hard` gets an always-loaded Gotcha, matching the
register the force-push refusal already sets.
Cherry-pick had three claimants pointing at git-history while git-commits owned the
flow, and the two copies were not equivalent — git-history's lacked the destination
check, the rtk prefix and `--abort`. Resolved to git-commits per #112; the weaker
duplicate is replaced by a hand-off.
git-commits' metadata.version was deleted rather than bumped in 14af50b, leaving two
house-contract documents citing a worked v0.1.2 to v0.1.3 transition against a file
declaring no version. Restored to 0.1.3.
Also: the divergent-pull explanation stated a `--ff-only` default that does not
exist (it is a hard error); `--remote` "requires" a configured branch where it uses
one; `git push origin --delete` moved to git-remotes, which owns the remote-side
gates; seven retired `git:<name>` source slugs; git-orchestrate quoted a
git-workflow sentence that no longer exists; git-submodules regains the indirect
trigger that made "add a dependency repo" routable; and commit atomicity is a common
gate rather than reachable only from the create flow.
Refs: #112, #113
66 lines
3.1 KiB
Markdown
66 lines
3.1 KiB
Markdown
---
|
|
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:
|
|
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/<name>/` 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 '<cmd>'`. Inside
|
|
`<cmd>`, 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: <clone|add|init|update|status|sync|set-url|set-branch|absorbgitdirs|deinit|remove>
|
|
status: <success|error|partial>
|
|
message: <one line; include git's own output on error>
|
|
details:
|
|
- <submodule-path>: <state>
|
|
conflicts: [<submodule-path>, ...]
|
|
next_step: <recovery action, when status is error or partial>
|
|
```
|