Documentation

Landing

How on land merges a change into main on the server, and what to do when it doesn't go through.

on land puts a change on main. The server does the merge, so you never pull or rebase first, and a land is never refused because someone else landed before you.

on land -m "Fix login redirect loop" -m "Why: expired sessions bounced between /login and /home. Checked: auth tests pass."

The first -m is the title and the rest are the body. A change needs a description, from -m, on describe or the title given to on new.

What happens

  1. Saved first. on land saves and sends the change's last save. Edits after that go into your next change.
  2. Ordered by the server. Each project's main has one queue, and landings are decided in the order they arrive.
  3. Merged on the server. Each file merges three ways: where your change started, the latest main and your change.
  4. One change, one version. The change becomes the next numbered version of main, with its description and author.
  5. You keep working. The workspace moves to a new, empty change on top of what landed. Your files don't change.

How files merge

  • Text merges line by line, as in Git. Where Git's line merge is clean, Onset's result is the same byte for byte.
  • Two changes that each add whole functions or tests at the same spot both go in.
  • Imports from both sides are kept in JavaScript, TypeScript, Python, Rust, Go, Java, Kotlin, C, C++, C# and Swift.
  • Entries added to a sorted list go in sorted.
  • JSON and TOML files merge by key.
  • A file moved in one change and edited in another lands once, at its new path, edited.
  • A merge never declares one thing twice. Two functions with one name, or one key twice in a map, is a conflict, even where Git would merge it.
  • Statements added at the same spot stay a conflict, because their order matters.

Outcomes

OutcomeExitWhat happenedNext
landed0The change is the next version of main.Keep working.
conflict3Main didn't move. Your change is saved, and the conflicting files are listed.on sync, fix, on land
checks failed4Main didn't move. A [land] run command failed.Fix, on land
waiting5Someone else has to land or approve it, or it's in review.on status <change> later
offline6The host can't be reached. The change is saved.on land again later
secret8Something in the change looks like a secret. The file and line are printed.Remove it, or move it to .env

Landing again is always safe. If the host landed a change and its answer never arrived, on land again gives the same answer and nothing lands twice.

Fix a conflict

$ on sync
synced     rtnbkcvx onto main 48213  (was main 48190)
conflict   src/auth/login.ts  lines 40-58
next: fix the marked lines in src/auth/login.ts, then on land

on sync brings your change up to date with main and writes conflicts into the files with Git-style markers:

<<<<<<< main 48213
  return redirect(session.next ?? "/home")
=======
  return redirect(safeNext(session.next))
>>>>>>> your change rtnbkcvx

Remove the markers, keep the right code and run on land. For a binary file your version stays in place, and on restore <file> --from main takes main's instead.

You never need to sync before landing. Sync when you want others' work in your files, or after a land reports a conflict.

Who can land

On Upstream, a repository's admins and writers land. Anyone else's land waits, and the people who can land are asked. Outside contributors work the same way, with no fork: they get the project, make a change and run on land.

on land <change> lands someone else's change when you have landing rights.

Rules, approvals and review

A repository's rules apply to Onset as they do to Git.

  • No rules. The land goes on main at once.
  • Rules. on land opens a change request with auto-merge on and prints its link. Upstream merges it once its approvals and checks pass, and the merge comes into main as that change.
  • Approvals only. on settings approvals=1 makes a land wait until that many other people run on approve <change>. An approval counts for exactly what was approved, and the last one lands the change.

On the web

A project's Onset tab on upstream.codes shows main as versions, newest first, and new ones appear as they land. Open a version to see its diff against the one before.

Changes lists the open changes you can see: yours, ones shared with you, and ones waiting on you. A change's page has its diff, its saves, and Approve and Land for people with landing rights. Approve and Land there work like on approve <change> and on land <change>, as you: the repository's rules, approvals, signed-only projects and the secret check all apply. Where the rules send lands through review, Land on your own change opens its change request, and the page shows it as In review with a link; it lands from there.

Checks

onset.toml can name commands that run in your workspace before a land:

[land]
run = ["pnpm lint", "pnpm test"]

If one fails, nothing lands. on land --no-run skips them once.

Lands don't wait for CI. To keep main working, run a watcher on any machine with landing rights:

on watch --run "pnpm test"

It runs the check on each new version of main. When the check fails, it finds the first failing version, takes it back out of main and reopens its change for its owner.

More ways to land

  • A stack. on new "Title" --on <change> builds on a change that hasn't landed. Landing the top change lands the whole stack, bottom first.
  • Two projects together. on land --with ../api lands this workspace's change and the other's together: both, or neither.
  • At a set time. on land --at "fri 9:00" (or "in 2h") keeps the change as it is now and lands it then. on land <change> lands it now, and on drop <change> cancels it.
  • Signed. After on key, every land from that machine is signed. on verify checks who signed a version, and on settings signed=required refuses unsigned lands.

Release lines

A release line is a named line of versions next to main, for a maintained 1.x while main goes on.

on line 1.x --from v1.0                                  # start a line from a tag or version
on get upstream.codes/acme/shop ../shop-1x --line 1.x    # a workspace on the line
on land <change> --to 1.x                                # bring a change over from main

A change started on a line lands there as 1.x/1, 1.x/2 and so on. In the Git view, each line is a branch of its name.