Skip to main content

Module refs

Module refs 

Source
Expand description

Refs subsystem.

Implements the local-disk side of docs/specs/SPEC-REFS.md: ref names, the 65-byte wire encoding, the symbolic-or-detached HEAD file, and shallow-boundary persistence at .mkit/shallow.

Wire format (per SPEC-REFS §1): exactly 64 lowercase-hex characters plus a trailing 0x0A newline = 65 bytes. Uppercase hex is rejected on read. Trailing \r and ASCII whitespace are tolerated when parsing local files (so a Windows-edited HEAD does not brick a repo), but fresh writes always emit the strict 65-byte form.

Ref name grammar (SPEC-REFS §3): [A-Za-z0-9._-]+ segments joined by /, with no leading/trailing /, no ./.. segments, no backslashes, no NULs. In addition, no segment may end in .lock (the canonical lock-file suffix) and the final segment may not be the literal HEAD (which would shadow the repo-level HEAD pointer). We share the validator with the future transport layer via validate_ref_name / validate_ref_prefix.

CAS variants for update_ref follow SPEC-REFS §5: Any (clobber), Missing (fail if it exists), Match(H) (fail if current value != H). As of #637, the local-filesystem Match read-compare-write is serialized under a shared refs.lock in the common dir (the same blocking kernel-lock primitive repo_lock uses elsewhere), so it is atomic across processes regardless of what other locks each caller holds — this closes the v1 gap previously documented here.

Structs§

Ref
A listed ref entry: name (with refs/heads/ or similar prefix stripped) plus the resolved hash, when readable.
RemoteRefBatch
Batched writer for remote-tracking refs (#645): amortises the parent-directory fsync across every ref written into it, instead of paying one per ref like write_remote_ref in a loop.

Enums§

Head
HEAD pointer: either a symbolic reference to a branch name, or a detached hash.
RefError
Errors raised by this module.
RefWriteCondition
CAS condition for update_ref.

Constants§

HEADS_DIR
Subdirectory holding branch refs (.mkit/refs/heads).
HEAD_FILE
HEAD file relative to the .mkit root.
REFS_DIR
Subdirectory holding all refs (.mkit/refs).
REMOTES_DIR
Subdirectory holding remote-tracking refs (.mkit/refs/remotes).
SHALLOW_FILE
Shallow-boundary file relative to the .mkit root.
TAGS_DIR
Subdirectory holding tag refs (.mkit/refs/tags).

Functions§

decode_ref_wire
Decode a ref wire blob into a Hash. Tolerates a trailing newline / \r / ASCII whitespace (so files round-tripped through a Windows editor still parse), but rejects uppercase hex per SPEC-REFS §1.
delete_ref
Delete a branch ref. Errors with RefError::NotFound if absent.
delete_ref_if_matches
CAS-guarded delete: removes a branch ref only if its current on-disk value is exactly expected. Issue #658.
delete_ref_safe
Delete a branch ref unless it is the currently checked-out branch.
delete_ref_safe_with_history
delete_ref_with_history guarded by the same current-branch check as delete_ref_safe — refuses to delete (and does not touch the journal of) the branch HEAD currently points at. This is the history-mmr counterpart mkit branch -d/-D route through.
delete_ref_with_history
Delete a branch ref and permanently destroy its history-MMR journal partition, so a later branch created with the same name never resumes a deleted incarnation’s leaves (issue #648).
delete_ref_with_history_if_matches
delete_ref_with_history, but CAS-guarded like delete_ref_if_matches: only deletes (and destroys the journal of) branch if its current on-disk value is exactly expected. Issue #658 — the history-mmr counterpart mkit branch -m routes through so a rename’s rollback of a lost race also drops the correct journal.
delete_remote_ref
Delete a remote-tracking branch ref (e.g. after the upstream deleted the branch). Errors with RefError::NotFound if absent.
delete_tag
Delete a tag ref.
encode_ref_wire
Encode h to its 65-byte wire form (lowercase hex + \n).
init
Initialise the ref layout: creates refs/, refs/heads/, refs/tags/, refs/remotes/ under the common dir and writes a default HEAD = ref: refs/heads/main\n into the worktree state dir if HEAD does not already exist.
list_refs
List all branch refs, sorted lexicographically by name.
list_remote_names
List the remote names that have at least one tracking ref on disk (the immediate subdirectories of refs/remotes/), sorted. A missing refs/remotes/ yields an empty list. Entries whose names fail the ref grammar are skipped (consistent with how malformed ref files are skipped by list_refs).
list_remote_refs
List all remote-tracking refs for one remote.
list_tags
List all tag refs, sorted lexicographically by name.
load_shallow_boundaries
Load shallow-boundary hashes from .mkit/shallow. Returns Ok(None) if the file does not exist or is empty.
open_and_update_ref_with_history_and_backfill
update_ref_with_history_and_backfill, but closes a race that shape leaves open when two concurrent writers have never touched branch’s journal before: CommitHistory::open_at runs AFTER the per-branch lock is acquired here, not before, so a concurrent writer already holding the lock can never be mid-sync (writing the on-disk metadata blob) while this call’s own open_at reads it — see this module’s private update_ref_with_history_critical_section helper’s doc comment for the full mechanism. mkit-cli’s write_ref_recording_history is the production caller.
parse_lowercase_hash
Strict lowercase-only hex parser: exactly HEX_LEN lowercase-hex bytes, decoded in a single pass. SPEC-REFS §1 forbids uppercase on read; the general hash::from_hex tolerates both cases for programmatic callers, so this is the stricter variant every on-the-wire / on-disk reader (ref wire blobs, the applied-packs record) shares to keep a hand-edited or foreign-cased line malformed rather than silently accepted.
read_head
Read this worktree’s HEAD.
read_ref
Read the hash a branch ref points to. Returns Ok(None) if the ref file does not exist.
read_remote_ref
Read a remote-tracking branch ref.
read_tag
Read the hash a tag points to.
resolve_head
Resolve HEAD to a commit hash. Returns Ok(None) when HEAD points at a branch that has no commit yet.
update_head
Update the ref HEAD currently points at (or HEAD itself, if detached) to commit_hash.
update_ref
CAS-aware ref write per SPEC-REFS §5.
update_ref_with_history
Combined ref-write + history-MMR-append, protected by a single repo-level lock. Issue #157.
update_ref_with_history_and_backfill
update_ref_with_history, additionally backfilling an empty journal from parent_of before the CAS-write + append — all inside the SAME refs-history.lock acquisition (issue #638 / INV-18).
update_tag
CAS-aware tag write — same semantics as update_ref but for refs/tags/.
validate_ref_name
Validate a ref name per SPEC-REFS §3. Used at every transport boundary; transports MUST NOT silently lower-case or canonicalise.
validate_ref_prefix
Validate a prefix passed to list_refs. An empty prefix is allowed. A single trailing / is allowed; otherwise the prefix must satisfy validate_ref_name.
write_head_branch
Write HEAD as a symbolic ref pointing at branch.
write_head_detached
Write HEAD as a detached hash.
write_ref
Write a branch ref (unconditional — equivalent to update_ref(branch, RefWriteCondition::Any, h)).
write_remote_ref
Write a remote-tracking branch ref unconditionally.
write_shallow_boundaries
Write shallow-boundary hashes to .mkit/shallow. Passing an empty slice removes the file.
write_tag
Write a tag ref (unconditional).

Type Aliases§

RefResult
Result alias used throughout this module.