Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
submarine
A terminal UI for git repositories with many submodules. See what needs your attention. Ignore the rest.
git submodule status gives you a wall of commit hashes. submarine answers
the questions you actually have:
- Which branch is this submodule on, and is the pin current?
- Which submodules need me, and which are fine?
- Is anything dangerous, like a pin nobody else can fetch?
Why you might like it
- Only submodules, as a tree. Nested submodules at any depth, grouped by directory, collapsed until you open them.
- Branch plus distance, not hashes.
origin/main ↓2says more thanb7c8d9e. A pin on a feature branch shows that branch. - Problems are loud, healthy is quiet. Submodules without issues are
muted
in sync. A collapsed parent counts the problems hidden below it (·1). - Words, not symbols. Every state is a short word (
unpushed,conflict,missing,off pin,changed), so nothing depends on color alone. - Live. Fetches in the background on startup and follows changes you make in other shells within about two seconds.
- Built for dozens to hundreds of submodules. Each status loads asynchronously, so the UI never freezes.
Install
curl -fsSL https://git.simon-franken.de/simonfranken/submarine/raw/branch/main/install.sh | sh
Installs submarine and the alias sub (linux/macOS, amd64/arm64) to
~/.local/bin. Update later with submarine update.
Try it
submarine # the repository in the current directory
submarine ~/code/project # any directory inside a repository
submarine --no-fetch # skip the background fetch
submarine --mock # built-in sample data, no repository needed
Examples
Find what needs attention
Problems stand out: unpushed in red, off pin and changed in yellow,
everything else muted. Select a submodule to see the details on the right:
every issue in words, the resolved ref and why, the pinned, checked-out and
tip commits, and a preview of uncommitted changes.
src/ │ src/
core off pin origin/main │ net
▸ net [2] unpushed origin/main ↑1│
ui in sync origin/main │ unpushed pin not pushed to any remote
│
│ Ref origin/main ↑1
│ via checked out branch
│ Pinned b7c8d9e Hotfix null pointer
│ Checkout b7c8d9e Hotfix null pointer
│ Tip 6f5e4d3 Release 2.1.0
Jump to a submodule with /
Press / and type. Only matching submodules (and the parents that lead to
them) stay. Your selection moves to the next match if it was filtered out.
libs/
▾ log in sync origin/main
modules/
nested changed origin/main
/ nest enter navigate • esc close
enter keeps the filter and gives you the normal keys back, esc removes
it and leaves your selection where it is.
Copy a path
Select a submodule and press c. Its absolute directory lands in your
clipboard, ready for cd <paste>. It works over SSH too (OSC 52; in tmux,
set -g set-clipboard on).
Fetch and reload
f fetches all repositories again, r reloads everything after you edited
files.
Keys
| Key | Action |
|---|---|
↑ ↓ / j k |
Move |
← → / h l |
Fold / unfold, parent / first child |
H L / ⇧← ⇧→ |
Collapse / expand all |
space |
Toggle the selected submodule |
home end / g G, pgup pgdn |
Jump, page |
/ |
Filter |
c |
Copy path |
f / r |
Fetch / reload |
? |
Full help |
q |
Quit |
The mouse works too: click to select, click ▸ to toggle, wheel to move.
Status
A prototype. Browsing is complete; the actions u (check out the pin),
b (bump the pin to the tip) and ! (problems only) are planned.
Documentation
Requirements, state rules, UX guide, architecture and the decision log are in docs/.
Development
go run ./cmd/submarine --mock # run on mock data
scripts/make-fixture.sh DIR # build a test superproject with every state
go vet ./... && go test ./...
