testMergesFollowHistory
Merges follow history: fast-forwards, recorded merges, and remotes that move forward only.
import { tempDir } from "#codebase/tcmts/cli/test/e2e/harness"; import { codebase } from "#codebase/tcmts/cli/test/e2e/history"; import assert from "node:assert/strict"; export const testMergesFollowHistory = () => { const root = tempDir("history"); const a = codebase(root, "c"); a.tcm("init"); a.write(`export const base = 1;\n`); a.tcm("add"); a.tcm("branch", "feature"); a.tcm("switch", "feature"); a.write(`export const feature = 2;\n`); a.tcm("add"); a.tcm("switch", "main"); // main hasn't moved: merging is moving it to feature's head, with no merge entry assert.match(a.tcm("merge", "feature"), /fast-forwarded main to feature/); assert.equal(a.entries()[0], (a.tcm("switch", "feature"), a.entries()[0])); a.tcm("switch", "main"); // both moved: a merge entry with both heads as parents, and merging again brings nothing (into a branch of main's: // on main, a branch lands, main coming into it first) a.tcm("branch", "m"); a.tcm("switch", "m"); a.write(`export const onMain = 3;\n`); a.tcm("add"); a.tcm("switch", "feature"); a.write(`export const onFeature = 4;\n`); a.tcm("add"); const featureHead = a.entries()[0]!; a.tcm("switch", "m"); assert.match(a.tcm("merge", "feature"), /merged cleanly/); assert.match(a.tcm("history", "1"), new RegExp(`merge feature merged #${featureHead}`)); assert.match(a.tcm("merge", "feature"), /already has everything in feature: no changes/); a.tcm("switch", "main"); // another codebase changes too; pulling merges (from the common ancestor), and pushing that back is a // fast-forward for the first, which then pulls nothing new to merge const b = codebase(root, "d"); b.tcm("init"); b.tcm("remote", "add", "origin", a.dir); b.tcm("pull"); b.write(`export const fromB = 5;\n`); b.tcm("add"); a.write(`export const fromA = 6;\n`); a.tcm("add"); assert.throws(() => b.tcm("push"), /has changes you don't have/); assert.match(b.tcm("pull"), /merged origin\/main into main[\s\S]*\+ fromA[\s\S]*merged cleanly/); assert.match(b.tcm("push"), /pushed origin\/main/); assert.deepEqual(a.entries(), b.entries(), "the push brought b's history, merge included"); assert.match(a.tcm("ls"), /fromB/); }