refs: accept symref values in `ref_transaction_update()`

The function `ref_transaction_update()` obtains ref information and flags to create a `ref_update` and add them to the transaction at hand. To extend symref support in transactions, we need to also accept the old and new ref targets and process it. This commit adds the required parameters to the function and modifies all call sites. The two parameters added are `new_target` and `old_target`. The `new_target` is used to denote what the reference should point to when the transaction is applied. Some functions allow this parameter to be NULL, meaning that the reference is not changed. The `old_target` denotes the value the reference must have before the update. Some functions allow this parameter to be NULL, meaning that the old value of the reference is not checked. We also update the internal function `ref_transaction_add_update()` similarly to take the two new parameters. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Karthik Nayak committed May 7, 2024 at 14:58 UTC 1bc4cc3fc4276203e62de610a712c8ddea45b5cf
14 files changed +71 -24
branch.c
+1 -1
@@ -627,7 +627,7 @@ void create_branch(struct repository *r,
627 if (!transaction ||
628 ref_transaction_update(transaction, ref.buf,
629 &oid, forcing ? NULL : null_oid(),
630 - 0, msg, &err) ||
630 + NULL, NULL, 0, msg, &err) ||
631 ref_transaction_commit(transaction, &err))
632 die("%s", err.buf);
633 ref_transaction_free(transaction);
builtin/fast-import.c
+3 -2
@@ -1634,7 +1634,7 @@ static int update_branch(struct branch *b)
1634 transaction = ref_transaction_begin(&err);
1635 if (!transaction ||
1636 ref_transaction_update(transaction, b->name, &b->oid, &old_oid,
1637 - 0, msg, &err) ||
1637 + NULL, NULL, 0, msg, &err) ||
1638 ref_transaction_commit(transaction, &err)) {
1639 ref_transaction_free(transaction);
1640 error("%s", err.buf);
@@ -1675,7 +1675,8 @@ static void dump_tags(void)
1675 strbuf_addf(&ref_name, "refs/tags/%s", t->name);
1676
1677 if (ref_transaction_update(transaction, ref_name.buf,
1678 - &t->oid, NULL, 0, msg, &err)) {
1678 + &t->oid, NULL, NULL, NULL,
1679 + 0, msg, &err)) {
1680 failure |= error("%s", err.buf);
1681 goto cleanup;
1682 }
builtin/fetch.c
+1 -1
@@ -667,7 +667,7 @@ static int s_update_ref(const char *action,
667
668 ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
669 check_old ? &ref->old_oid : NULL,
670 - 0, msg, &err);
670 + NULL, NULL, 0, msg, &err);
671 if (ret) {
672 ret = STORE_REF_ERROR_OTHER;
673 goto out;
builtin/receive-pack.c
+1
@@ -1595,6 +1595,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
1595 if (ref_transaction_update(transaction,
1596 namespaced_name,
1597 new_oid, old_oid,
1598 + NULL, NULL,
1599 0, "push",
1600 &err)) {
1601 rp_error("%s", err.buf);
builtin/replace.c
+1 -1
@@ -201,7 +201,7 @@ static int replace_object_oid(const char *object_ref,
201 transaction = ref_transaction_begin(&err);
202 if (!transaction ||
203 ref_transaction_update(transaction, ref.buf, repl, &prev,
204 - 0, NULL, &err) ||
204 + NULL, NULL, 0, NULL, &err) ||
205 ref_transaction_commit(transaction, &err))
206 res = error("%s", err.buf);
207
builtin/tag.c
+1
@@ -660,6 +660,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
660 transaction = ref_transaction_begin(&err);
661 if (!transaction ||
662 ref_transaction_update(transaction, ref.buf, &object, &prev,
663 + NULL, NULL,
664 create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
665 reflog_msg.buf, &err) ||
666 ref_transaction_commit(transaction, &err)) {
builtin/update-ref.c
+1
@@ -204,6 +204,7 @@ static void parse_cmd_update(struct ref_transaction *transaction,
204
205 if (ref_transaction_update(transaction, refname,
206 &new_oid, have_old ? &old_oid : NULL,
207 + NULL, NULL,
208 update_flags | create_reflog_flag,
209 msg, &err))
210 die("%s", err.buf);
refs.c
+17 -5
@@ -1228,6 +1228,7 @@ struct ref_update *ref_transaction_add_update(
1228 const char *refname, unsigned int flags,
1229 const struct object_id *new_oid,
1230 const struct object_id *old_oid,
1231 + const char *new_target, const char *old_target,
1232 const char *msg)
1233 {
1234 struct ref_update *update;
@@ -1235,6 +1236,11 @@ struct ref_update *ref_transaction_add_update(
1236 if (transaction->state != REF_TRANSACTION_OPEN)
1237 BUG("update called for transaction that is not open");
1238
1239 + if (old_oid && old_target)
1240 + BUG("only one of old_oid and old_target should be non NULL");
1241 + if (new_oid && new_target)
1242 + BUG("only one of new_oid and new_target should be non NULL");
1243 +
1244 FLEX_ALLOC_STR(update, refname, refname);
1245 ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
1246 transaction->updates[transaction->nr++] = update;
@@ -1253,6 +1259,8 @@ int ref_transaction_update(struct ref_transaction *transaction,
1259 const char *refname,
1260 const struct object_id *new_oid,
1261 const struct object_id *old_oid,
1262 + const char *new_target,
1263 + const char *old_target,
1264 unsigned int flags, const char *msg,
1265 struct strbuf *err)
1266 {
@@ -1280,7 +1288,8 @@ int ref_transaction_update(struct ref_transaction *transaction,
1288 flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
1289
1290 ref_transaction_add_update(transaction, refname, flags,
1283 - new_oid, old_oid, msg);
1291 + new_oid, old_oid, new_target,
1292 + old_target, msg);
1293 return 0;
1294 }
1295
@@ -1295,7 +1304,8 @@ int ref_transaction_create(struct ref_transaction *transaction,
1304 return 1;
1305 }
1306 return ref_transaction_update(transaction, refname, new_oid,
1298 - null_oid(), flags, msg, err);
1307 + null_oid(), NULL, NULL, flags,
1308 + msg, err);
1309 }
1310
1311 int ref_transaction_delete(struct ref_transaction *transaction,
@@ -1308,7 +1318,8 @@ int ref_transaction_delete(struct ref_transaction *transaction,
1318 BUG("delete called with old_oid set to zeros");
1319 return ref_transaction_update(transaction, refname,
1320 null_oid(), old_oid,
1311 - flags, msg, err);
1321 + NULL, NULL, flags,
1322 + msg, err);
1323 }
1324
1325 int ref_transaction_verify(struct ref_transaction *transaction,
@@ -1321,6 +1332,7 @@ int ref_transaction_verify(struct ref_transaction *transaction,
1332 BUG("verify called with old_oid set to NULL");
1333 return ref_transaction_update(transaction, refname,
1334 NULL, old_oid,
1335 + NULL, NULL,
1336 flags, NULL, err);
1337 }
1338
@@ -1335,8 +1347,8 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
1347
1348 t = ref_store_transaction_begin(refs, &err);
1349 if (!t ||
1338 - ref_transaction_update(t, refname, new_oid, old_oid, flags, msg,
1339 - &err) ||
1350 + ref_transaction_update(t, refname, new_oid, old_oid, NULL, NULL,
1351 + flags, msg, &err) ||
1352 ref_transaction_commit(t, &err)) {
1353 ret = 1;
1354 ref_transaction_free(t);
refs.h
+17 -1
@@ -648,6 +648,16 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
648 * before the update. A copy of this value is made in the
649 * transaction.
650 *
651 + * new_target -- the target reference that the reference will be
652 + * updated to point to. If the reference is a regular reference,
653 + * it will be converted to a symbolic reference. Cannot be set
654 + * together with `new_oid`. A copy of this value is made in the
655 + * transaction.
656 + *
657 + * old_target -- the reference that the reference must be pointing to.
658 + * Canont be set together with `old_oid`. A copy of this value is
659 + * made in the transaction.
660 + *
661 * flags -- flags affecting the update, passed to
662 * update_ref_lock(). Possible flags: REF_NO_DEREF,
663 * REF_FORCE_CREATE_REFLOG. See those constants for more
@@ -713,7 +723,11 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
723 * beforehand. The old value is checked after the lock is taken to
724 * prevent races. If the old value doesn't agree with old_oid, the
725 * whole transaction fails. If old_oid is NULL, then the previous
716 - * value is not checked.
726 + * value is not checked. If `old_target` is not NULL, treat the reference
727 + * as a symbolic ref and validate that its target before the update is
728 + * `old_target`. If the `new_target` is not NULL, then the reference
729 + * will be updated to a symbolic ref which targets `new_target`.
730 + * Together, these allow us to update between regular refs and symrefs.
731 *
732 * See the above comment "Reference transaction updates" for more
733 * information.
@@ -722,6 +736,8 @@ int ref_transaction_update(struct ref_transaction *transaction,
736 const char *refname,
737 const struct object_id *new_oid,
738 const struct object_id *old_oid,
739 + const char *new_target,
740 + const char *old_target,
741 unsigned int flags, const char *msg,
742 struct strbuf *err);
743
refs/files-backend.c
+6 -6
@@ -1198,7 +1198,7 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)
1198 ref_transaction_add_update(
1199 transaction, r->name,
1200 REF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING,
1201 - null_oid(), &r->oid, NULL);
1201 + null_oid(), &r->oid, NULL, NULL, NULL);
1202 if (ref_transaction_commit(transaction, &err))
1203 goto cleanup;
1204
@@ -1292,7 +1292,7 @@ static int files_pack_refs(struct ref_store *ref_store,
1292 * packed-refs transaction:
1293 */
1294 if (ref_transaction_update(transaction, iter->refname,
1295 - iter->oid, NULL,
1295 + iter->oid, NULL, NULL, NULL,
1296 REF_NO_DEREF, NULL, &err))
1297 die("failure preparing to create packed reference %s: %s",
1298 iter->refname, err.buf);
@@ -2309,7 +2309,7 @@ static int split_head_update(struct ref_update *update,
2309 transaction, "HEAD",
2310 update->flags | REF_LOG_ONLY | REF_NO_DEREF,
2311 &update->new_oid, &update->old_oid,
2312 - update->msg);
2312 + NULL, NULL, update->msg);
2313
2314 /*
2315 * Add "HEAD". This insertion is O(N) in the transaction
@@ -2372,7 +2372,7 @@ static int split_symref_update(struct ref_update *update,
2372 new_update = ref_transaction_add_update(
2373 transaction, referent, new_flags,
2374 &update->new_oid, &update->old_oid,
2375 - update->msg);
2375 + NULL, NULL, update->msg);
2376
2377 new_update->parent_update = update;
2378
@@ -2763,7 +2763,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
2763 packed_transaction, update->refname,
2764 REF_HAVE_NEW | REF_NO_DEREF,
2765 &update->new_oid, NULL,
2766 - NULL);
2766 + NULL, NULL, NULL);
2767 }
2768 }
2769
@@ -3048,7 +3048,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
3048 ref_transaction_add_update(packed_transaction, update->refname,
3049 update->flags & ~REF_HAVE_OLD,
3050 &update->new_oid, &update->old_oid,
3051 - NULL);
3051 + NULL, NULL, NULL);
3052 }
3053
3054 if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
refs/refs-internal.h
+14
@@ -124,6 +124,19 @@ struct ref_update {
124 */
125 struct object_id old_oid;
126
127 + /*
128 + * If set, point the reference to this value. This can also be
129 + * used to convert regular references to become symbolic refs.
130 + * Cannot be set together with `new_oid`.
131 + */
132 + const char *new_target;
133 +
134 + /*
135 + * If set, check that the reference previously pointed to this
136 + * value. Cannot be set together with `old_oid`.
137 + */
138 + const char *old_target;
139 +
140 /*
141 * One or more of REF_NO_DEREF, REF_FORCE_CREATE_REFLOG,
142 * REF_HAVE_NEW, REF_HAVE_OLD, or backend-specific flags.
@@ -173,6 +186,7 @@ struct ref_update *ref_transaction_add_update(
186 const char *refname, unsigned int flags,
187 const struct object_id *new_oid,
188 const struct object_id *old_oid,
189 + const char *new_target, const char *old_target,
190 const char *msg);
191
192 /*
refs/reftable-backend.c
+2 -2
@@ -826,7 +826,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
826 new_update = ref_transaction_add_update(
827 transaction, "HEAD",
828 u->flags | REF_LOG_ONLY | REF_NO_DEREF,
829 - &u->new_oid, &u->old_oid, u->msg);
829 + &u->new_oid, &u->old_oid, NULL, NULL, u->msg);
830 string_list_insert(&affected_refnames, new_update->refname);
831 }
832
@@ -905,7 +905,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
905 */
906 new_update = ref_transaction_add_update(
907 transaction, referent.buf, new_flags,
908 - &u->new_oid, &u->old_oid, u->msg);
908 + &u->new_oid, &u->old_oid, NULL, NULL, u->msg);
909 new_update->parent_update = u;
910
911 /*
sequencer.c
+5 -4
@@ -616,7 +616,7 @@ static int fast_forward_to(struct repository *r,
616 if (!transaction ||
617 ref_transaction_update(transaction, "HEAD",
618 to, unborn && !is_rebase_i(opts) ?
619 - null_oid() : from,
619 + null_oid() : from, NULL, NULL,
620 0, sb.buf, &err) ||
621 ref_transaction_commit(transaction, &err)) {
622 ref_transaction_free(transaction);
@@ -1248,7 +1248,7 @@ int update_head_with_reflog(const struct commit *old_head,
1248 if (!transaction ||
1249 ref_transaction_update(transaction, "HEAD", new_head,
1250 old_head ? &old_head->object.oid : null_oid(),
1251 - 0, sb.buf, err) ||
1251 + NULL, NULL, 0, sb.buf, err) ||
1252 ref_transaction_commit(transaction, err)) {
1253 ret = -1;
1254 }
@@ -3764,8 +3764,9 @@ static int do_label(struct repository *r, const char *name, int len)
3764 } else if (repo_get_oid(r, "HEAD", &head_oid)) {
3765 error(_("could not read HEAD"));
3766 ret = -1;
3767 - } else if (ref_transaction_update(transaction, ref_name.buf, &head_oid,
3768 - NULL, 0, msg.buf, &err) < 0 ||
3767 + } else if (ref_transaction_update(transaction, ref_name.buf,
3768 + &head_oid, NULL, NULL, NULL,
3769 + 0, msg.buf, &err) < 0 ||
3770 ref_transaction_commit(transaction, &err)) {
3771 error("%s", err.buf);
3772 ret = -1;
walker.c
+1 -1
@@ -324,7 +324,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
324 strbuf_reset(&refname);
325 strbuf_addf(&refname, "refs/%s", write_ref[i]);
326 if (ref_transaction_update(transaction, refname.buf,
327 - oids + i, NULL, 0,
327 + oids + i, NULL, NULL, NULL, 0,
328 msg ? msg : "fetch (unknown)",
329 &err)) {
330 error("%s", err.buf);