swarmops diff#
List the files that differ between two revisions, a page at a time.
- Group
read- Since
0.1.0- Mutates
- no
- Identity required
- no
- MCP tool
diff- Envelope op
diff- Exit codes
- 026
Syntax#
swarmops diff [OPTIONS] <FROM> <TO>Required arguments#
Syntax: <FROM>.
The revision to diff from.
Syntax: <TO>.
The revision to diff to.
Optional arguments#
The command also takes the global options.
Syntax: --path <P>....
Only the files at or below this path; give it again for more.
Syntax: --format <FORMAT>.
Default: names.
What to say of each file. Values: names: Its path and status; stat: Also whether it is binary and, for text, the lines it inserts and deletes; unified: Also its kinds, its blobs and, for text, its hunks.
Syntax: --context <N>.
Default: 3.
The unchanged lines around each change in a unified hunk.
Syntax: --limit <N>.
Default: 500.
The most files to list.
Syntax: --cursor <CURSOR>.
Resume a diff: the previous page's cursor, exactly as it was returned.
Syntax: --max-bytes <N>.
Default: 32768.
The most bytes of a unified page's files, as JSON (the first file comes all the same, its hunks cut to fit).
Examples#
swarmops --repo [tmp]/store diff [c1] [c2]{
"ok": true,
"op": "diff",
"api": 1,
"result": {
"from": "[c1]",
"to": "[c2]",
"files": [
{
"path": "README.md",
"status": "modified"
},
{
"path": "bin/run",
"status": "modified"
},
{
"path": "latest",
"status": "type_changed"
},
{
"path": "logo.bin",
"status": "modified"
},
{
"path": "notes.txt",
"status": "deleted"
},
{
"path": "src/lib.rs",
"status": "added"
}
],
"truncated": false
},
"meta": {
"repo": "[tmp]/store",
"elapsed_ms": "[elapsed_ms]",
"resolved": {
"[c1]": "[c1]",
"[c2]": "[c2]"
},
"auth": "trust"
}
}Exit code 0. Recorded by the CLI tests. A name in square brackets, such as [tmp] or [c1], stands for what differs from run to run: the test's temporary directory, an id, a time.
No recorded example yet.
Details#
diff compares the trees of any two changesets and lists the files that differ, in path order,
a page at a time. --format decides how much it says of each file, from the path and its status
up to unified hunks, so an agent can ask for exactly what it needs.
What differs#
FROM is the old side, TO the new; both resolve in one snapshot, and the result names the full
ids they resolved to. The two need not be related: any two changesets compare. Swapping them
swaps added and deleted. The same changeset on both sides gives files: [].
Only files, executables and symlinks are listed, never a directory. Each has a status:
status | Meaning |
|---|---|
added | In TO only: in FROM nothing, or a directory, is at its path. |
deleted | In FROM only. |
modified | Its content or its executable bit changed: a file or an executable on both sides, or a symlink on both sides. |
type_changed | A symlink on one side, a file or an executable on the other. |
A file that becomes a directory is that file deleted and the directory's files added. No
rename is detected: a moved file is one deleted and one added.
Formats#
--format | Adds to path and status | Reads content |
|---|---|---|
names (default) | Nothing. | No: trees only. |
stat | binary; for text, insertions and deletions in lines. | Both sides of each listed file, whole. |
unified | Also old_kind, new_kind, old_blob, new_blob and, for text, hunks. | The same. |
A side is binary when it is not UTF-8, or holds a NUL in its first 8,000 bytes; a binary file
gets no line counts and no hunks. A change of the executable bit alone, or of the kind with the
same bytes, is modified or type_changed with no hunks (hunks: []) and 0 lines either way.
A side of more than 49,152 lines, or of more than 8 MiB, is not line-diffed: no line counts, and
hunks_truncated: true.
Each hunk carries the numbers of a @@ -old_start,old_lines +new_start,new_lines @@ header and
its lines in order, each context, remove or add, the removed lines of a change before the
added ones; a line keeps its \n, and a \r is part of its line. --context (3 by default) sets
the unchanged lines around each change; --context 0 gives the changes alone.
Paths#
--path P keeps the files at or below P: a file's own path takes that file, and a directory's
everything below it. Paths match whole components (--path Zeta does not take Zeta.txt), one
trailing / is taken, and --path again adds more. An empty path is E_INVALID_ARG. Only the
directories a path reaches are read, and a subtree both sides share is never read at all.
Pages#
--limit (500 by default, at least 1) caps the files of a page. A unified page is also held
within --max-bytes (32 KiB by default, at least 1) of its files as JSON: it stops before the
first file that would take it past that, but always holds one file, whose hunks are cut to the
first ones that fit, with hunks_truncated: true. Its insertions and deletions still count
every line. names and stat pages ignore --max-bytes.
A cut page says truncated: true and gives cursor, the path of its last file; --cursor
starts the next page after that path. A file whose hunks were cut is not sent again on the next
page: to see all of it, diff it alone (--path <file>) with a larger --max-bytes, or read both
blobs with cat. A cursor that is not a repository path is E_INVALID_ARG; one that names no
listed file starts after where it would sort.
Patterns#
- What one changeset changed.
diff X~1 Xlists the changes of X against its first parent, a page at a time, whichshowcaps without a cursor. The first changeset of a history has no parent to diff against:showlists its changes. - What a change does since its base.
diff <base> <head>of an agent's work shows what alandwould publish, before the merge with what the target gained. - Cheap first, then detail. A
namespage reads no content; ask forunifiedwith--pathfor only the files you need to read. - Pin both sides. Give full ids, the
fromandtoof the first page, to every later page: the cursor is a path and does not pin the revisions, so pages ofmaincan come from two revisions if another agent lands in between. - Through MCP, the tool is
diff, withfrom,to,paths(an array),format,context,limit,cursorandmax_bytes. Ask for 100 files or fewer a call, andmax_bytesof 32,768 or less forunified: see Result size limits.
Caveats#
statandunifiedread both versions of every listed file whole, and build its hunks before the page is cut to--max-bytes, so memory and time follow the files, not the page.namesreads no content. See known limitations.--limit 0and--max-bytes 0areE_INVALID_ARG.
Guides#
- Reading and repairing history: Compare two revisions
- Reading and repairing history: Page through a large diff
- MCP integration: Result size limits
Return information#
result is a Diff (swarmops schema Diff prints its JSON Schema).
| Field | Type | Required | Description |
|---|---|---|---|
cursor | string or null | no | When truncated: where the next page starts. Opaque: pass it back as given, as the next request's cursor. |
files | array of FileDiff | yes | The files. |
from | string | yes | The changeset from named. |
to | string | yes | The changeset to named. |
truncated | boolean | yes | Whether more files follow this page. |
Envelope op: diff.
Exit codes:
0: Success.2: The request or the command line is malformed.6: Something the request names does not exist.
Errors#
- E_REV_NOT_FOUND (exit 6): A revision names no changeset.
- E_INVALID_ARG (exit 2): A malformed argument or request, including a command-line usage error.
Any command that opens a store may also fail with a store error, such as E_NOT_A_REPO, E_IO or E_STORE_CORRUPT; a command line the grammar refuses is E_INVALID_ARG (exit 2).