diff options
author | Bence Ferdinandy <bence@ferdinandy.com> | 2024-11-22 13:28:45 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2024-11-25 03:46:35 +0100 |
commit | d842cd130122c6f3d3019d467040570d7d001f7a (patch) | |
tree | 89e96dc4ee82cbcf252d10b23eaddd77c9b9f9cc /refs.c | |
parent | refs: standardize output of refs_read_symbolic_ref (diff) | |
download | git-d842cd130122c6f3d3019d467040570d7d001f7a.tar.xz git-d842cd130122c6f3d3019d467040570d7d001f7a.zip |
refs: atomically record overwritten ref in update_symref
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. Make the return
value of the function notify the caller, if the previous value was
actually not a symbolic reference. 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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 22 |
1 files changed, 20 insertions, 2 deletions
@@ -2116,6 +2116,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; int ret = 0; @@ -2125,10 +2132,22 @@ 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) == NOT_A_SYMREF) { + struct object_id oid; + if (!refs_read_ref(refs, ref, &oid)) { + strbuf_addstr(referent, oid_to_hex(&oid)); + ret = NOT_A_SYMREF; + } + } + + if (ref_transaction_commit(transaction, &err)) + ret = error("%s", err.buf); +cleanup: strbuf_release(&err); if (transaction) ref_transaction_free(transaction); @@ -2948,4 +2967,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); } - |