TUI Navigation
Coco's interactive TUI is keyboard-driven and chord-based. Whether you launch it as coco ui or coco log -i, every git surface — history, working tree, diffs, commit compose, branches, tags, stash — is reachable from any other surface through a unified navigation model.
This page is the source of truth for that model. The companion pages Coco UI and Interactive Log TUI cover surface-specific actions and command-line flags; everything navigation-related lives here.
Mental model
- Views are top-level destinations. There are eighteen:
history,status,diff,compose,branches,tags,stash,worktrees,pull-request,pull-request-triage,issues,conflicts,reflog,bisect,submodules,remotes,blame, andchangelog. - Chords jump you between views. They start with
g, followed by a single key (g h,g s,g d,g c,g b,g t,g z,g w,g p,g P,g i,g x,g r,g B,g M,g n). Chords replace the top of the navigation stack rather than pushing onto it, so jumping laterally between top-level views never grows the stack (0.81.0). Pressgfor a live which-key menu of these, org?for the single-key actions in the view you're already in (see View-keys strip). - The navigation stack remembers how you drilled in. Pressing
<orEscpops back one level. Because chords replace rather than push,g s → g b → g z → g dis still just one level deep —Escfrom there returns you to wherever you were before the first chord, not back throughgz → gb → gs. Contextual drill-ins (Enteron a commit,e/cinto compose — see Contextual transitions) still push, sohistory → Enter → diff → e → compose → Escunwinds one hop at a time: compose → diff → history. - The repo stack (#931) nests the navigation stack one level deeper. Drilling into a submodule pushes a frame; every view inside that frame is scoped to the submodule's working directory, as if you had launched
coco uifrom there. Esc /<pops the frame when you're at the root of its view stack — and the header shows acoco › vendor/lib ← escbreadcrumb so the level you're on is always visible. - Selection state survives navigation. The selected commit, selected branch, selected stash, and current compose draft are all preserved when you jump away and come back.
- The chrome adapts. A
›-separated breadcrumb in the header reflects the navigation stack; the footer's right-side global slot stays the same across views; help and palette read the active view to show the right scope.
Views and chords
| View | Chord | What it shows |
|---|---|---|
| History | g h | Commit graph/list with refs and metadata. gh also clears the navigation stack. |
| Status | g s | Working-tree files (staged/unstaged/untracked) with stage/unstage/revert. |
| Diff | g d | Hunks of the currently-selected commit (from history) or worktree file (from status). |
| Compose | g c | Full-screen commit draft editor with summary/body cursors, AI draft, hook feedback. |
| Branches | g b | Local branches with divergence info; checkout/delete/create-PR via workflow keys; r rebases the current branch onto the selected ref (#0.71 — non-interactive, confirms, guards self-rebase / detached HEAD). |
| Tags | g t | Tag list. |
| Stash | g z | Stash list as an aligned table (ref · age · branch · files · message) with a column header; a/A apply, p pop, R rename, b branch-from-stash, X drop, u undo-drop. (g s is reserved for status, hence g z. gZ creates a stash from any view.) |
| Worktrees | g w | Linked worktrees with current/dirty markers; remove via W. |
| Pull request | g p | Dedicated PR action panel for the current branch (header, checks, reviews, body) with m merge / x close / a approve / R request changes / c comment / O open in browser. |
| PR triage | g P | Multi-PR triage list with filter cycling and per-row actions. Capital P disambiguates from g p (single, current-branch panel). See Issue & PR Triage. |
| Issues | g i | Issue triage list with filter cycling and per-row actions: comment, label, assign, close, reopen. See Issue & PR Triage. |
| Conflicts | g x | Conflict resolution helper view, available during merge / rebase / cherry-pick / revert. Per-row keys s stage / u theirs / U ours / o edit / C continue. |
| Reflog | g r | Chronological recovery log — every HEAD movement (commit / checkout / merge / reset / etc.) with relative time, action, hash, and message. Enter drills into the diff for the entry's hash; c checks out the entry (detaches HEAD), Z resets HEAD to it (soft / mixed / hard prompt), B creates a branch at it — reset and branch reuse the history-view workflows. |
| Bisect | g B | Bisect workflow surface (#784). Capital B disambiguates from g b (branches). Shows the current candidate, the parsed decision log, and the four action keys: g good / b bad / s skip / x reset. |
| Submodules | g M | Registered submodules (#932) with name, pinned sha, tracking branch, and clean/modified/uninitialized/conflicted state. Enter drills into the cursored submodule. i init / u update (--init) / s sync the cursored submodule (#0.71). Capital M disambiguates from g m (compare-base mark). |
| Remotes | g n | Configured remotes with their fetch / push URLs (#0.71). a add (prompts for name url), e set-url for the cursored remote, x remove*, p prune*, y yank URL. (* remove / prune confirm first; n for network, since g r is reflog.) |
| Blame | b (from status) | Per-file git blame drill-down (#0.71). Press b on a file in the status view; shows a dimmed <shorthash> <author> gutter per line, fetched on demand and windowed so large files stay responsive. j/k move, Esc back. |
| Changelog | L | Full-screen AI-generated changelog for the current branch (#914). Reached via L from history or branches rather than a g-prefixed chord. Per-branch cache; r regenerates, y yanks, E opens in $EDITOR, c kicks off create-PR seeded with the content. |
g g is a separate chord that jumps to the first commit in the active history list — it pre-dates the view chords. g H (uppercase) on a diff view applies the cursored hunk to the index (companion to bare H which applies to the worktree). g T (uppercase) on the history view opens a new-tag prompt rooted at the cursored commit.
One-keystroke workflows (not view-jumps)
A few uppercase keys kick off workflows that span multiple views. These aren't chords; press them once and the workflow takes over.
| Key | Where | Action |
|---|---|---|
C | history / branches | Create a pull request for the current branch. Seeds the title + body from a generated changelog and opens a multi-line prompt for review. |
L | history / branches | Generate a changelog for the current branch in a full-screen surface. Per-branch cache; r regenerates, y yanks to clipboard, E opens in $EDITOR, c kicks off create-PR seeded with this content. |
S | compose | Split the staged set into multiple commits. Opens an overlay with the LLM-generated plan. y apply / r regenerate / < cancel. |
E | compose / status / diff | Open the current commit draft in $EDITOR. Round-trips through a temp file; on save the content is re-split into summary + body. Companion to lowercase e (inline edit). |
I | compose / status / diff | Generate an AI commit draft from the staged set. Press Esc while the draft is loading to cancel; press R afterwards to accept a pending draft when one is staged over user-typed content. See Coco UI → Compose surface for the streaming preview and pending-draft details. |
B | history (on a commit) | Create a branch rooted at the cursored commit (git switch -c). |
+ | branches view / sidebar branches tab | Create a branch from HEAD (git switch -c). |
z | any view, as a fallback (0.81.0) | Global undo — reflog-powered inverse of the last git operation. Only fires when nothing more specific claims z first (see note below). |
zis context-routed, not a second binding.zalready means "revert the selected file or hunk" on the status and diff views (see Coco UI → Generic) — that behavior is unchanged. Global undo is whatzfalls through to everywhere else, or on status/diff when nothing is selected to revert. It inspects the reflog tip, describes the last operation in the confirm panel (e.g. "Undo commit (fix: the thing)"), and onyruns the inverse: acheckoutentry switches back to the previous branch; everything else (commit, reset, rebase, merge, cherry-pick, revert, pull) runsgit reset --hard HEAD@{1}. Refuses to run while another operation (merge/rebase/etc.) is already in progress. This is lazygit'szundo, generalized from Coco's earlier stash-only undo-drop (uon the stash view, still separate and unaffected).
Going back
| Key | Action |
|---|---|
< | Pop the navigation stack — and once that's drained inside a nested submodule frame (#931), pop the repo frame itself |
Esc | Same as < when in a normal view; also closes filter/help/palette/confirmation modes |
The stack always has at least one frame (the root view), so pressing < from the root is a no-op rather than an exit. Use q or Ctrl+C to quit.
Contextual transitions
Some keys perform navigation based on what's selected:
| Trigger | Effect |
|---|---|
Enter on a commit (history view) | Push diff scoped to that commit. The diff view inherits the selection so < returns to the same row. |
Enter on a file (status view) | Push diff scoped to that file. < returns to status. |
Enter on a reflog row | Push diff scoped to that entry's hash (#781). |
Enter on a submodule row (submodules view, g M) | Drill into the submodule — every view re-scopes to the submodule's working directory (#931). |
Enter on a submodule file (commit diff view) | Drill into the submodule with the diff's (oldPin, newPin) range captured as the entry hint (#931). |
e from status or diff | Push compose and start editing. From inside compose, e toggles edit mode without re-pushing. |
c from status or diff | Push compose and run createManualCommit — the result (success or hook output) lands in compose so you can see it. |
Cross-view workflows
Some flows span multiple views — you mark a state on one view and then act on it from a different one. The footer hints adapt to the flow state so the override is always discoverable.
Compare two refs (#779)
Diff any two refs (branches, tags, or commits) without leaving the workstation:
| Step | Trigger | Effect |
|---|---|---|
| 1 | m on a row in branches / tags / history | Mark the cursored ref as the compare base. Status banner sticks: "Compare base: <label> — press enter on another ref to diff." |
| 2 | m on the same ref again | Toggle the base off (no Enter needed). |
| 3 | Navigate to a second ref on any of branches / tags / history | (no key required — just move) |
| 4 | Enter on that second ref | Push the diff view in compare mode, showing git diff <base>..<head>. |
| 5 | < / Esc | Pop the diff. The compare base clears automatically when the diff is popped. |
The compare diff is read-only — no per-file cherry-pick or hunk-apply across arbitrary refs (those don't have a sensible mutate-from-here flow). Just scroll with j/k, toggle split mode with d, and back out with <.
While a base is set, the footer adapts on every compare-flow target view:
Branches: ↑/↓ branches · enter compare · m clear · esc back
Tags: ↑/↓ tags · enter compare · m clear · esc back
History: ↑/↓ move · enter compare · m clear · esc backOutside the compare flow, m is unbound on those views except the dedicated PR view (where it triggers merge).
Multi-select and batch operations (#1361)
Batch-act on several branches, stashes, or a run of commits in one confirm instead of repeating a single-item action N times. (0.81.0)
| Key | Action |
|---|---|
x | Toggle a mark on the cursored item and auto-advance to the next row. |
v | Anchor a range at the cursor; j/k extend it. v again clears it. |
Esc | Two-stage: first clears the range anchor (if active), second clears marks. |
Marks and a range anchor are mutually exclusive per view — starting a range drops any marks, and marking an item drops an active range. They're alternatives (build a set with x, or define a span with v), not layers.
Where it applies:
| View | Marks / range | Batch action |
|---|---|---|
Branches (g b) | x marks or v range | D batch-deletes. Confirm panel pluralizes exactly ("3 branches: a, b, c" / "+N more"). |
Stash (g z) | x marks or v range | X batch-drops, in descending stash@{N} order regardless of mark order — dropping stash@{0} renumbers every later entry, so order matters for correctness; Coco handles it for you. |
History (g h) | v range only — no marks. A contiguous run is what "select several commits" naturally means. | c cherry-picks the whole span as one git cherry-pick oldest^..newest, instead of a per-commit loop. |
On a partial batch failure, the attempted set freezes into marks so a retry (once you've fixed whatever refused) targets exactly what failed, not the whole batch again.
vis also the narrow-terminal sidebar peek (see Footer) — an unrelated binding scoped to terminals under ~100 columns. On branches / stash / history at normal width,vmeans range-anchor; the two never collide because the peek only engages when the layout has actually folded to a single pane.
Bisect (#784)
Bisect support pairs the g B view with a top-bar BISECTING badge so you can't lose the workflow. The TUI picks up an active bisect on its next refresh — start it from your shell with git bisect start <bad-ref> <good-ref> and re-open coco ui.
| Trigger | Effect |
|---|---|
g B | Push the bisect view. Shows current candidate (HEAD), parsed decision log, and the action keys. The view is reachable even when bisect is inactive — the empty-state hint tells you how to start one. |
g (on the bisect view) | Mark the current candidate as good (bug not yet present). Advances to the next candidate. |
b (on the bisect view) | Mark the current candidate as bad (bug present). Advances to the next candidate. |
s (on the bisect view) | Skip the current candidate (e.g. it doesn't build). Advances to the next candidate. |
x (on the bisect view) | Reset the bisect — discards in-progress state. Routed through the y-confirm path. |
Inside the bisect view, g and b bypass the chord prefix — pressing g marks good rather than entering chord mode. The path back out is < / Esc (never a chord). Outside the view, g/b/s/x keep their existing semantics.
The status line surfaces git's own "Bisecting: N revisions left to test after this (roughly K steps)" line after each decision so you always know how far you have to go.
Submodule drill-in (#931)
Drilling into a submodule pushes a repo frame that re-scopes every view — history, branches, status, diff, even the inspector — to the submodule's working directory. It's the mental equivalent of running coco ui from inside the submodule, but without leaving the parent session.
| Trigger | Effect |
|---|---|
Enter on a submodule row (submodules view, g M) | Push a frame against that submodule. Lands on its history view. |
Enter on a submodule file in a commit diff | Push a frame with the diff's (oldPin, newPin) range captured. Useful for seeing what changed between the two pinned commits. |
Esc / < at the root of a frame's view stack | Pop the frame. Returns the user to the parent's exact view position (selected commit, filter, etc.). |
Esc / < deeper in a frame's view stack | Pop a view first (drains the frame's own view stack), then pop the frame on the next press. |
The header shows a breadcrumb whenever you're inside a frame:
coco › vendor/lib ← esc
Frames stack. Drilling further (a submodule of the submodule) produces coco › vendor/lib › vendor/lib/inner ← esc, and each Esc walks back one level.
Cached state survives the round trip — pop back to the parent and you land on the same row, with the same filter, with cached context (no refetch flicker).
Mutations (stage, commit, checkout, …) inside a nested frame run against the submodule's working tree, since the active frame's SimpleGit instance is bound to its workdir. Two known polish items are tracked as follow-ups to #931: per-frame sidebar tab / sort mode persistence (today these carry over root → submodule), and frame-tagging on in-flight refreshes (rare race where a parent refresh that's mid-await when a push fires writes to the submodule frame).
Command palette (:)
The palette is an interactive launcher, not a static reference. Press : to open it; type to filter, press Enter to run.
| Key | Action |
|---|---|
| Printable keys | Append to the fuzzy filter |
Backspace / Delete | Remove the last filter character |
Ctrl+U | Clear the filter |
↑ / ↓, Ctrl+P / Ctrl+N | Move the selection cursor (clamped to filtered count) |
Enter | Run the selected command (records as recent, then closes) |
Esc | Close without running |
The palette enumerates every keybinding plus every workflow action (commit, delete-branch, ai-commit-summary, etc.). Recently-used items float to the top when the filter is empty; once a query is set, relevance ranking takes over and recent ordering is ignored.
Behind the scenes, palette execution maps each command id to the same events the keystroke would dispatch — palette and keymap stay in sync.
Search (/)
/ opens filter mode in the active view:
- History: ranked fuzzy matching across hash, date, author, message, and refs. Four prefixes re-run
git logserver-side instead of filtering the loaded window client-side:path:<spec>— commits touching a path (e.g.path:src/foo).author:<name>— commits by a given author (e.g.author:alice).S:<token>— pickaxe (0.81.0): commits that changed the occurrence count of a literal string (git log -S).G:<regex>— grep-diff (0.81.0): commits whose patch matches a regex (git log -G).
- Branches: substring match on branch names and upstreams.
- Tags: substring match on tag names and subjects.
- Stash: substring match on stash refs and messages.
While filtering, the active view's header shows N/M totals plus the filter text (5/12 local | filter: feat). Ctrl+U clears, Esc or Enter exits filter mode. The four server-side history prefixes re-fetch on Enter; the footer's active-filter indicator shows exactly what ran (e.g. -Sfoo, -Gfoo.*bar) so you can tell a server-side filter from a plain client-side one.
In other views (diff, compose, status), / opens filter mode but the surface doesn't currently apply it — typing closes the filter without effect. That's a polish opportunity for a follow-up; track it via the wiki/issue tracker.
Help overlay (?)
Help is grouped into two sections so the right scope is always obvious:
- Global — bindings that work from any view or focus (
?,:,q,r, focus nav, workflow actions, the navigation chords). - This view (
<active>) — bindings filtered to what makes sense in the current view + focus, with the active view named in the section title so you always know which scope applies.
Esc or ? closes the overlay.
View-keys strip (g?)
The g which-key overlay solves discovery for the chords (g h, g s, …). g? is its counterpart for the single keys — the per-view overloads where the same letter means different things in different views (c cherry-picks on history but cherry-picks a file in a commit diff; R reverts on history; m marks a compare base; [/] jump hunks or sidebar tabs depending on focus).
Press g? in any view to pop a compact strip listing exactly the single-key actions available right there, with their labels. It's sourced live from the same binding table the ? help uses, filtered to the active view + focus — so as you move between views the list changes with you, and it can never drift out of sync with what the keys actually do.
g?— open the strip for the current view.?— step up from the strip to the full categorized help (progressive disclosure).Esc— close.
It changes nothing about what any key does; it's a pure discoverability surface. Bare ? still opens the full help directly, so existing muscle memory is untouched. The strip is also reachable from the command palette (:) as keys.
Footer
The footer has two slots that don't overlap:
- Contextual (left, dimmed) — what changes by mode/view/focus, like
↑/↓ files · enter diff · space stage · z revert · e/c composein status. - Global (right edge, dimmed) — persistent affordances anchored to the right:
g jump · < back · ? help · : cmds · q quit.
In special modes (filter / help open / palette open), the global slot trims down (q quit always present) since : and ? mean close in those contexts.
A few keys are context-routed across surfaces:
[/]— diff view: jump previous/next hunk or file. Sidebar focused: cycle sidebar tabs. Inspector focused (on short terminals where the inspector is tabbed): cycle inspector tabs. Each context owns its meaning of the key; the footer hints surface which one applies.←/→— sidebar focused: switch between Status / Branches / Tags / Stashes / Worktrees tabs. Vertical axis (↑/↓) navigates items within the active tab.v— narrow / single-pane terminals only (under ~100 cols): momentary sidebar peek from the main or inspector pane.vagain orEscsnaps you back to where you were. A no-op in the full three-pane layout where everything's already visible.
Header breadcrumb
The header shows where you are in the navigation stack as a ›-separated trail:
| Stack | Breadcrumb |
|---|---|
[history] | (empty — no breadcrumb shown at root) |
[history, diff] | history › diff |
[status, diff] | status › diff |
[history, status, diff] | history › status › diff |
The breadcrumb is purely informational — there's no clickable navigation through it (the TUI is keyboard-only). Use < / Esc to walk it back.
Themes and accessibility
- 108 built-in color themes / 109 selectable presets (29 light) —
default,monochrome,catppuccin,gruvbox,dracula,nord,tokyo-night, and many more (full gallery). Set via--theme <preset>orlogTui.theme.presetin.coco.config.json.NO_COLOR=1honored;monochromefor grayscale. The active/selected row renders readably on every theme (light + dark, truecolor + downgraded). NO_COLOR=1is honored end-to-end. Borders fall back to the terminal default and color emphasis is dropped without changing layout.- The chrome uses a small set of unicode glyphs (
›,↑/↓,·); layout is ASCII-only so a missing glyph never breaks columns. - Empty / loading copy is unified across views and points users at the next sensible action — no blank screens.
- The TUI is keyboard-only by design. Every action is reachable from the keymap or
:palette. Mouse input is not consumed.
What's new since v0.34.0
The shell architecture landed in v0.34.0 (TUI shell epic, #747). The releases since have layered on a navigable, action-rich workstation. Highlights worth knowing if you came from an earlier version:
v0.81.0 — global undo, multi-select, pickaxe search, confirmation cleanup
- Global undo.
zfalls through to a reflog-powered undo of the last git operation when nothing more specific claims it — see One-keystroke workflows. - Multi-select & batch operations. Mark or range-select branches, stashes, and commit spans and act on all of them in one confirm — see Multi-select and batch operations.
- Pickaxe & grep-diff search. New
S:<token>andG:<regex>filter prefixes joinpath:/author:for server-side commit-content search — see the Search (/) section below. yis now reserved exclusively for confirming destructive actions, everywhere. The one exception — the worktree-conflict prompt's "switch to that worktree" option — moved tos.- Two-stage
Escnow protects every multi-line input prompt (PR comments, review bodies), matching the filter/palette/theme-picker contract: firstEscclears typed text, secondEsccloses. g-chords replace the top of the navigation stack instead of pushing — see the updated Mental model above.Escafter any run of chords always returns exactly one level.- Status-line navigation echoes (e.g. "jumped to ...") now clear on your next keystroke instead of persisting until something else overwrites them.
v0.62.x — workstation readability tweaks
- Worktree-aware checkout conflicts. Checking out a branch that's already checked out in another worktree no longer dead-ends on git's raw
already checked out at <path>. Coco names the branch + worktree and offerss(switch to that worktree — opens it as a nested repo frame),r(remove that worktree and check out here — refused/warned if it's dirty), orx(remove the worktree and delete the branch). (0.62.4; the switch key moved fromytosin 0.81.0 — see below — soymeans "confirm the dangerous option" everywhere, with no exceptions) - Stash view is an aligned table. The stash list is now a real table — a dim column header over aligned columns (
ref · age · branch · files · message), metadata dim, the message filling the remainder and tail-truncated, numeric columns right-aligned. Rows fit the panel exactly (no wrapping), and on narrow terminals the columns the inspector preview already shows are shed in priority order (branch → age → file count) before the message is squeezed. (0.62.3) - The checked-out branch is highlighted in green. Its name renders in the theme's
successcolour (matching the green*HEAD marker) in both the Branches view and the sidebar Branches tab; the colour yields to the selection highlight on the focused row, andNO_COLORthemes fall back to the*glyph. (0.62.3) - Inline spinner on branch checkout. Checking out a branch now shows the same per-row pending spinner as a delete, instead of blanking the list behind a "loading branches…" placeholder. Deleting a branch that's checked out in another worktree now explains which worktree to free up rather than dead-ending on git's raw error. (0.62.2)
- History opens on the full multi-ref graph again on a bare
coco. A barecocolaunch was dropping the--alldefault and booting the history view in compact mode (fewer commits, branches-ahead hidden, a graph that could loop back to the initial commit); it now opens on the all-refs graph as intended. (0.62.1)
v0.60.0 — stash workflow, narrow terminals, honest chrome
- Stash workflow overhaul. The stash list went from
ref + messageto richer rows:stash@{0} on main · 3 files · 2w <message>(origin branch · file count · relative age; refs are the compactstash@{N}form again). New keys on the stash view / sidebar tab:Rrename a stash ·bcreate a branch from it (git stash branch) ·Aapply restoring the staged/unstaged split (git stash apply --index, vs plaina) ·uundo the last drop.gZstashes all changes from any view (including status / diff / compose, where bareSis the commit-split key) — mnemonic pair withgz(jump to the stash view). Submitting an empty message makes a quick WIP stash. The:palette adds Stash staged only (--staged) and Stash keeping index (--keep-index).
- Narrow terminals are first-class. Below 100 columns the three-pane layout folds to a single full-width pane (the old 8-cell icon rails are retired).
Tab/Shift+Tabcycles which pane is visible (sidebar → main → inspector); the footer prepends atab: [sidebar] main inspectorswitcher.vmomentarily peeks the sidebar from the main/inspector pane —vorEscsnaps you straight back (a no-op in the full three-pane layout). - Honest, trimmed chrome. The commit-diff footer was relabeled
j/k lines · [/] hunk(the keys did the opposite of what it said), and each footer row was trimmed to its highest-value actions (the rest live in?). The header breadcrumb dropped its trailing← <hint (it's pure location now), and the⊘ no PRchip is gone — the PR chip shows only when a PR actually exists.
v0.40.0 — unified three-tier navigation
Wherever a list of items lives inside a named group, the group's title is now a first-class cursor target with its own canonical action. The same mental model carries across all four surfaces it applies to:
- Sidebar.
↑at items index 0 promotes the cursor onto the active tab's header (Branches / Tags / Stashes / Worktrees).←/→scans neighboring tab headers;Enteron the header drills into the dedicated view. - Status view. Files render under
▾ Staged (n)/▾ Unstaged (n)/▾ Untracked (n).←/→jumps between groups;↑at a group's first file promotes to the header;Enteron a header fires the batch action (Stage all unstaged,Unstage all staged,Stage all untrackedwith y-confirm). - Inspector Actions.
[/]toggles to the Actions tab;↑/↓moves the cursor;Enterfires the cursored action (cherry-pick, revert, reset, yank, open in browser). - Stash diffs.
diff --gitrows render as compact▾ <path>headers; the file the cursor is scrolled inside gets selection styling so the active context is always visible.
Header focus persists across ← / → switches in the sidebar so the user can scan tab → tab → drill in one fluid motion. All four surfaces use the same selection styling for their headers, so the visual cue is the same wherever you are.
v0.39.0 — inspector and cross-list cursor sync
- The right-hand inspector dropped its duplicative repo / branch / status trailer and added an
Actions:section listing the keystrokes available on the cursored entity. Destructive actions render with a[!]marker. - Inspector at rest is narrow (~22% of width); focusing it via
tabexpands to ~40% so the metadata, body preview, and action panel get the room they need. Mirrors the existing sidebar focus-expand pattern. - On short terminals (rows < 28), the inspector collapses into a tabbed
[Inspector] Actionslayout.[/]while the inspector is focused cycles tabs. - Cursoring a branch in the sidebar / branches view auto-jumps the history panel cursor to that branch's tip commit (debounced 150ms). Same for tags. A
Synced history to <ref>status confirms the jump even when the dedicated branches view obscures the history graph. - Current branch always pins to position 0 of the branches list regardless of sort mode. After a checkout, the cursor snaps back to row 0 so it lands on the just-checked-out branch.
- New keys on the history view:
Bcreate branch from cursored commit,gTcreate tag from cursored commit. The prompt itself is the affirmative gate. - Header label is
coco(wascoco ui).
v0.38.0 — action surface
- Pull-request panel via
g p: header / checks / reviews / body withm/x/a/R/c/Oaction keys. - History-view mutations:
Rrevert,Zreset (soft / mixed / hard mode prompt),iinteractive rebase. All routed through y-confirm or mode prompt. don a commit-diff or stash-diff toggles between unified and side-by-side rendering. Persists per-repo. Falls back to unified on terminals narrower than 120 cols.Hon a diff view applies the cursored hunk to the worktree (git apply).gHapplies to the index (git apply --cached).- Higher-fidelity commit graph: pattern junctions (
├╮/├╯), per-lane coloring, distinct merge / HEAD glyphs (◆/◉). - In-sidebar selection: when sidebar is focused,
←/→switch tabs and↑/↓(orj/k) navigate items. Per-entity ops (Enter checkout /aapply /Ddelete / etc.) fire from the sidebar without drilling into the dedicated view. - Multi-line input prompt for PR comments + review bodies. Enter inserts a newline;
Ctrl+Dsubmits. Single-line prompts (branch names, merge strategies) keep Enter as submit. - Branches list polish: dropped "even with X" noise, added relative timestamps (
today/Nd/Nw), four-state remote indicator (*/◌/≡/↕). - Stash diff header surfaces
@{N} <message> on <branch>instead of the raw timestamp ref.
v0.37.0 — quick-win affordances
y/Yyank the cursored identifier (commit hash, branch, tag, stash ref, file path) to the system clipboard from every promoted view.1/2/3on the status view toggle staged / unstaged / untracked visibility./path:src/fooand/author:alicere-rungit logwith the matching flags so commits touching a path or by a given author show up without dropping to a shell.
v0.34.0 — chord prefix
gis now a chord prefix. Pressinggalone no longer toggles the graph immediately — it waits for the second key. The graph toggle moved to\. PreviouslygdidtoggleGraphas a side effect of starting aggchord, which caused a brief flicker on everyg-prefixed sequence.
If you had muscle memory for g, you can either retrain to \ or use : and search for "graph" to invoke it from the palette.
Quick reference card
1Navigation Within a view Modes
2 g h history j/k, ↑/↓ move ? help (toggles)
3 g s status gg / G top / bottom : palette (toggles)
4 g d diff n / N next / prev / search (toggles)
5 g c compose Tab focus next Esc close mode / back
6 g b branches ←/→ sidebar tab < back (nav stack)
7 g t tags [/] sidebar tab / Quit
8 g z stash inspector tab q, Ctrl+C
9 g w worktrees 1-5 sidebar jump
10 g p pull request \ toggle graph
11 g x conflicts r refresh
12 g r reflog d unified ↔ split (diff view)
13 g B bisect m mark compare base (branches/tags/history)
14 g/b/s/x bisect: good/bad/skip/reset (bisect view)
15
16History view ops Diff view ops PR view ops
17 c cherry-pick H apply hunk m merge
18 R revert gH apply hunk to x close
19 Z reset (mode prompt) index a approve
20 i interactive rebase [/] file/hunk nav R request changes
21 B create branch here space stage/unstage c comment
22 gT create tag here z revert O open in browser
23 y/Y yank hash c cherry-pick file
24 O open in browserFor surface-specific actions (staging, hunks, commit compose, workflow keys like D/X/I), see the per-view sections in Coco UI.