tcmts.cli.test.e2e.merge

Server

withConflicts (name: string) => { dir: string; tcm: (...args: string[]) => string; merged: { status: number | nul…
A codebase whose branch `s` has just merged `main` with two conflicts: `lib.k`, both sides changing the same line (main another too, apart), and `lib.m`, which uses it, both changing it too. `lib.user` uses both.

Tests

testACommentChangeStaysOnItsBranch () => void
A session that changes only a definition's doc and comments (the same code, the same hash) changes its own branch: main reads it as before, the session's history has the change as an entry (`tcm diff` shows it), revert and reset undo it alone, and merging lands it (main into it first, three-way), beside what main did meanwhile.
testAMergeLeftToSettleWaitsApart () => void
A merge that leaves conflicts isn't made: the branch stays as it was, the conflicts' sides are written to scratch files to settle them in, and commands on the branch work on the merge as merged; once nothing's left to settle, the branch has the merge.
testAMergeNotFinishedIsntPushed () => Promise<void>
A merge not finished stays where it was made: pushing the branch sends the branch as it is (not the merge), and a codebase pulling it has nothing to settle; the merge waits on here.
testAbortDropsAMergeNotFinished () => void
`tcm merge --abort` drops a merge not finished: the branch is as it was all along, and it can merge again.
testCommentChangeMergesWithCodeChange () => void
One side changes a definition's doc, the other its code: the merge keeps both, the doc merged into the new code as text, rather than dropping the doc change.
testConflictEditSaysWhatEachSideChanged () => void
`tcm edit` of a conflict says what each side changed from the base (lines added and taken out, and where they are in the file), and how many stretches both changed.
testConflictFileImportsWhatItsCodeUses () => void
A conflicted definition's file imports what its code uses: not `y`, which only ours used, on a line theirs changed (merged, nothing uses it), but `x`, which ours' side of the conflict marked uses. Settled for theirs, nothing uses `x` either, and saving the file takes its import out.
testConflictMarkersRoundTrip () => void
`tcm edit` of a conflicted name writes its two sides merged from the base, with git's conflict markers where both changed the same lines, and the rest merged. It can't be saved with the markers in it; without them, saving it resolves the conflict, and what used either side's is re-derived against it.
testConflictSidesAreKept () => void
The sides of a conflict are kept: `tcm todo` labels each definition with its side and branch, as the merge did, after the merge and in later commands, and says how to settle it.
testConflictUsingAnotherConflict () => void
A conflict whose sides merge cleanly but that uses another conflicted name can't typecheck until that's settled: `tcm edit` says so (not that it "didn't typecheck"), as `tcm check` does, and editing both puts them in one file, where they check together; saving it resolves both, named so in history.
testConflictedDefinitionsAreRederived () => void
Both definitions of a conflicted name are re-derived against what the merge names, as all code is: the other side's uses this side's replacement for what it used, once that's re-derived itself (here against the other side's change to what it uses, with a new signature), not a version in between that nothing names.
testConflictsEditedInARow () => void
Conflicts edited one after another each get a file of their own, named after the definition, rather than colliding on the default scratch file (or the one an update left behind).
testCrissCrossMerge () => void
Criss-cross merges: two branches that merged each other have two best common ancestors, each lacking the other's change. Merged from the newer one alone, the other's change looks like no change, so a side undoing it is lost; merged into a virtual base first, it isn't. And a conflict between them that the two merges resolved differently is a conflict again. (The two merges must differ: the same merge both ways is the same causal, one ancestor.)
testDeletedNameStillUsedIsKept () => void
A name one side removed, that the other side's new code uses, is kept: the merged code would otherwise use what nothing names.
testDiffOfDefinitions () => void
`tcm diff` compares definitions: two by #hash, or a conflicted name's, the base's against each side's.
testLandingKeepsTheHistoryOfItsReleases () => void
A branch that made a release lands with its history, squashed or not: the release is an entry of the branch's, so main's next release follows it, and a push of main carries it.
testLandingMergesMainIntoTheBranchFirst () => void
On main, `tcm merge <branch>` lands it as a session does: main is merged into the branch first, there; where that leaves something to settle, nothing lands and main is untouched (the merge waits on the branch); settled, the branch lands, its tests passing.
testLeftoverScratchFileIsReplaced () => void
A file `tcm update` left behind holding only what's saved (here, what's one side of a conflict since) is replaced by a conflict's edit; one holding work that isn't saved isn't, and what's in the way is named.
testMergeAfterASquashedLandingLeavesNothingStale () => void
Work kept on a branch after its squashed landing, while main moved on: merging main in starts from the landing (merged into the branch when it landed), so a name the branch changed again isn't a conflict with its own landed version, and what uses what both sides re-hashed follows to the merged version: nothing is left using a version nothing names.
testMergeOfAChangeBothSidesMadeLeavesNothingStale () => void
Both sides made the same change (a cherry-pick, say), and one side another: a definition each side only re-hashed is ours re-derived, which hashes as theirs did, and what uses it follows it there: nothing is left using a version nothing names.
testPageConflictMarkers () => void
A conflicted page is edited the same way: its Markdown merged, with conflict markers, and saved to resolve it.
testPageConflictWithImporter () => void
Both sides edit a page that code imports. Edits apart are merged as text, and the code follows the merged page; edits that overlap are a conflict, and resolving it re-derives the code against the page kept.
testResolveBySide () => void
`tcm resolve --ours` / `--theirs` keeps a side's definition by its side, as it is now: resolving one conflict re-derives the other side's code that used the definition it drops, so a hash copied before would be stale.
testResolveRepointsDependents () => void
The same, with edits that overlap: the class is a conflict, labelled by side. The code using the conflicted class through what's between uses this side's, so the other side's code that needs its own doesn't typecheck: it's to do (not left using versions nothing names). Resolving the conflict to the other side re-derives it, and this side's code, against the one kept.
testRevertUndoesOneLanding () => void
A branch landed with `--no-fast-forward` is one history entry, though main could have fast-forwarded; `tcm revert` undoes it whole, and nothing done on main since.
testSavingOverAConflictResolvesIt () => void
A definition saved from a scratch file at a conflicted name (written by hand, not `tcm edit`'s) resolves the conflict to it, in one step: no `tcm resolve` first.
testSharedDependencyChangedOnBothSides () => void
Both sides change a class their code shares (each adding a method), and one side's code uses its own method. The class is merged as text (the edits are apart), and the code taken from either side is re-derived against it, through what's between (each side had re-derived it for its own class): nothing is left using a version nothing names.
testSquashedLandingKeepsItsStepsOwn () => void
A branch squashed in is one entry whose only parent is main's: its steps stay its own, so a push of main sends what it ended with, not each version along the way; it counts as landed until it changes again.
testTextMergeThatDoesntTypecheckIsQuiet () => void
A definition both sides edited apart whose text merge doesn't typecheck stays a conflict, and the merge says so without the type errors (`tcm todo` and `tcm check` have them): `tcm edit` writes the merged text, no markers in it, to fix, and says it doesn't typecheck.
testThreeWayMerge () => void
Three-way merge: one-sided changes combine, real conflicts stay conflicts, code follows the other side.
testViewNamesWhatTheOtherSideUses () => void
The other side's definition of a conflicted name that can't follow this side's change (it doesn't typecheck against it) keeps using what this branch replaced; `tcm view` shows that by name, saying which version it is.