refs: add TRANSACTION_CREATE_EXISTS error

Currently there is only one special error for transaction, for when there is a naming conflict, all other errors are dumped under a generic error. Add a new special error case for when the caller requests the reference to be updated only when it does not yet exist and the reference actually does exist. 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 ed2f6f8804cc142a02c701e808d110223b0256f8
3 files changed +23 -11
refs.h
+3 -1
@@ -773,8 +773,10 @@ int ref_transaction_verify(struct ref_transaction *transaction,
773
774 /* Naming conflict (for example, the ref names A and A/B conflict). */
775 #define TRANSACTION_NAME_CONFLICT -1
776 +/* When only creation was requested, but the ref already exists. */
777 +#define TRANSACTION_CREATE_EXISTS -2
778 /* All other errors. */
777 -#define TRANSACTION_GENERIC_ERROR -2
779 +#define TRANSACTION_GENERIC_ERROR -3
780
781 /*
782 * Perform the preparatory stages of committing `transaction`. Acquire
refs/files-backend.c
+16 -8
@@ -2501,14 +2501,18 @@ static int split_symref_update(struct ref_update *update,
2501 static int check_old_oid(struct ref_update *update, struct object_id *oid,
2502 struct strbuf *err)
2503 {
2504 + int ret = TRANSACTION_GENERIC_ERROR;
2505 +
2506 if (!(update->flags & REF_HAVE_OLD) ||
2507 oideq(oid, &update->old_oid))
2508 return 0;
2509
2508 - if (is_null_oid(&update->old_oid))
2510 + if (is_null_oid(&update->old_oid)) {
2511 strbuf_addf(err, "cannot lock ref '%s': "
2512 "reference already exists",
2513 ref_update_original_update_refname(update));
2514 + ret = TRANSACTION_CREATE_EXISTS;
2515 + }
2516 else if (is_null_oid(oid))
2517 strbuf_addf(err, "cannot lock ref '%s': "
2518 "reference is missing but expected %s",
@@ -2521,7 +2525,7 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
2525 oid_to_hex(oid),
2526 oid_to_hex(&update->old_oid));
2527
2524 - return -1;
2528 + return ret;
2529 }
2530
2531 /*
@@ -2601,9 +2605,11 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2605 ret = TRANSACTION_GENERIC_ERROR;
2606 goto out;
2607 }
2604 - } else if (check_old_oid(update, &lock->old_oid, err)) {
2605 - ret = TRANSACTION_GENERIC_ERROR;
2606 - goto out;
2608 + } else {
2609 + ret = check_old_oid(update, &lock->old_oid, err);
2610 + if (ret) {
2611 + goto out;
2612 + }
2613 }
2614 } else {
2615 /*
@@ -2634,9 +2640,11 @@ static int lock_ref_for_update(struct files_ref_store *refs,
2640 update->old_target);
2641 ret = TRANSACTION_GENERIC_ERROR;
2642 goto out;
2637 - } else if (check_old_oid(update, &lock->old_oid, err)) {
2638 - ret = TRANSACTION_GENERIC_ERROR;
2639 - goto out;
2643 + } else {
2644 + ret = check_old_oid(update, &lock->old_oid, err);
2645 + if (ret) {
2646 + goto out;
2647 + }
2648 }
2649
2650 /*
refs/reftable-backend.c
+4 -2
@@ -1208,10 +1208,13 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1208 goto done;
1209 }
1210 } else if ((u->flags & REF_HAVE_OLD) && !oideq(&current_oid, &u->old_oid)) {
1211 - if (is_null_oid(&u->old_oid))
1211 + ret = TRANSACTION_NAME_CONFLICT;
1212 + if (is_null_oid(&u->old_oid)) {
1213 strbuf_addf(err, _("cannot lock ref '%s': "
1214 "reference already exists"),
1215 ref_update_original_update_refname(u));
1216 + ret = TRANSACTION_CREATE_EXISTS;
1217 + }
1218 else if (is_null_oid(&current_oid))
1219 strbuf_addf(err, _("cannot lock ref '%s': "
1220 "reference is missing but expected %s"),
@@ -1223,7 +1226,6 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1226 ref_update_original_update_refname(u),
1227 oid_to_hex(&current_oid),
1228 oid_to_hex(&u->old_oid));
1226 - ret = -1;
1229 goto done;
1230 }
1231