Skip to content

Commit d842cd1

Browse files
ferdinandybgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8102d10 commit d842cd1

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

refs.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,13 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct
21152115

21162116
int refs_update_symref(struct ref_store *refs, const char *ref,
21172117
const char *target, const char *logmsg)
2118+
{
2119+
return refs_update_symref_extended(refs, ref, target, logmsg, NULL);
2120+
}
2121+
2122+
int refs_update_symref_extended(struct ref_store *refs, const char *ref,
2123+
const char *target, const char *logmsg,
2124+
struct strbuf *referent)
21182125
{
21192126
struct ref_transaction *transaction;
21202127
struct strbuf err = STRBUF_INIT;
@@ -2125,10 +2132,22 @@ int refs_update_symref(struct ref_store *refs, const char *ref,
21252132
ref_transaction_update(transaction, ref, NULL, NULL,
21262133
target, NULL, REF_NO_DEREF,
21272134
logmsg, &err) ||
2128-
ref_transaction_commit(transaction, &err)) {
2135+
ref_transaction_prepare(transaction, &err)) {
21292136
ret = error("%s", err.buf);
2137+
goto cleanup;
21302138
}
2139+
if (referent && refs_read_symbolic_ref(refs, ref, referent) == NOT_A_SYMREF) {
2140+
struct object_id oid;
2141+
if (!refs_read_ref(refs, ref, &oid)) {
2142+
strbuf_addstr(referent, oid_to_hex(&oid));
2143+
ret = NOT_A_SYMREF;
2144+
}
2145+
}
2146+
2147+
if (ref_transaction_commit(transaction, &err))
2148+
ret = error("%s", err.buf);
21312149

2150+
cleanup:
21322151
strbuf_release(&err);
21332152
if (transaction)
21342153
ref_transaction_free(transaction);
@@ -2948,4 +2967,3 @@ int ref_update_expects_existing_old_ref(struct ref_update *update)
29482967
return (update->flags & REF_HAVE_OLD) &&
29492968
(!is_null_oid(&update->old_oid) || update->old_target);
29502969
}
2951-

refs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,10 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
584584
int refs_update_symref(struct ref_store *refs, const char *refname,
585585
const char *target, const char *logmsg);
586586

587+
int refs_update_symref_extended(struct ref_store *refs, const char *refname,
588+
const char *target, const char *logmsg,
589+
struct strbuf *referent);
590+
587591
enum action_on_err {
588592
UPDATE_REFS_MSG_ON_ERR,
589593
UPDATE_REFS_DIE_ON_ERR,

0 commit comments

Comments
 (0)