SwarmOps
ReferenceCommandsswarmops ref delete
View as Markdown

swarmops ref delete#

Delete ref NAME.

Metadata
Group
refs
Since
0.1.0
Mutates
yes
Identity required
yes
MCP tool
ref_delete
Envelope op
ref_delete
Exit codes
045

Syntax#

swarmops ref delete [OPTIONS] --expect <REV> <NAME>

Required arguments#

Syntax: <NAME>.

The ref.

Syntax: --expect <REV>.

The changeset the ref holds now.

Give the full changeset id you read (from ref list, show, log or a commit's result). A ref name or a relative revision such as main~1 is read from the store when the command runs instead of pinning the id you read: the ref's own name always matches (a deleted ref errors instead), so the compare-and-swap protects nothing, and main~1 on main never matches. An id prefix pins the id you read only until another changeset shares it; then it is E_AMBIGUOUS_ID.

After E_CAS_MISMATCH, the ref holds the error's actual, which someone else moved it to: look at it (swarmops show <actual>) before you delete it with --expect <actual>.

Optional arguments#

The command also takes the global options.

Examples#

swarmops --repo [tmp]/store --as agent/worker-17 ref delete release/1.0 --expect [c1]
{
  "ok": true,
  "op": "ref_delete",
  "api": 1,
  "result": {
    "name": "release/1.0",
    "old": "[c1]",
    "already_applied": false
  },
  "meta": {
    "repo": "[tmp]/store",
    "elapsed_ms": "[elapsed_ms]",
    "resolved": {
      "[c1]": "[c1]"
    },
    "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#

ref delete removes one ref by compare-and-swap: it deletes the ref only if it still names the changeset you give as --expect. Deleting a ref removes the name only. Every changeset stays in the store, readable by id, and op undo of the deletion creates the ref again.

What happens, in order#

  1. Identity. Without --as or SWARMOPS_AGENT the command fails with E_IDENTITY_REQUIRED (exit 5) before it opens the store.
  2. The expected target. --expect is resolved as a revision first. A revision that names nothing is E_REV_NOT_FOUND (exit 6): so --expect release/1.0 on a ref that is gone fails here, before the delete is tried.
  3. The name. NAME must be main or release/<x> (letters, digits, ., _, -, not starting with ., at most 255 bytes); anything else is E_REF_NAME_INVALID (exit 1).
  4. The compare-and-swap, under the store's write lock, against the ref as committed:
The ref holdsResult
The expected changesetDeleted; old is that changeset, already_applied: false
Nothing (no such ref)Replay: already_applied: true, nothing written
Another changesetE_CAS_MISMATCH (exit 4), details.actual is what it holds

A ref that does not exist counts as deleted already, whoever deleted it, so a retry of a delete that succeeded is safe. This holds for a name that never existed too: ref delete release/typo --expect <id> succeeds with already_applied: true as long as <id> is a changeset in the store. Read already_applied when it matters whether this run deleted the ref.

On E_CAS_MISMATCH, someone moved the ref after you read it. The hint, swarmops show <actual>, only reads: look at what the ref holds now before you delete it with --expect <actual>.

Deleting main#

main can be deleted like any ref. Afterwards log without a revision, and every command given main (ls main, cat main:…), fails with E_REV_NOT_FOUND (exit 6, hint swarmops ref list), and a commit without --parent records a changeset with no parent, the root of a new history. To bring main back, op undo the deletion, or ref set main <id> --create.

After the delete#

The journal records the deletion as a ref move with no new target, with the agent's identity and the time; op log lists it as a ref_move whose move has old and no new. A ref created again under the same name starts at version 1. Durability, warnings, meta.recovered and the 10 s lock wait (E_BUSY) work as for ref set.

Patterns#

Delete a ref you just read:

OLD=$(swarmops resolve release/1.0 | jq -r '.result.id')
swarmops ref delete release/1.0 --expect "$OLD"

Take a branch imported from git into its own ref, land it on main, then delete the ref: One writer per trunk runs this sequence.

Undo a deletion: find the newest operation that deleted the ref (a move with no new) and undo it. op log lists 50 operations unless -n says otherwise; page with --before for older ones.

OP=$(swarmops op log | jq -r '[.result.ops[] | select(any(.ref_moves[]; .name == "main" and .new == null))][0].op')
swarmops op undo "$OP"

Caveats#

  • Expect a full id. A ref name or a relative revision as --expect is read when the command runs: --expect release/1.0 always matches the ref it deletes, so the compare-and-swap protects nothing. An id prefix pins the id only while no other changeset shares it.
  • No cleanup. Deleting a ref frees no space: the changesets it named, and their objects, stay.

Through MCP#

The MCP tool is ref_delete, with name and expected_old. The server refuses an expected_old that is not a full 64-hex changeset id with E_INVALID_ARG (hint swarmops ref list).

Guides#

Return information#

result is a RefSetResp (swarmops schema RefSetResp prints its JSON Schema).

FieldTypeRequiredDescription
already_appliedbooleanyesThe ref was already in the requested state, so nothing changed and a replay is safe; old and new are then the request's expected_old and new, resolved to full ids.
namestringyesThe ref.
newstring or nullnoIts target after; omitted when the ref was deleted.
oldstring or nullnoWhat the ref held before a move that was applied. On a replay (already_applied) it is expected_old as resolved, which the ref need not have held; omitted when create was given.
warningsarray of stringnoProblems found after the move became durable, such as failed housekeeping; the move itself succeeded. Omitted when empty.

Envelope op: ref_delete.

Exit codes:

  • 0: Success.
  • 4: The operation can succeed when it is run again.
  • 5: An identity or policy requirement refused the operation.

Errors#

  • E_IDENTITY_REQUIRED (exit 5): A mutation was asked for without an identity.
  • E_CAS_MISMATCH (exit 4): The ref no longer holds the expected target (or, with create, exists at another one); details.actual holds what it does, null when the ref does not exist.

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).

See also#

Edit on GitHub

On this page