refs: add create_only option to refs_update_symref_extended

Allow the caller to specify that it only wants to update the symref if it does not already exist. Silently ignore the error from the transaction API if the symref already exists. Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Bence Ferdinandy committed Nov 22, 2024 at 13:28 UTC 9963746c841dc786529827b7b6755d0a3e208ad4
3 files changed +26 -11
builtin/remote.c
+1 -1
@@ -1476,7 +1476,7 @@ static int set_head(int argc, const char **argv, const char *prefix)
1476 goto cleanup;
1477 }
1478 was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
1479 - "remote set-head", &b_local_head);
1479 + "remote set-head", &b_local_head, 0);
1480 if (was_detached == -1) {
1481 result |= error(_("Could not set up %s"), b_head.buf);
1482 goto cleanup;
refs.c
+24 -9
@@ -2116,26 +2116,38 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct
2116 int refs_update_symref(struct ref_store *refs, const char *ref,
2117 const char *target, const char *logmsg)
2118 {
2119 - return refs_update_symref_extended(refs, ref, target, logmsg, NULL);
2119 + return refs_update_symref_extended(refs, ref, target, logmsg, NULL, 0);
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)
2124 + struct strbuf *referent, int create_only)
2125 {
2126 struct ref_transaction *transaction;
2127 struct strbuf err = STRBUF_INIT;
2128 - int ret = 0;
2128 + int ret = 0, prepret = 0;
2129
2130 transaction = ref_store_transaction_begin(refs, &err);
2131 - if (!transaction ||
2132 - ref_transaction_update(transaction, ref, NULL, NULL,
2133 - target, NULL, REF_NO_DEREF,
2134 - logmsg, &err) ||
2135 - ref_transaction_prepare(transaction, &err)) {
2131 + if (!transaction) {
2132 + error_return:
2133 ret = error("%s", err.buf);
2134 goto cleanup;
2135 }
2136 + if (create_only) {
2137 + if (ref_transaction_create(transaction, ref, NULL, target,
2138 + REF_NO_DEREF, logmsg, &err))
2139 + goto error_return;
2140 + prepret = ref_transaction_prepare(transaction, &err);
2141 + if (prepret && prepret != TRANSACTION_CREATE_EXISTS)
2142 + goto error_return;
2143 + } else {
2144 + if (ref_transaction_update(transaction, ref, NULL, NULL,
2145 + target, NULL, REF_NO_DEREF,
2146 + logmsg, &err) ||
2147 + ref_transaction_prepare(transaction, &err))
2148 + goto error_return;
2149 + }
2150 +
2151 if (referent && refs_read_symbolic_ref(refs, ref, referent) == NOT_A_SYMREF) {
2152 struct object_id oid;
2153 if (!refs_read_ref(refs, ref, &oid)) {
@@ -2144,8 +2156,11 @@ int refs_update_symref_extended(struct ref_store *refs, const char *ref,
2156 }
2157 }
2158
2159 + if (prepret == TRANSACTION_CREATE_EXISTS)
2160 + goto cleanup;
2161 +
2162 if (ref_transaction_commit(transaction, &err))
2148 - ret = error("%s", err.buf);
2163 + goto error_return;
2164
2165 cleanup:
2166 strbuf_release(&err);
refs.h
+1 -1
@@ -586,7 +586,7 @@ int refs_update_symref(struct ref_store *refs, const char *refname,
586
587 int refs_update_symref_extended(struct ref_store *refs, const char *refname,
588 const char *target, const char *logmsg,
589 - struct strbuf *referent);
589 + struct strbuf *referent, int create_only);
590
591 enum action_on_err {
592 UPDATE_REFS_MSG_ON_ERR,