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
}