pull
uses tcmts.cli.sync.openRemote, which uses process
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { diffNamespaces, printDiff, stateOf } from "#codebase/tcmts/cli/diff"; import { mergeApart, takeConflicts } from "#codebase/tcmts/cli/merge"; import { dim } from "#codebase/tcmts/cli/style"; import { fetchHistory, fetchLints, fetchReleases, fetchResults, openRemote } from "#codebase/tcmts/cli/sync"; export async function pull(cb: Codebase, spec: string, remoteBranch: string | undefined) { const { remote, name } = openRemote(cb, spec); if (!name) throw new Error(`pull needs a configured remote: \`tcm remote add <name> ${spec}\``); const branch = remoteBranch ?? cb.store.branch().name; const theirs = await remote.branch(branch); if (!theirs) throw new Error(`${name} has no branch '${branch}'`); const stored = await fetchHistory(cb, remote, theirs.head); const tracking = `${name}/${branch}`; cb.store.setHead(tracking, theirs.head, `pull ${name}`); if (stored) console.log(dim(`received ${stored} definition(s), verified by re-hashing`)); // and what their tests came to, where they ran as they would here: they needn't run again const results = await fetchResults(cb, remote, theirs.names); if (results) console.log(dim(`received ${results} test result(s)`)); // and what linting found, which needn't be done again here const lints = await fetchLints(cb, remote, theirs.names); if (lints) console.log(dim(`received ${lints} lint result(s)`)); const released = await fetchReleases(cb, remote); if (released.length) console.log(dim(`received release(s) ${released.join(", ")}`)); const local = cb.store.branch().name; const mine = cb.store.head(); if (cb.store.isAncestor(theirs.head, mine)) { return console.log( dim( mine === theirs.head ? `${local} is up to date with ${tracking}` : `${local} already has everything in ${tracking}; \`tcm push ${name}\` publishes what's new here`, ), ); } if (!cb.store.isAncestor(mine, theirs.head)) { // both sides changed since they last shared history: merge theirs in (one that leaves something to settle waits // apart, main as it was); `push` then publishes the result const r = mergeApart(cb, tracking, { command: `pull ${name} (merge)`, keep: local !== "main" }); if (r.left.conflicts.length || r.left.failed.length) { if (local === "main") console.log( dim( ` (main isn't left with something to settle: pull ${tracking} into a branch of main's, settle it there, and land that)`, ), ); return; } // (conflicts theirs has that are still conflicts here keep their sides; the merge labels its own) takeConflicts(cb, local, theirs.conflicts, "add"); console.log(dim(` \`tcm push ${name}\` to publish the merge`)); return; } const before = stateOf(cb.store.names(undefined, true)); cb.store.setHead(local, theirs.head, `pull ${name}`); // (and the sides of its conflicts, as its merge labelled them) takeConflicts(cb, local, theirs.conflicts, "add"); cb.refreshShim(); const after = stateOf(cb.store.names(undefined, true)); printDiff( cb, diffNamespaces(before, after, (h) => cb.store.getDef(h)!.ir), before, after, `fast-forwarded ${local} to ${tracking}`, ); }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.diff.diffNamespaces
- tcmts.cli.diff.printDiff
- tcmts.cli.diff.stateOf
- tcmts.cli.merge.mergeApart
- tcmts.cli.merge.takeConflicts
- tcmts.cli.style.dim
- tcmts.cli.sync.fetchHistory
- tcmts.cli.sync.fetchLints
- tcmts.cli.sync.fetchReleases
- tcmts.cli.sync.fetchResults
- tcmts.cli.sync.openRemote