// docs · v1.x

Commit graph — map

commitbrief map draws the commit DAG and highlights exactly which commits a filter selected, so you can check a filter before paying for a review. --branches switches to a branch topology summary. Deterministic, no provider call, always exits 0.

commitbrief map draws the commit graph — and, when a filter is active, shows exactly which commits it selected. It is deterministic: no provider call, no cache, no cost, and it always exits 0 on a successful render. A viewer, not a gate. New in v1.15.0 (ADR-0037).

Why it exists

The commit filters can select a non-contiguous set of commits from anywhere in the history. That is what makes them powerful, and also what makes them invisible — the only feedback was a count:

$ commitbrief dry-run --author alice --start-date 2026-06-01
Commits (matched): 12

Which twelve? For a filter whose entire job is deciding what gets reviewed, “trust me, twelve” is weak feedback, and a wrong filter quietly reviews the wrong code. map shows them in place, against the commits they were interleaved with.

Usage

commitbrief map                            # the DAG, newest first
commitbrief map --max-commits 50
commitbrief map main..develop              # bound to a range
commitbrief map --author alice             # matches highlighted, rest dimmed
commitbrief map --branches                 # branch topology instead
commitbrief map --all                      # every ref, not just HEAD's history

Commit graph (default)

One row per commit: lane gutter, short hash, ref labels, subject, author, relative age.

● a1b2c3d  (main) feat: add commit filters        alice  2h
│╲
│ ○ e4f5a6b  (payments/stripe) chore: bump sdk    bob    3d
│ ○ b7c8d9e  fix: rounding                        bob    3d
│╱
● f0a1b2c  docs: readme                           carol  1w

● matches the filter   ○ context

With no filter every commit is and no legend is printed. With one, matches are highlighted and the rest are drawn as dimmed context — deliberately kept in the graph, because a picture of only the matches would be a list, not a graph, and the lanes would be meaningless.

Merge commits are always drawn here, even though the filters exclude them by default elsewhere. In a graph a merge is structure: hiding it leaves lanes that fork and never rejoin.

Branch topology — --branches

One row per branch, showing where it sits relative to the base and how far it has drifted:

main                      base       alice  2h
├─ payments/stripe        ▲3   ▼12   bob    3d
└─ feature/upgrade        ▲8   ▼0    alice  1h

is ahead (commits this branch has that the base does not), is behind. The base is resolved from origin/HEAD, falling back to main / master / trunk, then the current HEAD — it never fails, because a topology view with an imperfect base beats an error. Capped at 200 refs.

Commit filters are rejected in this mode: a branch list has no commits to select, and rendering an unchanged view that silently ignored your flag would be worse than saying so.

Flags

Flag Default Notes
--branches off Branch topology summary instead of the commit graph.
--all off Walk every ref rather than the given range / HEAD. Graph mode only.
--max-commits <N> 200 How many commits to draw. Truncation is reported on stderr.

All the commit filters apply in graph mode.

Rejected flags

map draws a graph, not findings, so flags that promise something else are refused rather than quietly ignored:

  • --json / --markdown — a graph JSON (nodes, edges, lanes) would be a new versioned schema for output whose consumer is a person looking at a terminal. Deferred until someone asks with a real use case. Use --output <file> to capture the plain-text graph.
  • --fail-on / --min-severity / --suggest-commit — there are no findings to act on.

Terminal behavior

  • Rows clip to the terminal width rather than wrapping. A wrapped row would carry no lane gutter on its continuation line, visually detaching it from the graph. The gutter is drawn first, so the topology survives even when a subject is cut.
  • Colour and box-drawing fall back together: a terminal that refused ANSI is also the one most likely to mangle . A pipe, a file, or --color=never yields pure ASCII (*, o, |, \, /).
  • Relative ages are coarse on purpose (3d, not 3 days 4 hours) to keep the column scannable.
  • A truncated walk closes lanes at the boundary rather than inventing edges to commits it was never given, so the graph shows where it stops.

See also