Expose libgit2's git_reference_create_matching (atomic compare-and-swap ref update)
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 2.3k
- Forks
- 293
- PR merge metrics
- No merged PRs in 30d
Description
Motivation
I'd like to advance a reference atomically from in-process Rugged, the way
git update-ref <ref> <new-oid> <old-oid> does on the command line: update the
ref to a new OID only if it still points at the OID I expect. This is the one
operation that currently forces a service doing everything else in-process
(index build, Rugged::Commit.create, reads) to shell out to git.
libgit2 has the primitive -- git_reference_create_matching, which takes a
current_id and returns GIT_EMODIFIED if the ref has moved -- but Rugged
doesn't currently surface it. ReferenceCollection#create calls plain
git_reference_create, and #update uses git_reference_set_target; neither
lets the caller pass an expected current value.
Proposed API
Add a :current_id option to ReferenceCollection#create, dispatching to
git_reference_create_matching when present:
# advance refs/heads/main to new_oid only if it still points at base_oid
repo.references.create("refs/heads/main", new_oid,
force: true, current_id: base_oid)
Outcomes:
- ref points at
current_id-> updated, returns the newRugged::Reference - ref exists but points elsewhere -> no change, returns
nil(this mirrors how
merge_treesreturnsnilonGIT_EMERGECONFLICTandrebase.commiton
GIT_EAPPLIED-- a CAS miss is an expected outcome under concurrency, not an
error) - ref does not exist -> raises
Rugged::ReferenceError(libgit2's not-found) :current_idwith a symbolic target ->ArgumentError(CAS is OID-only)
Open question
Is create the right home for this, or would you prefer it on #update, or a
dedicated method? I put it on create because that mirrors libgit2's own
naming (..._create_matching) and handles both create-if-absent and
conditional-update in one call, but I'm happy to reshape it to whatever fits
Rugged's conventions best.
Status
I'm opening a PR alongside this issue (thin C wrapper + tests covering all the
outcomes above + CHANGELOG/rdoc). Happy to rework the API shape before it's
merged if you'd prefer a different form.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ReferenceCollection#create and compare it with #update and the existing libgit2 bindings. Add coverage for the current_id outcomes described in the issue, including symbolic targets, then update the CHANGELOG and rdoc; done means the proposed API behavior is tested and documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, ruby
- Domain
- backend-api-design, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100