Skip to content

Add :current_id compare-and-swap option to ReferenceCollection#create#1014

Open
JonJagger wants to merge 1 commit into
libgit2:masterfrom
JonJagger:references-create-current-id
Open

Add :current_id compare-and-swap option to ReferenceCollection#create#1014
JonJagger wants to merge 1 commit into
libgit2:masterfrom
JonJagger:references-create-current-id

Conversation

@JonJagger

@JonJagger JonJagger commented Jul 23, 2026

Copy link
Copy Markdown

Proposed in #1013.

Why

Advancing a reference atomically -- update it to a new OID only if it still
points at an expected OID -- is the one ref operation (that I need) Rugged cannot not do
in-process. I have to shell out to git update-ref <ref> <new> <old>,
even when doing everything else (index build, Rugged::Commit.create, reads)
through Rugged. libgit2 already exposes git_reference_create_matching for
exactly this; this wires it up.

What

Adds a :current_id option to Rugged::ReferenceCollection#create. When
present, it dispatches to git_reference_create_matching (compare-and-swap)
instead of git_reference_create:

repo.references.create("refs/heads/main", new_oid,
                       force: true, current_id: base_oid)

Behaviour (all covered by tests):

  • ref points at current_id -> updated, returns the new Rugged::Reference
  • ref exists but points elsewhere -> no change, returns nil (matches
    merge_trees / rebase.commit, which return nil on GIT_EMERGECONFLICT /
    GIT_EAPPLIED)
  • ref does not exist -> raises Rugged::ReferenceError
  • :current_id with a symbolic target -> ArgumentError
  • malformed :current_id -> ArgumentError

Notes

  • :current_id is only consulted for direct (OID) references; existing
    behaviour is unchanged when it is absent.
  • rdoc and CHANGELOG updated.

See #1013 for the API discussion -- happy to reshape (e.g. onto #update or a
dedicated method) if you'd prefer.

Advancing a reference atomically (update only if it still points at an
expected OID) was the one ref operation Rugged could not do in-process,
forcing callers to shell out to `git update-ref <ref> <new> <old>` even
when doing everything else through Rugged. libgit2 exposes
git_reference_create_matching for exactly this; wire it up behind a
:current_id option on #create.

A mismatch on an existing ref returns nil (like merge_trees on conflict);
an absent ref raises; a symbolic target or malformed current_id raises
ArgumentError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant