Fetch in the background and follow changes in the repositories

- 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>
This commit is contained in:
Simon Franken
2026-10-21 16:15:22 +02:00
co-authored by Claude Opus 5.5
parent 19c6f17eb2
commit 27f0c0b5d2
27 changed files with 1097 additions and 90 deletions
+20 -6
View File
@@ -63,7 +63,8 @@ indent ▸ name [n] status ref delta
`detached HEAD on pin` as information
3. `Changes` (only with uncommitted changes), see
[Change preview](#change-preview)
4. `Ref` with distance and `via <rule>`
4. `Ref` with distance and `via <rule>`; `Fetched <age>` of the submodule;
`fetch failed: <git's message>` (yellow word) if the last fetch failed
5. `Pinned`, `Checkout`, `Tip`: SHA + subject; the checkout SHA is yellow if it
differs from the pin
6. "Pin is n commits behind/ahead of …" / "Pin and … have diverged": commit list
@@ -115,12 +116,23 @@ Changes 5 files · 2M 1A 1D 1R · +37 −12
- Untracked directories are shown as one entry (`tmp/`).
### Header
`path branch ↑↓ · n submodules · <count> <issue>… · n pin staged · n loading · fetched <age>`
`path branch ↑↓ · n submodules · <count> <issue>… · n pin staged · n loading · <fetch>`
Issue counts are ordered by severity (unpushed, conflict, missing, off pin,
changed), each in its level color. Zero counts are omitted. `<age>` is
`never` if the superproject has never been fetched; a detached superproject
shows `(detached)` as its branch.
changed), each in its level color. Zero counts are omitted. A detached
superproject shows `(detached)` as its branch.
`<fetch>` on the right:
| State | Shows |
|---|---|
| fetching | spinner + `fetching 12/174` (repositories done / total) |
| done | `fetched just now`, then the age (`fetched 5m ago`) |
| some failed | `fetched just now · 3 failed` (count in yellow) |
| never fetched | `fetched never` |
The age is the newer of the superproject's `FETCH_HEAD` and the end of the
application's own fetch.
## Colors
@@ -171,7 +183,9 @@ colors in components.
| `pgup`, `pgdn` | Move by one screen |
| `?` | Toggle full help |
| `q`, `ctrl+c` | Quit |
| `u`, `b`, `f`, `/`, `!` | Planned actions (see requirements) |
| `f` | Fetch all repositories (does nothing while a fetch runs) |
| `r` | Reload everything (e.g. after editing files) |
| `u`, `b`, `/`, `!` | Planned actions (see requirements) |
"First child" always means the first child **as displayed** (children are
grouped by directory).