Docs / Forks & merges

Forks & merges

Branch, reconcile, and propose changes across agents.

Forking is the only time travel

agit fork exp#4 -b alt           # branch off turn 4
agit fork alice/photo@exp -b repro --resume

You never “check out an old state” — history only grows. Forking from any ref (branch tip, old commit, tag, exp#12, someone else’s line) mints a new session identity and inherits the tree byte-for-byte. If the point you name has no session (a file-line point on main), fork refuses: agit new starts a fresh session instead.

  • agit resume alt — continue a session: native resume when the runtime matches (full fidelity), materialized resume across runtimes (loss list confirmed up front), or --force past an active sibling instance.
  • agit new -b fresh — a brand-new session that inherits the shared files (memory/, skills/) from main, empty transcript.

The merge protocol

agit merge alt --into exp           # start: recon (fork point, new turns each side)
# a merge agent is resumed — or drive it yourself:
agit merge alt --into exp --manual
agit merge pick alt#5..#6           # select turns
agit merge drop alt#7.2             # unselect
agit merge summary -m "keep only the ratelimit conclusion"
agit merge --continue               # CAS + two-parent commit
agit merge --abort                  # walk away; the target ref never moved

--status shows the open transaction, --dry-run recon only.

--continue validates the summary exists and the target ref still matches (compare-and-swap), then lands a two-parent commit. The VIEW gains marker envelopes (__merge_start__/__merge_end__) plus the merge summary — the next session inherits not just the merged content but what the reconciliation concluded.

Conflicts in this system are rarely text conflicts — they’re intent collisions (one side rate-limits by user_id, the other renamed it to uid; both compile, together they’re wrong). That’s why a merge agent reads the transcripts instead of git guessing byte ranges.

Cherry-pick and revert

agit cherry-pick alt#5..#6 --into exp   # lift turns without a merge agent
agit revert exp#12.3                    # drop an event from the VIEW

Both touch the VIEW only. The log — the evidence — never changes.

Pull requests

# contributor side (merge agent's work happened *before* this point)
agit pr create alice/photo@exp -b repro -m "fix for repro table 3"
# author side — review the proposed turns, then:
agit pr fetch <id> && agit show pr/<id> && agit pr merge <id>

pr merge is approve-and-land; the server never starts an agent. The server decides the landing shape:

  • fast-forward — contributor branched off the current tip;
  • mechanical merge — the contributor already landed a two-parent commit whose first parent is the target tip (a pre-run merge, replayed);
  • adopt — the whole incoming line is adopted as a new branch.

Two honest refusals: stale (your branch moved while the PR was open → 409, the PR is void rather than silently merging an old state) and genuinely diverged with no pre-run merge (→ 409 with the exact commands to fix it).