diff mbox series

[v13,7/9] refs: add create_only option to refs_update_symref_extended

Message ID 20241118151755.756265-8-bence@ferdinandy.com (mailing list archive)
State New
Headers show
Series set-head/fetch remote/HEAD updates | expand

Commit Message

Bence Ferdinandy Nov. 18, 2024, 3:09 p.m. UTC
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>
---

Notes:
    v4: new patch
    v5: no change
    
    v6: - switched from bool to int for create_only
        - refactored logic in refs_update_symref with goto as layed out by
          Junio
    
    v7: - change commit prefix to be more in line with project standards
        - refactored code to accommodate changes in the first patch, but
          otherwise no change
    
    v8: no change
    
    v9: - no change (except for following through the
          refs_update_symref_extended refactoring)
    
    v10: no change
    
    v11: no change
    
    v12: no change
    
    v13: changes only due to changes in previous patch

 builtin/remote.c |  2 +-
 refs.c           | 33 ++++++++++++++++++++++++---------
 refs.h           |  2 +-
 3 files changed, 26 insertions(+), 11 deletions(-)

Comments

Junio C Hamano Nov. 19, 2024, 2:54 a.m. UTC | #1
Bence Ferdinandy <bence@ferdinandy.com> writes:

> 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.

Because it is not even an error, from the point of view of "create
only if it does not exist", checking the current condition and
finding that there already is one, this makes perfect sense.
diff mbox series

Patch

diff --git a/builtin/remote.c b/builtin/remote.c
index a682ef5df2..7b4eb0e30b 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1476,7 +1476,7 @@  static int set_head(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 	}
 	updateres = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
-			"remote set-head", &b_local_head);
+			"remote set-head", &b_local_head, 0);
 	if (updateres == -2) {
 		result |= error(_("Could not setup %s"), b_head.buf);
 		goto cleanup;
diff --git a/refs.c b/refs.c
index c4500a7582..f4d8a8dcb1 100644
--- a/refs.c
+++ b/refs.c
@@ -2116,26 +2116,38 @@  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);
+	return refs_update_symref_extended(refs, ref, target, logmsg, NULL, 0);
 }
 
 int refs_update_symref_extended(struct ref_store *refs, const char *ref,
 		       const char *target, const char *logmsg,
-		       struct strbuf *referent)
+		       struct strbuf *referent, int create_only)
 {
 	struct ref_transaction *transaction;
 	struct strbuf err = STRBUF_INIT;
-	int ret = 0;
+	int ret = 0, prepret = 0;
 
 	transaction = ref_store_transaction_begin(refs, &err);
-	if (!transaction ||
-	    ref_transaction_update(transaction, ref, NULL, NULL,
-				   target, NULL, REF_NO_DEREF,
-				   logmsg, &err) ||
-	    ref_transaction_prepare(transaction, &err)) {
+	if (!transaction) {
+	error_return:
 		ret = error("%s", err.buf);
 		goto cleanup;
 	}
+	if (create_only) {
+		if (ref_transaction_create(transaction, ref, NULL, target,
+					   REF_NO_DEREF, logmsg, &err))
+			goto error_return;
+		prepret = ref_transaction_prepare(transaction, &err);
+		if (prepret && prepret != TRANSACTION_CREATE_EXISTS)
+			goto error_return;
+	} else {
+		if (ref_transaction_update(transaction, ref, NULL, NULL,
+					   target, NULL, REF_NO_DEREF,
+					   logmsg, &err) ||
+			ref_transaction_prepare(transaction, &err))
+			goto error_return;
+	}
+
 	if (referent && refs_read_symbolic_ref(refs, ref, referent) == -2) {
 		struct object_id oid;
 		if (!refs_read_ref(refs, ref, &oid)) {
@@ -2146,8 +2158,11 @@  int refs_update_symref_extended(struct ref_store *refs, const char *ref,
 		}
 	}
 
+	if (prepret == TRANSACTION_CREATE_EXISTS)
+		goto cleanup;
+
 	if (ref_transaction_commit(transaction, &err))
-		ret = error("%s", err.buf);
+		goto error_return;
 
 cleanup:
 	strbuf_release(&err);
diff --git a/refs.h b/refs.h
index 6a32f82f8c..f131e89fe6 100644
--- a/refs.h
+++ b/refs.h
@@ -581,7 +581,7 @@  int refs_update_symref(struct ref_store *refs, const char *refname,
 
 int refs_update_symref_extended(struct ref_store *refs, const char *refname,
 		       const char *target, const char *logmsg,
-		       struct strbuf *referent);
+		       struct strbuf *referent, int create_only);
 
 enum action_on_err {
 	UPDATE_REFS_MSG_ON_ERR,