revertEntry
uses tcmts.cli.main.causalArg, which uses tcmts.cli.main.releaseAt, which uses tcmts.cli.manifests.packagesIn, which uses tcmts.cli.config.configValue, which uses node:path
Undo one history entry (a landing, say) and nothing after it, as a new entry: history isn't rewritten. What the
entry changed goes back to how it was before it, three-way: the names before it merged into the names now, from
the names it made. A name changed since keeps that change; one changed since where the entry changed it too is
a conflict (tcm resolve). Code that has come to use what it brought is re-derived against what comes back, and
what no longer typechecks goes to tcm todo.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { diffNamespaces, keyPath, printDiff, stateOf } from "#codebase/tcmts/cli/diff"; import { causalArg, stateAt } from "#codebase/tcmts/cli/main"; import { mergeStates, mergeTexts, printSettled, printTextMerge, settleMerge } from "#codebase/tcmts/cli/merge"; import type { MergeResult } from "#codebase/tcmts/cli/merge"; import { bold, dim, yellow } from "#codebase/tcmts/cli/style"; import { UsageError } from "#codebase/tcmts/cli/ui"; import { shortHash } from "#codebase/tcmts/core/hash"; import { entryTitle } from "#codebase/tcmts/store"; import type { NameRow } from "#codebase/tcmts/store"; export function revertEntry(cb: Codebase, ref: string): MergeResult { const entry = causalArg(cb, ref); const c = cb.store.causal(entry)!; const parent = c.parents[0]; if (!parent) throw new UsageError( `${shortHash(entry)} is where history starts: there's nothing before it to go back to`, ); if (!cb.store.isAncestor(entry, cb.store.head())) throw new UsageError( `${shortHash(entry)} isn't in this branch's history (\`tcm history\` lists it)`, ); const irOf = (h: string) => cb.store.getDef(h)!.ir; const made = stateAt(cb, entry); const back = stateAt(cb, parent); const before = stateOf(cb.store.names(undefined, true)); const textsBefore = cb.store.texts(); const result = mergeStates(made, before, back, { ours: new Set(diffNamespaces(made, before, irOf).propagated.map((p) => p.path)), theirs: new Set(diffNamespaces(made, back, irOf).propagated.map((p) => p.path)), }); // and the text versions they show (comments, layout, doc), the same way: what the entry changed goes back const states = { ours: before, theirs: back, merged: result.merged }; const texts = mergeTexts( cb.store.textsAt(c.namespace), textsBefore, cb.store.textsAt(cb.store.causal(parent)!.namespace), states, ); const rows: NameRow[] = [...result.merged].flatMap(([key, hs]) => [...hs].map((hash) => { const text = texts.texts.get(hash); return { path: keyPath(key), hash, kind: cb.store.getDef(hash)!.kind, ...(text ? { text } : {}), }; }), ); cb.store.transaction(() => { cb.store.setBranchNames(cb.store.branch().name, rows, `revert ${shortHash(entry)}`); for (const [o, n] of result.patches) cb.store.addPatch(o, n); }); const settled = settleMerge(cb, { base: made, ours: before, theirs: back }, result, { ours: "changed since", theirs: "as before it", }); cb.refreshShim(); const after = stateOf(cb.store.names(undefined, true)); printDiff( cb, diffNamespaces(before, after, irOf, { before: textsBefore, after: cb.store.texts() }), before, after, `reverted ${shortHash(entry)} (${entryTitle(c)})`, ); for (const p of result.keptOverDelete) console.log( `${yellow(" kept")} ${bold(p)} ${dim("(changed since, though the entry added it)")}`, ); printSettled(settled, { ours: "changed since", theirs: "as before it" }, "revert"); printTextMerge(texts, states, { ours: "the branch now", theirs: "as before it" }); return { ...result, conflicts: settled.conflicts.map((c) => c.key) }; }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.diff.diffNamespaces
- tcmts.cli.diff.keyPath
- tcmts.cli.diff.printDiff
- tcmts.cli.diff.stateOf
- tcmts.cli.main.causalArg
- tcmts.cli.main.stateAt
- tcmts.cli.merge.MergeResult
- tcmts.cli.merge.mergeStates
- tcmts.cli.merge.mergeTexts
- tcmts.cli.merge.printSettled
- tcmts.cli.merge.printTextMerge
- tcmts.cli.merge.settleMerge
- tcmts.cli.style.bold
- tcmts.cli.style.dim
- tcmts.cli.style.yellow
- tcmts.cli.ui.UsageError
- tcmts.core.hash.shortHash
- tcmts.store.NameRow
- tcmts.store.entryTitle