feat(git-plugin): add complete git workflow automation suite
## Why The git plugin only covered a partial slice of common git workflows. This adds the remaining skill set (branches, commits, history, remotes, submodules, workflow, worktrees) plus a git-orchestrate agent so the plugin can handle end-to-end git automation instead of a handful of commands. ## Implementation Notes Each new skill was validated against its research docs and org conventions after initial authoring, which surfaced hallucinated version pins, factual errors, and completeness gaps that were corrected in the same pass rather than left for follow-up. ## Impact Bumps the git plugin to 1.3.0. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
24
plugins/git/skills/git-submodules/README.md
Normal file
24
plugins/git/skills/git-submodules/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# git-submodules
|
||||
|
||||
Initialize, clone, update, and manage git submodules for multi-repository projects.
|
||||
|
||||
## What it does
|
||||
|
||||
This skill handles submodule operations within the git workflow suite. It initializes submodules, clones repositories with nested submodule dependencies, updates submodule pinning, and manages version control across multi-repo projects. The skill provides clean workflows for projects with complex dependency structures and returns structured results suitable for agent composition.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/git-submodules
|
||||
```
|
||||
|
||||
Describe your submodule task: initialize, clone, update, or manage versions. The skill will handle the operation and return structured results (operation, status, per-submodule details, conflicts, and a recovery `next_step` when applicable) suitable for agent composition.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Skill instructions for agents |
|
||||
| `references/README.md` | Describes contents of references/ |
|
||||
| `references/submodules.md` | Deep-dive reference: full flag tables, workflow patterns, safe-removal sequence, `absorbgitdirs`, `foreach` variables |
|
||||
| `references/sources.md` | Research sources and provenance |
|
||||
91
plugins/git/skills/git-submodules/SKILL.md
Normal file
91
plugins/git/skills/git-submodules/SKILL.md
Normal file
@@ -0,0 +1,91 @@
|
||||
---
|
||||
name: git-submodules
|
||||
|
||||
description: >
|
||||
Use when managing Git submodules: add dependencies as submodules, initialize and update nested repositories, sync URLs, inspect status (including detached HEAD and divergence), and safely remove submodules. Handles multi-repo projects with pinning, parallel operations, and recursive traversal. Use for both initial setup and ongoing maintenance workflows, even if the user doesn't explicitly say "submodule". Do not use for general git operations outside of submodule management.
|
||||
|
||||
metadata:
|
||||
category: git
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
---
|
||||
|
||||
## Concept
|
||||
|
||||
A submodule is a full Git repository embedded as a subdirectory inside a parent repository (the superproject). The superproject doesn't store the submodule's files — it stores a pointer to a specific commit SHA in the submodule's own history, and the two repos keep fully independent commit histories.
|
||||
|
||||
Two files govern a submodule, and they serve different audiences:
|
||||
|
||||
- **`.gitmodules`** — version-controlled, shared with collaborators. Defines each submodule's name, path, and canonical URL.
|
||||
- **`.git/config`** — local only, populated by `git submodule init`. This is where local URL overrides live (e.g. a private mirror) — they never propagate to other clones.
|
||||
|
||||
The submodule's own `.git` directory lives at `.git/modules/<name>/` in the superproject, linked to the submodule's working tree via a `.git` pointer file. After `git submodule update`, the working tree normally ends up in **detached HEAD state** — see Gotchas.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Detached HEAD by default.** `git submodule update` checks out a specific commit, not a branch. Work on a branch first, then update the pointer in the superproject. Commits made in detached state are invisible until pinned.
|
||||
- **Two pushes required, in order.** Always commit and push the submodule first, then update and push the superproject's pointer. The superproject only stores a commit SHA — if that SHA isn't reachable on the submodule's remote yet, `git submodule update` fails for anyone who pulls the superproject before the submodule push lands.
|
||||
- **`--recursive` is not default.** Most commands operate one level deep. Pass `--recursive` explicitly for nested submodules.
|
||||
- **`.git/modules/` persists after `git rm`.** Manual cleanup is needed: `rm -rf .git/modules/<name>/`.
|
||||
- **Detached HEAD detection.** Status prefix `+` means the checked-out commit differs from the superproject's recorded commit — normal after `update --remote`, but should be re-pinned before committing.
|
||||
- **Relative URLs resolve against the remote, not the filesystem.** A `../foo.git` entry in `.gitmodules` is relative to the superproject's default remote URL.
|
||||
- **Custom `update` commands are security-gated.** A `.gitmodules` entry of `update = !some-command` is never copied to `.git/config` by `git submodule init` — this stops a clone from silently executing arbitrary code.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Use `rtk git` for parent-repo operations.** Drop into the submodule directory only for submodule-specific git commands (committing/pushing inside the submodule itself) — mixing the two from the wrong working directory targets the wrong repo's history.
|
||||
- **Check for a dirty submodule before committing the parent pointer.** After adding or updating a submodule, run `git status` in both the parent and the submodule. A `-dirty` suffix means the submodule has uncommitted local changes; committing the parent pointer now would pin a state no one else can reproduce, since those changes exist only in the local working tree.
|
||||
|
||||
## Operations
|
||||
|
||||
- **Clone a repo that has submodules**: `rtk git clone --recurse-submodules <url>` (one step, Git 2.13+) or `rtk git clone <url>` followed by `rtk git submodule update --init --recursive`.
|
||||
- **Add a submodule**: `rtk git submodule add <url> <path>` (`-b <branch>` to track a branch instead of a pinned commit, `--depth 1` for a shallow clone, `-f` to force past a gitignored path or name conflict, `--name <name>` when the logical name should differ from the path). Stages a `.gitmodules` entry and a gitlink — a commit is still required.
|
||||
- **Initialize**: `rtk git submodule init [<path>...]` copies submodule URLs from `.gitmodules` to `.git/config`. This is the point at which local URL overrides can be edited before fetching. Does not clone — use `update` (or `update --init` to run both in one step).
|
||||
- **Update (clone + checkout)**: `rtk git submodule update --init --recursive` is the common case — checks out the recorded commit in detached HEAD. Add `--remote --merge` (or `--remote --rebase`) to track the branch tip instead, `--jobs <n>` for parallel clones, `-f` to discard local changes. Full flag table: `references/submodules.md`.
|
||||
- **Inspect status**: `rtk git submodule status --recursive` (add `--cached` to show SHAs in the superproject index instead of the working tree). Status prefixes: `-` not initialized, `+` diverged from the superproject's recorded commit, `U` merge conflict.
|
||||
- **Sync and rebind URLs**: `rtk git submodule sync --recursive` after an upstream URL rename propagates `.gitmodules` changes into `.git/config`. `rtk git submodule set-url <path> <url>` changes a URL directly; `rtk git submodule set-branch -b <branch> <path>` sets the tracking branch used by `update --remote`.
|
||||
- **Override a submodule URL locally (private mirror)**: local-only, doesn't propagate to collaborators, and gets overwritten by the next `sync`. Full steps: `references/submodules.md`.
|
||||
- **Run a command across all submodules**: `rtk git submodule foreach --recursive '<command>'`. Shell variables available inside `<command>` (`$name`, `$sm_path`, `$displaypath`, `$sha1`, `$toplevel`): `references/submodules.md`.
|
||||
- **Deinit (unregister without removing)**: `rtk git submodule deinit <path>` (`--all` for every submodule, `-f` if local modifications are present) clears the `.git/config` section and empties the working tree. **`deinit` is not removal** — the `.gitmodules` entry and the gitlink in the superproject's index are untouched.
|
||||
- **Safe removal** (destructive; confirm before executing) — full three-step sequence including the manual `.git/modules/` cleanup: `references/submodules.md`.
|
||||
- **Move an embedded `.git` into `.git/modules/`**: `rtk git submodule absorbgitdirs [<path>...]` — needed when a submodule was created or copied without going through `git submodule add`. Details: `references/submodules.md`.
|
||||
|
||||
## Configuration
|
||||
|
||||
`.gitmodules` (version-controlled, shared with collaborators):
|
||||
|
||||
| Key | Purpose |
|
||||
|---|---|
|
||||
| `submodule.<name>.path` | Working tree path |
|
||||
| `submodule.<name>.url` | Remote URL |
|
||||
| `submodule.<name>.branch` | Branch used by `update --remote` |
|
||||
| `submodule.<name>.update` | Default update procedure |
|
||||
| `submodule.<name>.shallow` | Recommend shallow clone |
|
||||
|
||||
`.git/config` (local only, populated by `init`):
|
||||
|
||||
| Key | Purpose |
|
||||
|---|---|
|
||||
| `submodule.<name>.url` | Local URL override |
|
||||
| `submodule.<name>.update` | Local procedure override |
|
||||
| `submodule.fetchJobs` | Default parallelism for `update --jobs` |
|
||||
| `submodule.recurse` | Auto-recurse submodule updates on `pull`/`push`/etc. |
|
||||
|
||||
```bash
|
||||
rtk git config submodule.recurse true # keep submodules pinned automatically after every pull
|
||||
```
|
||||
|
||||
## Agent output format
|
||||
|
||||
Return results as structured data:
|
||||
```
|
||||
operation: <clone|add|init|update|sync|set-url|set-branch|status|summary|absorbgitdirs|remove>
|
||||
status: <success|error|partial>
|
||||
message: <human-readable summary>
|
||||
details:
|
||||
- <submodule-path>: <state>
|
||||
conflicts: [<submodule-path>, ...] # if any
|
||||
next_step: <recovery action if applicable>
|
||||
```
|
||||
|
||||
For errors, include the git command output and recommend recovery (e.g., `git submodule deinit`, force-update, or URL override).
|
||||
15
plugins/git/skills/git-submodules/references/README.md
Normal file
15
plugins/git/skills/git-submodules/references/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
metadata:
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
---
|
||||
|
||||
# References
|
||||
|
||||
## submodules.md
|
||||
|
||||
Deep-dive reference: full `update` flag table, workflow patterns (clone, add, keep-pinned, update-to-latest, override URL), the complete safe-removal sequence, `absorbgitdirs`, and `foreach` shell variables. Load when SKILL.md's condensed Operations list isn't enough detail.
|
||||
|
||||
## sources.md
|
||||
|
||||
Research sources that informed this skill — provenance chain for git-scm-submodule-docs reference material.
|
||||
29
plugins/git/skills/git-submodules/references/sources.md
Normal file
29
plugins/git/skills/git-submodules/references/sources.md
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
topic: submodules
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
---
|
||||
|
||||
## git-scm-submodule-docs
|
||||
|
||||
**Description:** Official git-scm.com reference for `git submodule` — all subcommands, flags, configuration keys, and behaviour details.
|
||||
|
||||
**Source:** https://git-scm.com/docs/git-submodule
|
||||
|
||||
- **Research doc:** plugins/git/docs/research/docs/git/submodules.md (whole-document reference — the research doc is organized by descriptive prose headings such as "Concept Overview" and "Key Commands" rather than a heading matching this slug; this key covers the entire doc, not a single section)
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (all sections)
|
||||
- references/submodules.md (all sections)
|
||||
|
||||
---
|
||||
|
||||
Other source keys extracted during the git plugin research phase inform sibling skills in the git workflow suite, not this one:
|
||||
|
||||
- `context7-git-htmldocs` — git:branches, git:history, git:remotes
|
||||
- `git-scm-docs` — git:configuration
|
||||
- `git-scm-worktree-docs` — git:worktrees
|
||||
- `nvie-gitflow-post`, `atlassian-gitflow-tutorial`, `gitflow-cheatsheet` — git:branches
|
||||
- `conventional-commits-spec`, `commitlint-config-conventional` — git:commits
|
||||
- `git-scm-push-docs`, `git-scm-fetch-docs`, `git-scm-pull-docs`, `git-scm-remote-docs` — git:remotes
|
||||
- `git-scm-bisect-docs`, `git-scm-log-docs`, `git-scm-diff-docs` — git:history
|
||||
93
plugins/git/skills/git-submodules/references/submodules.md
Normal file
93
plugins/git/skills/git-submodules/references/submodules.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
topic: submodules
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
---
|
||||
|
||||
# Submodules — Deep Reference
|
||||
|
||||
## Update flag reference
|
||||
|
||||
| Flag | Meaning |
|
||||
|---|---|
|
||||
| `--init` | Run init first (avoids a separate step) |
|
||||
| `--remote` | Use the submodule's remote branch tip instead of the superproject's recorded commit |
|
||||
| `--checkout` | Detached HEAD at recorded commit (default) |
|
||||
| `--rebase` | Rebase current branch onto recorded commit |
|
||||
| `--merge` | Merge recorded commit into current branch |
|
||||
| `--recursive` | Operate on nested submodules |
|
||||
| `--jobs <n>` | Parallel clone (defaults to `submodule.fetchJobs`) |
|
||||
| `-N` / `--no-fetch` | Skip remote fetch |
|
||||
| `--depth <n>` | Shallow clone |
|
||||
| `--filter <spec>` | Partial clone filter |
|
||||
|
||||
## Workflow patterns
|
||||
|
||||
### Clone a repo with submodules
|
||||
```bash
|
||||
git clone --recurse-submodules <url> # Git 2.13+, one step
|
||||
# or
|
||||
git clone <url>
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
### Add a dependency as a submodule
|
||||
```bash
|
||||
git submodule add https://github.com/org/lib.git libs/lib
|
||||
git commit -m "chore: add lib as submodule"
|
||||
```
|
||||
|
||||
### Keep submodules pinned to the superproject's recorded commit
|
||||
```bash
|
||||
git submodule update --recursive # after every git pull
|
||||
git config submodule.recurse true # do this automatically on pull
|
||||
```
|
||||
|
||||
### Update submodules to the latest commit on their tracked branch
|
||||
```bash
|
||||
git submodule update --remote --merge --recursive
|
||||
git commit -am "chore: update submodules to latest"
|
||||
```
|
||||
|
||||
### Override a submodule URL locally (private mirror)
|
||||
```bash
|
||||
git submodule init
|
||||
# edit .git/config: submodule.<name>.url = <mirror-url>
|
||||
git submodule update
|
||||
```
|
||||
Local-only override (`.git/config`, not `.gitmodules`) — doesn't propagate to collaborators. Re-running `sync` overwrites it with the `.gitmodules` URL.
|
||||
|
||||
## Removal, in full
|
||||
|
||||
`deinit` alone does not remove a submodule — it only clears `.git/config` and empties the working tree. To fully remove:
|
||||
```bash
|
||||
git submodule deinit -f <path> # unregister from .git/config
|
||||
git rm <path> # remove .gitmodules entry + gitlink from index
|
||||
rm -rf .git/modules/<name>/ # stale git dir; not tracked by git, not auto-cleaned
|
||||
git commit -m "chore: remove <name> submodule"
|
||||
```
|
||||
`.git/modules/<name>/` persisting after `git rm` will block re-adding the same path until manually deleted.
|
||||
|
||||
## Relocate an embedded `.git` directory
|
||||
|
||||
```bash
|
||||
git submodule absorbgitdirs [<path>...]
|
||||
```
|
||||
Moves a submodule's own `.git` directory into the superproject's `.git/modules/<name>/`, linking it back with a `.git` pointer file. Needed when a submodule was created or copied without going through `git submodule add` (e.g. converting a plain nested repo into a proper submodule).
|
||||
|
||||
## `foreach` shell variables
|
||||
|
||||
Available inside the `<command>` argument to `git submodule foreach`:
|
||||
|
||||
| Variable | Meaning |
|
||||
|---|---|
|
||||
| `$name` | Logical submodule name |
|
||||
| `$sm_path` | Path relative to superproject root |
|
||||
| `$displaypath` | Path relative to current working directory |
|
||||
| `$sha1` | Recorded commit SHA |
|
||||
| `$toplevel` | Superproject's root path |
|
||||
|
||||
```bash
|
||||
git submodule foreach --recursive '<command>'
|
||||
git submodule foreach 'git pull origin main || :' # || : continues past failures
|
||||
```
|
||||
Reference in New Issue
Block a user