Archived
- On startup, after the local state is shown, fetch the superproject and every initialized submodule (all remotes, prune, at most 8 at once). Fetches never prompt; failures show git's message. --no-fetch skips it, f fetches again. - The header shows "fetching n/m", then the fetch age and failures; the detail pane shows each submodule's last fetch and fetch errors. - The git provider polls each repository's metadata (refs, HEAD, index, .gitmodules) every 2 s and reports changes. The app reloads only what changed, keeping old values, expansion and cursor; loads are single-flight with coalesced reruns. Refresh is driven by the repositories, so a fetch in another shell updates the view like ours. - r reloads everything (worktree edits are not watched). - Docs: F50-F53, N1/N8 rewritten, D18-D20 (D12 superseded). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
Requirements
Problem
In repositories with many submodules, git submodule status shows pinned
commit hashes. It doesn't answer the questions users actually have:
- Which branch is this submodule on, and is the pin current?
- Which submodules need my attention, and which are fine?
- Is anything dangerous, e.g. a pin that other people can't fetch?
Goals
- Show only submodules (not files), recursively nested, as a tree.
- Describe pins as ref + distance instead of a commit hash.
- Let problems stand out and keep healthy submodules quiet.
- Work comfortably with dozens to hundreds of submodules.
Functional requirements
Tree
- F1 Show all submodules of the superproject, including nested submodules of submodules, at any depth.
- F2 Group submodules by the directory of their path relative to the
parent repository. A directory with submodules is shown as a non-selectable
header line (e.g.
src/,modules/). Submodules at the repository root have no header. - F3 Nested submodules are shown under their parent submodule. A
directory header inside a submodule (e.g.
modules/) means the nested submodule lives in that subdirectory of the parent. - F4 On startup only the first level is shown; every submodule with nested submodules is collapsed.
- F5 A collapsed submodule shows the number of its direct children,
e.g.
[2]. - F6 A collapsed submodule shows the number of issues hidden in all
its descendants (
·2), colored by the most severe hidden issue. - F7 Expansion state of descendants is remembered when a parent is collapsed and restored when it is expanded again (except after "collapse all", which resets it).
State per submodule
- F10 Each submodule shows at most one state word: the most severe
issue, plus
+nif there are more. Submodules without issues show no word. See state-model.md for the full rules. - F11 Each submodule shows its pin as a ref (
origin/main, a tag, or a short SHA as a fallback) and the distance to that ref (↑n,↓n,↑n↓m). - F12 A pin that is not reachable from any remote ref ("unpushed") is the most prominent state.
- F13 States load asynchronously per submodule; a submodule shows a
spinner until its state is known. Loading errors are shown as
error.
Detail pane
- F20 Shows the selected submodule: full path, name, all issues in words, staged-pin and detached-HEAD notes.
- F21 Shows the resolved ref, how it was resolved, and three commits: Pinned, Checkout and Tip (SHA + subject). A checkout that differs from the pin is highlighted.
- F22 Lists the commits between pin and tip (SHA, subject, author, age) with a title stating ahead/behind/diverged.
- F23 Shows child count, issues below, and the remote URL.
- F24 For a submodule with uncommitted changes, previews the changed
files so the user can remember what they were doing: a flat list with a
colored letter per file (
Mmodified,Aadded,Dremoved,Rrenamed,?untracked,!conflict), line counts (+n −m) per file and in total, and how long ago each file was edited. Only a handful of files are shown; the rest is summarized as "n more" with their kinds. Staged and unstaged changes are combined.
Header and footer
- F30 The header shows the superproject path, its branch and ahead/behind, the number of submodules, a count per issue kind (most severe first), staged pins, how many are still loading, and the time since the last fetch.
- F31 The footer shows key hints;
?toggles the full help. It temporarily shows short messages (e.g. "not implemented").
Navigation
- F40 Keyboard navigation as specified in ux-guide.md.
- F41 Mouse: click a row to select it, click
▸/▾to toggle, scroll wheel moves the selection.
Fetch and refresh
- F50 On startup, after the local state is shown, the superproject and
every initialized submodule are fetched in the background (all remotes,
with prune).
--no-fetchturns this off. - F51 While fetching, the header shows progress (
fetching 12/174) instead of the fetch age; afterwards the age and the number of failed fetches. The detail pane shows each submodule's last fetch and, if it failed, git's message. - F52 The view follows changes in the repositories, no matter who made
them: a fetch, commit, checkout or
git addin another shell shows up within about two seconds. Refreshing is driven by the repositories, not by the application's own fetch. - F53
ffetches again;rreloads everything (e.g. after editing files, which is not watched).
Actions (planned, not implemented)
| Key | Action |
|---|---|
u |
Check out the pinned commit (git submodule update) |
b |
Bump the pin to the tip of its ref |
/ |
Filter by name/path |
! |
Show only submodules with issues |
Usage
submarine [dir] # the repository containing dir (default: current directory)
submarine --mock # built-in mock data
submarine --no-fetch [dir] # no background fetch on startup
Non-functional requirements
- N1 Startup must not block on the network. The tool shows the local state at once and fetches in the background (F50).
- N2 Loading many submodules must not freeze the UI (async, per submodule).
- N3 Colors follow the user's terminal theme (ANSI 16 colors); the UI works on dark and light backgrounds.
- N4 Meaning never depends on color alone: every state has a word.
- N5 Works without a Nerd Font.
SUBMARINE_ASCII=1replaces the few remaining Unicode symbols with ASCII. - N6 Works in narrow terminals (detail pane hides below 90 columns).
- N7 The UI is independent of the data source: the mock and the git provider are interchangeable without UI changes.
- N8 The git provider only uses the network in
Fetch, and never prompts (no password, passphrase or host-key questions; those fetches fail with git's message). It uses thegitcommand line, so the user's git configuration applies. Apart from fetching, it is read-only.