Contributions: reviewing changes
A contribution is a branch proposed for merging into another, as on Unison Share. It's reviewed as a diff of
definitions rather than text, commented on, and merged on the remote by history. Contributions live
in the codebase you push to: a tcm serve server, or another codebase directory.
Proposing a change
Make the change on a branch, then contribute it:
$ tcm branch faster && tcm switch faster $ tcm update # change lib.square, add lib.cube $ tcm contribute --title "Faster squares" --description "Uses ** now." pushed origin/faster: 3 names (new branch); sent 3 definition(s) opened contribution #1 on origin review: tcm contribution view 1 · https://tcm.example.com:7737/forge/contributions/1#token=…
tcm contribute [remote] [--to main] [--as name] [--title t] [--description d]pushes the current branch (under its own name, or--as) and opens a contribution of it intomain(or--to). Without--title, you're asked at a terminal; elsewhere the branch's name is the title.- Pushing again updates it:
tcm contributeortcm pushon the same branch moves the open contribution to your latest changes. - From
mainthere's nothing to propose: make a branch first.
Contributors
A project with contributors works as on Unison Share:
only the maintainer pushes main. Each contributor gets a token from the maintainer and pushes contributor
branches, under their handle, into the project itself (no fork):
$ tcm user add grace # the maintainer, with the server's token added @grace on origin: they push branches under @grace/ and propose them their token (shown once; adding them again makes a new one): 8bS… they connect with: tcm remote add origin https://tcm.example.com --token 8bS… $ tcm remote add origin https://tcm.example.com --token 8bS… # grace $ tcm pull && tcm branch cubes && tcm switch cubes $ tcm contribute --title "Cubes" pushed origin/@grace/cubes: 1 added, 0 changed, 0 removed, 0 renamed; sent 1 definition(s) opened contribution #1 on origin
- A contributor's branches are named for them.
tcm pushandtcm contributepushcubesas@grace/cubes, and--as spareas@grace/spare(a name already under@grace/stays as it is). The server refuses them any other branch. - Their token signs what they write: contributions, comments, closing and reopening are
@grace's, whatever$TCM_AUTHORsays. The maintainer's token signs as$TCM_AUTHOR(or your user name). - Merging is the maintainer's, as are releases and the test results and lint findings a push sends. A contributor's pushes leave those out: the maintainer's tests run on what's merged. A contributor closes and reopens only their own contributions.
tcm user [--remote origin]says who you are on a remote; to the maintainer, it lists the contributors.tcm user rm gracestops grace's token working;tcm user add graceagain gives grace a new one.- On a
--publicserver, anyone can pull and read contributions and their review pages without a token.
Reviewing
$ tcm contribution view 1
#1 Faster squares open
faster → main · opened by ada 2026-10-29 01:30 · 0 comment(s)
Uses ** now.
✓ merges as a fast-forward
changes on faster since it left main (#2jut5etj)
edited
~ lib.square #tvtxd4fk → #kndlow5j
- export const square = (x: number): number => x * x
+ export const square = (x: number): number => x ** 2
updated because a dependency changed (code unchanged)
~ lib.sumSquares #675kvzb7 → #d72molby via lib.square
added
+ lib.cube #dzuntsd3 : (x: number) => number
tcm contribution [--all]- the remote's open contributions (
--all: merged and closed too) tcm contribution view <id>- its changes and whether it merges
tcm contribution comment <id> <text> [--about <name>]- comment on the whole change, or on one definition
tcm contribution merge <id>- merge it on the remote
tcm contribution close <id>/reopen <id>- close it without merging, or open it again
Each takes --remote <name> (default origin).
viewshows the changes since the branch left its target, astcm diffdoes: edits, what re-hashed because of them (and why), and what's added, removed and renamed. Renames and reformatting aren't changes.- It says whether it merges: as a fast-forward, cleanly (naming definitions both sides edited apart, which the merge merges as text), or with conflicts in which names.
- Comments and merges are signed with
$TCM_AUTHOR, or your user name; a contributor's, with their handle (above).
The review page
tcm serve's web UI has a page for each contribution, at the link tcm contribute prints. The link
signs the browser in with the token in its fragment, which is never sent to a server. The page has:
- the conversation;
- the changes along a review path (what's new before what uses it, then tests; what only re-hashed, folded), each definition's diff with its comments;
- whether it merges;
- what you may do: comment, close or reopen your own, or merge (the maintainer).
/forge/contributions lists them all (a site served beside it has every other path).
With no token, on a public server, the pages are read-only.
Merging
tcm contribution merge <id> (or the page's button) merges it on the remote, by history:
- A fast-forward if the target hasn't moved since the branch left it.
- Otherwise a three-way merge from their common ancestor, recorded with both as parents. Definitions both sides edited apart are merged as text, and the merge is refused if they don't typecheck merged.
- Refused if what it brings doesn't typecheck, with the errors. The code its branch reaches that the target didn't is typechecked on the remote, under each definition's recorded check profile. This is where a contribution's types are judged: receiving a push checks only that code is what it claims (sync).
- Refused if both changed the same names differently. Bring the target into the branch, settle the conflicts, and push again:
$ tcm contribution merge 3 #3 conflicts with main in lib.square: merge main into b (`tcm pull <remote> main` on that branch), resolve, push, and merge again $ tcm switch b && tcm pull origin main # merges origin/main into b $ tcm resolve lib.square '#…' $ tcm contribute # updated contribution #3 $ tcm contribution merge 3 merged #3 on origin as #mio7i2g5
Afterwards, tcm pull on your main fast-forwards to the merge, and the contribution shows what the merge brought.