Locking
January 26, 2026 · View on GitHub
Grite uses lease-based locks stored as git refs. Locks are optional and designed for coordination, not enforcement.
Lock refs
- Ref format:
refs/grite/locks/<resource_hash> - Payload: JSON with
owner,nonce,expires_unix_ms, andresource. - Acquire by pushing a new commit to the lock ref if it is missing or expired.
Lock policy
Lock policy is configured in .git/grite/config.toml:
off: no lock checkswarn(default): warn on conflicts, but continuerequire: block write commands if a conflicting lock exists
When require is enabled, the CLI must check locks before write operations such as:
issue create/update/comment/closesnapshotsync --push
An optional pre-push hook can enforce the same policy for users who prefer git-level gating.
Namespaces and why they matter
A lock namespace is a prefix embedded in the resource string (for example repo:, path:, issue:). It defines scope and conflict policy.
Repo-wide lock (repo:)
- One lock for the entire repository.
- Used for global operations like schema migrations, large refactors, or release tasks.
- When present, it should block acquisition of any other lock type.
Path lock (path:)
- Fine-grained lock for a specific file or directory.
- Allows multiple agents to work concurrently on different areas.
- Only blocks overlapping path locks; does not block unrelated paths.
Why keep both
- Repo-wide locks provide a simple “stop the world” switch for risky operations.
- Path locks allow safe parallelism without coordinating the entire team.
- The namespace tells clients how to apply conflict rules (global vs scoped).
Example resources
repo:globalpath:src/parser.rspath:docs/issue:abcd1234
Lock lifecycle
- Acquire: create a new lock commit with a lease TTL
- Renew: push a new commit extending expiry (owner must match)
- Release: push a commit with expiry=0
- Status:
grite lock statusreports current locks and conflicts - GC:
grite lock gcremoves expired locks locally