refs: introduce `.ref` field for the base iterator

The base iterator has a couple of fields that tracks the name, target, object ID and flags for the current reference. Due to this design we have to create a new `struct reference` whenever we want to hand over that reference to the callback function, which is tedious and not very efficient. Convert the structure to instead contain a `struct reference` as member. This member is expected to be populated by the implementations of the iterator and is handed over to the callback directly. While at it, simplify `should_pack_ref()` to take a `struct reference` directly instead of passing its respective fields. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Oct 23, 2025 at 09:16 UTC 89baa52da612dde6da031acfa2cb957d4297d544
8 files changed +75 -100
refs.c
+4 -4
@@ -2327,8 +2327,8 @@ int refs_optimize(struct ref_store *refs, struct pack_refs_opts *opts)
2327 int peel_iterated_oid(struct repository *r, const struct object_id *base, struct object_id *peeled)
2328 {
2329 if (current_ref_iter &&
2330 - (current_ref_iter->oid == base ||
2331 - oideq(current_ref_iter->oid, base)))
2330 + (current_ref_iter->ref.oid == base ||
2331 + oideq(current_ref_iter->ref.oid, base)))
2332 return ref_iterator_peel(current_ref_iter, peeled);
2333
2334 return peel_object(r, base, peeled) ? -1 : 0;
@@ -2703,7 +2703,7 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
2703
2704 while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
2705 if (skip &&
2706 - string_list_has_string(skip, iter->refname))
2706 + string_list_has_string(skip, iter->ref.name))
2707 continue;
2708
2709 if (transaction && ref_transaction_maybe_set_rejected(
@@ -2712,7 +2712,7 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
2712 continue;
2713
2714 strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
2715 - iter->refname, refname);
2715 + iter->ref.name, refname);
2716 goto cleanup;
2717 }
2718
refs/debug.c
+3 -5
@@ -160,11 +160,9 @@ static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator)
160 trace_printf_key(&trace_refs, "iterator_advance: (%d)\n", res);
161 else
162 trace_printf_key(&trace_refs, "iterator_advance: %s (0)\n",
163 - diter->iter->refname);
163 + diter->iter->ref.name);
164
165 - diter->base.refname = diter->iter->refname;
166 - diter->base.oid = diter->iter->oid;
167 - diter->base.flags = diter->iter->flags;
165 + diter->base.ref = diter->iter->ref;
166 return res;
167 }
168
@@ -185,7 +183,7 @@ static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator,
183 struct debug_ref_iterator *diter =
184 (struct debug_ref_iterator *)ref_iterator;
185 int res = diter->iter->vtable->peel(diter->iter, peeled);
188 - trace_printf_key(&trace_refs, "iterator_peel: %s: %d\n", diter->iter->refname, res);
186 + trace_printf_key(&trace_refs, "iterator_peel: %s: %d\n", diter->iter->ref.name, res);
187 return res;
188 }
189
refs/files-backend.c
+21 -26
@@ -961,26 +961,23 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
961
962 while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
963 if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
964 - parse_worktree_ref(iter->iter0->refname, NULL, NULL,
964 + parse_worktree_ref(iter->iter0->ref.name, NULL, NULL,
965 NULL) != REF_WORKTREE_CURRENT)
966 continue;
967
968 if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
969 - (iter->iter0->flags & REF_ISSYMREF) &&
970 - (iter->iter0->flags & REF_ISBROKEN))
969 + (iter->iter0->ref.flags & REF_ISSYMREF) &&
970 + (iter->iter0->ref.flags & REF_ISBROKEN))
971 continue;
972
973 if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
974 - !ref_resolves_to_object(iter->iter0->refname,
974 + !ref_resolves_to_object(iter->iter0->ref.name,
975 iter->repo,
976 - iter->iter0->oid,
977 - iter->iter0->flags))
976 + iter->iter0->ref.oid,
977 + iter->iter0->ref.flags))
978 continue;
979
980 - iter->base.refname = iter->iter0->refname;
981 - iter->base.oid = iter->iter0->oid;
982 - iter->base.flags = iter->iter0->flags;
983 - iter->base.referent = iter->iter0->referent;
980 + iter->base.ref = iter->iter0->ref;
981
982 return ITER_OK;
983 }
@@ -1367,30 +1364,29 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
1364 * Return true if the specified reference should be packed.
1365 */
1366 static int should_pack_ref(struct files_ref_store *refs,
1370 - const char *refname,
1371 - const struct object_id *oid, unsigned int ref_flags,
1367 + const struct reference *ref,
1368 struct pack_refs_opts *opts)
1369 {
1370 struct string_list_item *item;
1371
1372 /* Do not pack per-worktree refs: */
1377 - if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
1373 + if (parse_worktree_ref(ref->name, NULL, NULL, NULL) !=
1374 REF_WORKTREE_SHARED)
1375 return 0;
1376
1377 /* Do not pack symbolic refs: */
1382 - if (ref_flags & REF_ISSYMREF)
1378 + if (ref->flags & REF_ISSYMREF)
1379 return 0;
1380
1381 /* Do not pack broken refs: */
1386 - if (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))
1382 + if (!ref_resolves_to_object(ref->name, refs->base.repo, ref->oid, ref->flags))
1383 return 0;
1384
1389 - if (ref_excluded(opts->exclusions, refname))
1385 + if (ref_excluded(opts->exclusions, ref->name))
1386 return 0;
1387
1388 for_each_string_list_item(item, opts->includes)
1393 - if (!wildmatch(item->string, refname, 0))
1389 + if (!wildmatch(item->string, ref->name, 0))
1390 return 1;
1391
1392 return 0;
@@ -1443,8 +1439,7 @@ static int should_pack_refs(struct files_ref_store *refs,
1439 iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
1440 refs->base.repo, 0);
1441 while ((ret = ref_iterator_advance(iter)) == ITER_OK) {
1446 - if (should_pack_ref(refs, iter->refname, iter->oid,
1447 - iter->flags, opts))
1442 + if (should_pack_ref(refs, &iter->ref, opts))
1443 refcount++;
1444 if (refcount >= limit) {
1445 ref_iterator_free(iter);
@@ -1489,24 +1484,24 @@ static int files_pack_refs(struct ref_store *ref_store,
1484 * in the packed ref cache. If the reference should be
1485 * pruned, also add it to refs_to_prune.
1486 */
1492 - if (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))
1487 + if (!should_pack_ref(refs, &iter->ref, opts))
1488 continue;
1489
1490 /*
1491 * Add a reference creation for this reference to the
1492 * packed-refs transaction:
1493 */
1499 - if (ref_transaction_update(transaction, iter->refname,
1500 - iter->oid, NULL, NULL, NULL,
1494 + if (ref_transaction_update(transaction, iter->ref.name,
1495 + iter->ref.oid, NULL, NULL, NULL,
1496 REF_NO_DEREF, NULL, &err))
1497 die("failure preparing to create packed reference %s: %s",
1503 - iter->refname, err.buf);
1498 + iter->ref.name, err.buf);
1499
1500 /* Schedule the loose reference for pruning if requested. */
1501 if ((opts->flags & PACK_REFS_PRUNE)) {
1502 struct ref_to_prune *n;
1508 - FLEX_ALLOC_STR(n, name, iter->refname);
1509 - oidcpy(&n->oid, iter->oid);
1503 + FLEX_ALLOC_STR(n, name, iter->ref.name);
1504 + oidcpy(&n->oid, iter->ref.oid);
1505 n->next = refs_to_prune;
1506 refs_to_prune = n;
1507 }
@@ -2379,7 +2374,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
2374 REFNAME_ALLOW_ONELEVEL))
2375 continue;
2376
2382 - iter->base.refname = diter->relative_path;
2377 + iter->base.ref.name = diter->relative_path;
2378 return ITER_OK;
2379 }
2380
refs/iterator.c
+12 -27
@@ -41,10 +41,7 @@ void base_ref_iterator_init(struct ref_iterator *iter,
41 struct ref_iterator_vtable *vtable)
42 {
43 iter->vtable = vtable;
44 - iter->refname = NULL;
45 - iter->referent = NULL;
46 - iter->oid = NULL;
47 - iter->flags = 0;
44 + memset(&iter->ref, 0, sizeof(iter->ref));
45 }
46
47 struct empty_ref_iterator {
@@ -127,8 +124,8 @@ enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
124 * latter.
125 */
126 if (iter_worktree) {
130 - int cmp = strcmp(iter_worktree->refname,
131 - iter_common->refname);
127 + int cmp = strcmp(iter_worktree->ref.name,
128 + iter_common->ref.name);
129 if (cmp < 0)
130 return ITER_SELECT_0;
131 else if (!cmp)
@@ -139,7 +136,7 @@ enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
136 * We now know that the lexicographically-next ref is a common
137 * ref. When the common ref is a shared one we return it.
138 */
142 - if (parse_worktree_ref(iter_common->refname, NULL, NULL,
139 + if (parse_worktree_ref(iter_common->ref.name, NULL, NULL,
140 NULL) == REF_WORKTREE_SHARED)
141 return ITER_SELECT_1;
142
@@ -212,10 +209,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
209 }
210
211 if (selection & ITER_YIELD_CURRENT) {
215 - iter->base.referent = (*iter->current)->referent;
216 - iter->base.refname = (*iter->current)->refname;
217 - iter->base.oid = (*iter->current)->oid;
218 - iter->base.flags = (*iter->current)->flags;
212 + iter->base.ref = (*iter->current)->ref;
213 return ITER_OK;
214 }
215 }
@@ -313,7 +307,7 @@ static enum iterator_selection overlay_iterator_select(
307 else if (!front)
308 return ITER_SELECT_1;
309
316 - cmp = strcmp(front->refname, back->refname);
310 + cmp = strcmp(front->ref.name, back->ref.name);
311
312 if (cmp < 0)
313 return ITER_SELECT_0;
@@ -371,7 +365,7 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
365 int ok;
366
367 while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
374 - int cmp = compare_prefix(iter->iter0->refname, iter->prefix);
368 + int cmp = compare_prefix(iter->iter0->ref.name, iter->prefix);
369 if (cmp < 0)
370 continue;
371 /*
@@ -382,6 +376,8 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
376 if (cmp > 0)
377 return ITER_DONE;
378
379 + iter->base.ref = iter->iter0->ref;
380 +
381 if (iter->trim) {
382 /*
383 * It is nonsense to trim off characters that
@@ -392,15 +388,11 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
388 * one character left in the refname after
389 * trimming, report it as a bug:
390 */
395 - if (strlen(iter->iter0->refname) <= iter->trim)
391 + if (strlen(iter->base.ref.name) <= iter->trim)
392 BUG("attempt to trim too many characters");
397 - iter->base.refname = iter->iter0->refname + iter->trim;
398 - } else {
399 - iter->base.refname = iter->iter0->refname;
393 + iter->base.ref.name += iter->trim;
394 }
395
402 - iter->base.oid = iter->iter0->oid;
403 - iter->base.flags = iter->iter0->flags;
396 return ITER_OK;
397 }
398
@@ -476,14 +468,7 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
468
469 current_ref_iter = iter;
470 while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
479 - struct reference ref = {
480 - .name = iter->refname,
481 - .target = iter->referent,
482 - .oid = iter->oid,
483 - .flags = iter->flags,
484 - };
485 -
486 - retval = fn(&ref, cb_data);
471 + retval = fn(&iter->ref, cb_data);
472 if (retval)
473 goto out;
474 }
refs/packed-backend.c
+23 -23
@@ -908,7 +908,7 @@ static int next_record(struct packed_ref_iterator *iter)
908 if (iter->pos == iter->eof)
909 return ITER_DONE;
910
911 - iter->base.flags = REF_ISPACKED;
911 + iter->base.ref.flags = REF_ISPACKED;
912 p = iter->pos;
913
914 if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
@@ -923,22 +923,22 @@ static int next_record(struct packed_ref_iterator *iter)
923 iter->pos, iter->eof - iter->pos);
924
925 strbuf_add(&iter->refname_buf, p, eol - p);
926 - iter->base.refname = iter->refname_buf.buf;
926 + iter->base.ref.name = iter->refname_buf.buf;
927
928 if (refname_contains_nul(&iter->refname_buf))
929 - die("packed refname contains embedded NULL: %s", iter->base.refname);
929 + die("packed refname contains embedded NULL: %s", iter->base.ref.name);
930
931 - if (check_refname_format(iter->base.refname, REFNAME_ALLOW_ONELEVEL)) {
932 - if (!refname_is_safe(iter->base.refname))
931 + if (check_refname_format(iter->base.ref.name, REFNAME_ALLOW_ONELEVEL)) {
932 + if (!refname_is_safe(iter->base.ref.name))
933 die("packed refname is dangerous: %s",
934 - iter->base.refname);
934 + iter->base.ref.name);
935 oidclr(&iter->oid, iter->repo->hash_algo);
936 - iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN;
936 + iter->base.ref.flags |= REF_BAD_NAME | REF_ISBROKEN;
937 }
938 if (iter->snapshot->peeled == PEELED_FULLY ||
939 (iter->snapshot->peeled == PEELED_TAGS &&
940 - starts_with(iter->base.refname, "refs/tags/")))
941 - iter->base.flags |= REF_KNOWS_PEELED;
940 + starts_with(iter->base.ref.name, "refs/tags/")))
941 + iter->base.ref.flags |= REF_KNOWS_PEELED;
942
943 iter->pos = eol + 1;
944
@@ -956,11 +956,11 @@ static int next_record(struct packed_ref_iterator *iter)
956 * definitely know the value of *this* reference. But
957 * we suppress it if the reference is broken:
958 */
959 - if ((iter->base.flags & REF_ISBROKEN)) {
959 + if ((iter->base.ref.flags & REF_ISBROKEN)) {
960 oidclr(&iter->peeled, iter->repo->hash_algo);
961 - iter->base.flags &= ~REF_KNOWS_PEELED;
961 + iter->base.ref.flags &= ~REF_KNOWS_PEELED;
962 } else {
963 - iter->base.flags |= REF_KNOWS_PEELED;
963 + iter->base.ref.flags |= REF_KNOWS_PEELED;
964 }
965 } else {
966 oidclr(&iter->peeled, iter->repo->hash_algo);
@@ -976,15 +976,15 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
976 int ok;
977
978 while ((ok = next_record(iter)) == ITER_OK) {
979 - const char *refname = iter->base.refname;
979 + const char *refname = iter->base.ref.name;
980 const char *prefix = iter->prefix;
981
982 if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
983 - !is_per_worktree_ref(iter->base.refname))
983 + !is_per_worktree_ref(iter->base.ref.name))
984 continue;
985
986 if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
987 - !ref_resolves_to_object(iter->base.refname, iter->repo,
987 + !ref_resolves_to_object(iter->base.ref.name, iter->repo,
988 &iter->oid, iter->flags))
989 continue;
990
@@ -1033,10 +1033,10 @@ static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
1033 struct packed_ref_iterator *iter =
1034 (struct packed_ref_iterator *)ref_iterator;
1035
1036 - if ((iter->base.flags & REF_KNOWS_PEELED)) {
1036 + if ((iter->base.ref.flags & REF_KNOWS_PEELED)) {
1037 oidcpy(peeled, &iter->peeled);
1038 return is_null_oid(&iter->peeled) ? -1 : 0;
1039 - } else if ((iter->base.flags & (REF_ISBROKEN | REF_ISSYMREF))) {
1039 + } else if ((iter->base.ref.flags & (REF_ISBROKEN | REF_ISSYMREF))) {
1040 return -1;
1041 } else {
1042 return peel_object(iter->repo, &iter->oid, peeled) ? -1 : 0;
@@ -1194,7 +1194,7 @@ static struct ref_iterator *packed_ref_iterator_begin(
1194 iter->snapshot = snapshot;
1195 acquire_snapshot(snapshot);
1196 strbuf_init(&iter->refname_buf, 0);
1197 - iter->base.oid = &iter->oid;
1197 + iter->base.ref.oid = &iter->oid;
1198 iter->repo = ref_store->repo;
1199 iter->flags = flags;
1200
@@ -1436,7 +1436,7 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
1436 if (!iter)
1437 cmp = +1;
1438 else
1439 - cmp = strcmp(iter->refname, update->refname);
1439 + cmp = strcmp(iter->ref.name, update->refname);
1440 }
1441
1442 if (!cmp) {
@@ -1459,11 +1459,11 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
1459 }
1460
1461 goto error;
1462 - } else if (!oideq(&update->old_oid, iter->oid)) {
1462 + } else if (!oideq(&update->old_oid, iter->ref.oid)) {
1463 strbuf_addf(err, "cannot update ref '%s': "
1464 "is at %s but expected %s",
1465 update->refname,
1466 - oid_to_hex(iter->oid),
1466 + oid_to_hex(iter->ref.oid),
1467 oid_to_hex(&update->old_oid));
1468 ret = REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE;
1469
@@ -1527,8 +1527,8 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
1527 struct object_id peeled;
1528 int peel_error = ref_iterator_peel(iter, &peeled);
1529
1530 - if (write_packed_entry(out, iter->refname,
1531 - iter->oid,
1530 + if (write_packed_entry(out, iter->ref.name,
1531 + iter->ref.oid,
1532 peel_error ? NULL : &peeled))
1533 goto write_error;
1534
refs/ref-cache.c
+5 -5
@@ -425,10 +425,10 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
425 level->prefix_state = entry_prefix_state;
426 level->index = -1;
427 } else {
428 - iter->base.refname = entry->name;
429 - iter->base.referent = entry->u.value.referent;
430 - iter->base.oid = &entry->u.value.oid;
431 - iter->base.flags = entry->flag;
428 + iter->base.ref.name = entry->name;
429 + iter->base.ref.target = entry->u.value.referent;
430 + iter->base.ref.oid = &entry->u.value.oid;
431 + iter->base.ref.flags = entry->flag;
432 return ITER_OK;
433 }
434 }
@@ -550,7 +550,7 @@ static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
550 {
551 struct cache_ref_iterator *iter =
552 (struct cache_ref_iterator *)ref_iterator;
553 - return peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;
553 + return peel_object(iter->repo, ref_iterator->ref.oid, peeled) ? -1 : 0;
554 }
555
556 static void cache_ref_iterator_release(struct ref_iterator *ref_iterator)
refs/refs-internal.h
+1 -4
@@ -249,10 +249,7 @@ const char *find_descendant_ref(const char *dirname,
249 */
250 struct ref_iterator {
251 struct ref_iterator_vtable *vtable;
252 - const char *refname;
253 - const char *referent;
254 - const struct object_id *oid;
255 - unsigned int flags;
252 + struct reference ref;
253 };
254
255 /*
refs/reftable-backend.c
+6 -6
@@ -704,10 +704,10 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
704 &iter->oid, flags))
705 continue;
706
707 - iter->base.refname = iter->ref.refname;
708 - iter->base.referent = referent;
709 - iter->base.oid = &iter->oid;
710 - iter->base.flags = flags;
707 + iter->base.ref.name = iter->ref.refname;
708 + iter->base.ref.target = referent;
709 + iter->base.ref.oid = &iter->oid;
710 + iter->base.ref.flags = flags;
711
712 break;
713 }
@@ -828,7 +828,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
828
829 iter = xcalloc(1, sizeof(*iter));
830 base_ref_iterator_init(&iter->base, &reftable_ref_iterator_vtable);
831 - iter->base.oid = &iter->oid;
831 + iter->base.ref.oid = &iter->oid;
832 iter->flags = flags;
833 iter->refs = refs;
834 iter->exclude_patterns = filter_exclude_patterns(exclude_patterns);
@@ -2072,7 +2072,7 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
2072
2073 strbuf_reset(&iter->last_name);
2074 strbuf_addstr(&iter->last_name, iter->log.refname);
2075 - iter->base.refname = iter->log.refname;
2075 + iter->base.ref.name = iter->log.refname;
2076
2077 break;
2078 }