historySides
What each of a branch's entries (newest first, as historyList reads them) is beside main: its own work, on the
branch and not on main (own); landed on main, a squashed landing (merge <branch> on main) taking it, said by
that landing, the branch having merged it back since (landed); or main's, in main's history (base). For main
itself, or a codebase without one, there's no base, and nothing is said.
import type { HistoryItem } from "#codebase/tcmts/cli/changes"; import type { Codebase } from "#codebase/tcmts/cli/codebase"; export function historySides( cb: Codebase, branch: string, entries: HistoryItem[], ): { base?: string; sides: Map<string, { side: "own" | "landed" | "base"; landing?: string }> } { const sides = new Map<string, { side: "own" | "landed" | "base"; landing?: string }>(); const base = branch !== "main" && cb.store.hasBranch("main") ? "main" : undefined; if (!base) return { sides }; const onBase = new Set(cb.store.ancestors(cb.store.head(base))); const landing = (h: string) => onBase.has(h) && cb.store.causal(h)?.command.split("\n")[0] === `merge ${branch}`; // (newest first: a merge back of a landing, and every entry before it, landed with it) let landed: string | undefined; for (const e of entries) { if (onBase.has(e.hash)) { sides.set(e.hash, { side: "base" }); continue; } const back = e.parents.find(landing); if (back) landed = back; sides.set(e.hash, landed ? { side: "landed", landing: landed } : { side: "own" }); } return { base, sides }; }