[PATCH v13 3/9] refs: atomically record overwritten ref in update_symref
- From
Bence Ferdinandy <bence@ferdinandy.com>
- Date
- Nov 18, 2024, 15:09 UTC
- Message-ID
- <20241118151755.756265-4-bence@ferdinandy.com>
- In-Reply-To
- <20241118151755.756265-1-bence@ferdinandy.com>
When updating a symref with update_symref it's currently not possible to know for sure what was the previous value that was overwritten. Extend refs_update_symref under a new function name, to record the value after the ref has been locked if the caller of refs_update_symref_extended requests it via a new variable in the function call. Keep the original refs_update_symref function with the same signature, but now as a wrapper around refs_update_symref_extended.
Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com> ---
Notes:
v4: new patch
v5: - added before_target to reftables backend
- added an extra safety check for transaction's existence in refs.c
v6: - no change
v7: - remove the whole before_target concept from the backends and
handle checking it in refs.c instead (thanks Karthik)
- rename the before_target to referent which is how the same concept
is called in the backends
- change commit prefix to be more in line with project standards
v8: no change
v9: - instead of adding parameters to refs_update_symref, rename what
was in v8 as refs_update_symref_extended and make refs_update_symref
a wrapper for that. This significantly reduces the number of files
that need to be touched, and avoids adding a lot of dummy NULL-s
in unrelated places.
v10: no change
v11: no change
v12: no change
v13: if referent is a non-symbolic ref, record the hash in referent and
signal this with a return value of -1refs.c | 24 ++++++++++++++++++++++-- refs.h | 4 ++++ 2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/refs.c b/refs.c index 5f729ed412..c4500a7582 100644 --- a/refs.c +++ b/refs.c @@ -2115,6 +2115,13 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct int refs_update_symref(struct ref_store *refs, const char *ref, const char *target, const char *logmsg) +{ + return refs_update_symref_extended(refs, ref, target, logmsg, NULL); +} + +int refs_update_symref_extended(struct ref_store *refs, const char *ref, + const char *target, const char *logmsg, + struct strbuf *referent) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; @@ -2125,10 +2132,24 @@ int refs_update_symref(struct ref_store *refs, const char *ref, ref_transaction_update(transaction, ref, NULL, NULL, target, NULL, REF_NO_DEREF, logmsg, &err) || - ref_transaction_commit(transaction, &err)) { + ref_transaction_prepare(transaction, &err)) { ret = error("%s", err.buf); + goto cleanup; + } + if (referent && refs_read_symbolic_ref(refs, ref, referent) == -2) { + struct object_id oid; + if (!refs_read_ref(refs, ref, &oid)) { + strbuf_addstr(referent, oid_to_hex(&oid)); + ret = -1; + } else { + ret = 1; + } } + if (ref_transaction_commit(transaction, &err)) + ret = error("%s", err.buf); + +cleanup: strbuf_release(&err); if (transaction) ref_transaction_free(transaction); @@ -2948,4 +2969,3 @@ int ref_update_expects_existing_old_ref(struct ref_update *update) return (update->flags & REF_HAVE_OLD) && (!is_null_oid(&update->old_oid) || update->old_target); } - diff --git a/refs.h b/refs.h index f8b714ca1d..92622e807d 100644 --- a/refs.h +++ b/refs.h @@ -579,6 +579,10 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref, int refs_update_symref(struct ref_store *refs, const char *refname, const char *target, const char *logmsg); +int refs_update_symref_extended(struct ref_store *refs, const char *refname, + const char *target, const char *logmsg, + struct strbuf *referent); + enum action_on_err { UPDATE_REFS_MSG_ON_ERR, UPDATE_REFS_DIE_ON_ERR,
-- 2.47.0.296.gda1ecfef29.dirty