Skip to content

ctx resolve

ctx resolve settles one page that changed both on your machine and on the server. --ours keeps your working file and makes the next push publish it over your teammate’s version. --theirs replaces your working file with the server’s version, after saving a backup of yours.

When ctx push reports a conflict, when ctx status lists a page under CONFLICTS, or when ctx pull skips a page with “conflicts with the server version”. Push and pull never pick a side for you; this command is how you pick one.

Neither option merges. If you want both sets of changes, merge by hand: look at the server version with ctx show <path> --at server, edit your working file until it holds what you want, then run ctx resolve <path> --ours and push. --ours means “my file, as it is now, is the new version”.

--theirs has a second use: it brings back a page you deleted locally. ctx status suggests it under DELETED LOCALLY.

Terminal window
ctx resolve <relpath> --ours
ctx resolve <relpath> --theirs
ctx resolve <relpath> --ours --if-server-sha <sha>
ctx resolve <relpath> --theirs --json
FlagTypeDefaultDescription
--if-server-shastringfail with stale unless the server is still at this sha
--jsonboolfalseemit a JSON document
--oursboolfalsekeep the local content, re-based onto the server version
--theirsboolfalsereplace the local file with the server version

Pass exactly one of --ours and --theirs. Neither, or both, is a usage error: with --json it is the usage envelope and exit 3; without --json it is a plain error message and exit 1, like every other failure in human mode.

--if-server-sha <sha> makes the command refuse unless the server’s current version of the page is still that commit. Use it when you looked at the server version (with ctx show --at server, or the remote.sha in ctx status --json) and want to be sure your decision still applies: if your teammate pushed again in the meantime, resolve fails with stale (exit 6) and changes nothing. The sha must be 7 to 64 hex characters and is compared in full, ignoring case. An abbreviated sha that merely prefixes the server’s sha counts as stale.

--json prints a ctx.resolve.v1 document instead of the one-line summary. This one comes from the real binary (paths and shas are test placeholders):

{
"schema": "ctx.resolve.v1",
"path": "wiki/concepts/retry-policy.md",
"strategy": "theirs",
"previous_state": "conflict",
"state": "unchanged",
"base_sha": "0000000000000000000000000000000000000001",
"file_written": true,
"backup_file": ".sync/backup/wiki/concepts/retry-policy.md.20000101T000000Z",
"warnings": []
}

base_sha is the server version the page is now based on. backup_file appears only when a backup was taken, and is relative to .contexo/. file_written is false for --ours, which never touches the working file.

FlagTypeDefaultDescription
--rootstringproject root directory (default: current directory)

Your working file stays exactly as it is. ctx records the server’s current version as the page’s base and clears the recorded conflict. The page now shows as modified (or unchanged, if your file happens to equal the server version), and the next ctx push sends your content with the server’s version as its parent, so it lands on top of your teammate’s edit instead of being refused.

--ours is allowed only from a conflict (either kind) or from an unverified page with a valid working file. From any other state it refuses with not_resolvable (exit 9) and writes nothing. For example, --ours on a page that is only incoming (you never changed it) would silently revert your teammate’s change, so ctx will not do it.

The working file is replaced with the server’s version, and that version becomes the base, so the page ends unchanged. If your file differs from the server’s bytes, it is first copied to:

.contexo/.sync/backup/<relpath>.<YYYYMMDDTHHMMSSZ>

The timestamp is UTC. The file is read right before it is overwritten, so the backup holds whatever you last saved. A missing working file (a page you deleted locally, or one that exists only on the server) is created with its directories. A file that already equals the server version is not rewritten. When the file is written, index.md and tags.md are regenerated.

--theirs works from any local state, as long as the server has the page. On a page that is already unchanged it is a no-op that only drops a leftover conflict record, so running it twice never takes a second backup.

In both cases the page must exist on the server: if it does not, the result is page_not_found (exit 8).

Take the server version of the worker page. Your previous file is kept as a backup, and the summary prints its full path:

Terminal window
ctx resolve wiki/entities/billing-worker.md --theirs
ctx resolve wiki/entities/billing-worker.md --theirs
✔ Took the server version of wiki/entities/billing-worker.md (3b8e1a0); your previous file is saved at ~/projects/acme-api/.contexo/.sync/backup/wiki/entities/billing-worker.md.20260728T091407Z

Keep your version of the subscription page, on top of the server’s commit f0c47d2:

Terminal window
ctx resolve wiki/concepts/stripe-subscription.md --ours
ctx resolve wiki/concepts/stripe-subscription.md --ours
✔ Kept your version of wiki/concepts/stripe-subscription.md on top of server f0c47d2; now run ctx push

Then publish it. The push is now an ordinary edit of the server’s latest version, so it goes through:

Terminal window
ctx push --yes
ctx push --yes (after resolve --ours)
About to push 1 page(s) to acme-api:
  [EDIT]  wiki/concepts/stripe-subscription.md  (~ Concepts)
Pushed 1 page(s); HEAD=a4b2c1d3

The command’s own help text:

Terminal window
ctx resolve --help
ctx resolve --help
Resolve a conflicted page.

--ours keeps your working file and re-bases it onto the current server version;
run ctx push afterwards to publish it over the teammate's edit.
--theirs replaces your working file with the server version. A file that differs
is first saved under .contexo/.sync/backup/.

--if-server-sha refuses (stale) unless the server is still at that sha.

Usage:
  ctx resolve <relpath> (--ours|--theirs) [flags]

Flags:
  -h, --help                   help for resolve
      --if-server-sha string   fail with stale unless the server is still at this sha
      --json                   emit a JSON document
      --ours                   keep the local content, re-based onto the server version
      --theirs                 replace the local file with the server version

Global Flags:
      --root string   project root directory (default: current directory)
  1. Checks the arguments with no I/O: the path rules (the same as ctx show), exactly one strategy, and the form of --if-server-sha. A bad argument is invalid_path or usage (exit 3) in any project, logged in or not.
  2. Checks that .contexo/ exists, then resolves the server, token and repo id the same way push and pull do.
  3. Takes .contexo/.sync/lock, waiting up to CONTEXO_LOCK_TIMEOUT (default 10 seconds) if another ctx process, often an agent’s push or pull, holds it. After that it fails with busy (exit 12).
  4. Reads the page from the server once, taking both its content and its sha.
  5. Applies --if-server-sha, then classifies the page against that fresh server sha, taking any recorded conflict into account.
  6. Writes, in this order: the backup and the working file (--theirs only), the base, then the indexes under .contexo/.sync/. The page’s conflict record is cleared.

resolve makes exactly one server read. It never lists the repo, never reads history, never repairs other pages’ bases, and never pushes: after --ours, publishing your version is a separate ctx push.

With --json, every failure is a one-line envelope on stderr; without it, a message and exit 1. The exit codes with --json are 0, 3, 4, 5, 6, 7, 8, 9 and 12 (and 1 for an internal error).

not_resolvable (exit 9): the strategy does not apply to the page’s current state. details names the path, the state and the strategy. From the real binary:

{"schema":"ctx.error.v1","exit_code":9,"error":{"code":"not_resolvable","message":"resolve wiki/concepts/idempotency-keys.md --ours: the page is incoming, not a conflict","advice":[],"retryable":false,"details":{"path":"wiki/concepts/idempotency-keys.md","state":"incoming","strategy":"ours"}}}

Run ctx status to see the real state. For an incoming page, ctx pull is what you want.

stale (exit 6): --if-server-sha did not match. details carries path, expected_sha and server_sha. Look at the new server version and decide again.

page_not_found (exit 8): the server does not have the page. There is nothing to resolve against; push it instead.

usage (exit 3, or exit 1 without --json): resolve: pass exactly one of --ours or --theirs, or a malformed --if-server-sha.

busy (exit 12): another ctx process held the lock for longer than CONTEXO_LOCK_TIMEOUT. details names its pid, host, command and start time. Retry once it finishes.

not_authenticated (exit 4), server_unresolved or repo_not_configured (exit 5): resolve always talks to the server. See ctx login and ctx remote.