packfile: introduce macro to iterate through packs

We have a bunch of different sites that want to iterate through all packs of a given `struct packfile_store`. This pattern is somewhat verbose and repetitive, which makes it somewhat cumbersome. Introduce a new macro `repo_for_each_pack()` that removes some of the boilerplate. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Oct 9, 2025 at 10:01 UTC 86d8c62f48a1b193299de19c4dbc664650a853f1
20 files changed +57 -75
builtin/cat-file.c
+1 -2
@@ -852,10 +852,9 @@ static void batch_each_object(struct batch_options *opt,
852
853 if (bitmap && !for_each_bitmapped_object(bitmap, &opt->objects_filter,
854 batch_one_object_bitmapped, &payload)) {
855 - struct packfile_store *packs = the_repository->objects->packfiles;
855 struct packed_git *pack;
856
858 - for (pack = packfile_store_get_all_packs(packs); pack; pack = pack->next) {
857 + repo_for_each_pack(the_repository, pack) {
858 if (bitmap_index_contains_pack(bitmap, pack) ||
859 open_pack_index(pack))
860 continue;
builtin/count-objects.c
+1 -2
@@ -122,7 +122,6 @@ int cmd_count_objects(int argc,
122 count_loose, count_cruft, NULL, NULL);
123
124 if (verbose) {
125 - struct packfile_store *packs = the_repository->objects->packfiles;
125 struct packed_git *p;
126 unsigned long num_pack = 0;
127 off_t size_pack = 0;
@@ -130,7 +129,7 @@ int cmd_count_objects(int argc,
129 struct strbuf pack_buf = STRBUF_INIT;
130 struct strbuf garbage_buf = STRBUF_INIT;
131
133 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
132 + repo_for_each_pack(the_repository, p) {
133 if (!p->pack_local)
134 continue;
135 if (open_pack_index(p))
builtin/fsck.c
+6 -9
@@ -867,20 +867,20 @@ static int mark_packed_for_connectivity(const struct object_id *oid,
867
868 static int check_pack_rev_indexes(struct repository *r, int show_progress)
869 {
870 - struct packfile_store *packs = r->objects->packfiles;
870 struct progress *progress = NULL;
871 + struct packed_git *p;
872 uint32_t pack_count = 0;
873 int res = 0;
874
875 if (show_progress) {
876 - for (struct packed_git *p = packfile_store_get_all_packs(packs); p; p = p->next)
876 + repo_for_each_pack(r, p)
877 pack_count++;
878 progress = start_delayed_progress(the_repository,
879 "Verifying reverse pack-indexes", pack_count);
880 pack_count = 0;
881 }
882
883 - for (struct packed_git *p = packfile_store_get_all_packs(packs); p; p = p->next) {
883 + repo_for_each_pack(r, p) {
884 int load_error = load_pack_revindex_from_disk(p);
885
886 if (load_error < 0) {
@@ -1000,8 +1000,6 @@ int cmd_fsck(int argc,
1000 for_each_packed_object(the_repository,
1001 mark_packed_for_connectivity, NULL, 0);
1002 } else {
1003 - struct packfile_store *packs = the_repository->objects->packfiles;
1004 -
1003 odb_prepare_alternates(the_repository->objects);
1004 for (source = the_repository->objects->sources; source; source = source->next)
1005 fsck_source(source);
@@ -1012,8 +1010,7 @@ int cmd_fsck(int argc,
1010 struct progress *progress = NULL;
1011
1012 if (show_progress) {
1015 - for (p = packfile_store_get_all_packs(packs); p;
1016 - p = p->next) {
1013 + repo_for_each_pack(the_repository, p) {
1014 if (open_pack_index(p))
1015 continue;
1016 total += p->num_objects;
@@ -1022,8 +1019,8 @@ int cmd_fsck(int argc,
1019 progress = start_progress(the_repository,
1020 _("Checking objects"), total);
1021 }
1025 - for (p = packfile_store_get_all_packs(packs); p;
1026 - p = p->next) {
1022 +
1023 + repo_for_each_pack(the_repository, p) {
1024 /* verify gives error messages itself */
1025 if (verify_pack(the_repository,
1026 p, fsck_obj_buffer,
builtin/gc.c
+7 -9
@@ -487,10 +487,9 @@ static int too_many_loose_objects(struct gc_config *cfg)
487 static struct packed_git *find_base_packs(struct string_list *packs,
488 unsigned long limit)
489 {
490 - struct packfile_store *packfiles = the_repository->objects->packfiles;
490 struct packed_git *p, *base = NULL;
491
493 - for (p = packfile_store_get_all_packs(packfiles); p; p = p->next) {
492 + repo_for_each_pack(the_repository, p) {
493 if (!p->pack_local || p->is_cruft)
494 continue;
495 if (limit) {
@@ -509,14 +508,13 @@ static struct packed_git *find_base_packs(struct string_list *packs,
508
509 static int too_many_packs(struct gc_config *cfg)
510 {
512 - struct packfile_store *packs = the_repository->objects->packfiles;
511 struct packed_git *p;
514 - int cnt;
512 + int cnt = 0;
513
514 if (cfg->gc_auto_pack_limit <= 0)
515 return 0;
516
519 - for (cnt = 0, p = packfile_store_get_all_packs(packs); p; p = p->next) {
517 + repo_for_each_pack(the_repository, p) {
518 if (!p->pack_local)
519 continue;
520 if (p->pack_keep)
@@ -1425,9 +1423,9 @@ static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
1423 if (incremental_repack_auto_limit < 0)
1424 return 1;
1425
1428 - for (p = packfile_store_get_all_packs(the_repository->objects->packfiles);
1429 - count < incremental_repack_auto_limit && p;
1430 - p = p->next) {
1426 + repo_for_each_pack(the_repository, p) {
1427 + if (count >= incremental_repack_auto_limit)
1428 + break;
1429 if (!p->multi_pack_index)
1430 count++;
1431 }
@@ -1494,7 +1492,7 @@ static off_t get_auto_pack_size(void)
1492 struct repository *r = the_repository;
1493
1494 odb_reprepare(r->objects);
1497 - for (p = packfile_store_get_all_packs(r->objects->packfiles); p; p = p->next) {
1495 + repo_for_each_pack(r, p) {
1496 if (p->pack_size > max_size) {
1497 second_largest_size = max_size;
1498 max_size = p->pack_size;
builtin/pack-objects.c
+7 -15
@@ -3831,12 +3831,10 @@ static int pack_mtime_cmp(const void *_a, const void *_b)
3831
3832 static void read_packs_list_from_stdin(struct rev_info *revs)
3833 {
3834 - struct packfile_store *packs = the_repository->objects->packfiles;
3834 struct strbuf buf = STRBUF_INIT;
3835 struct string_list include_packs = STRING_LIST_INIT_DUP;
3836 struct string_list exclude_packs = STRING_LIST_INIT_DUP;
3837 struct string_list_item *item = NULL;
3839 -
3838 struct packed_git *p;
3839
3840 while (strbuf_getline(&buf, stdin) != EOF) {
@@ -3856,7 +3854,7 @@ static void read_packs_list_from_stdin(struct rev_info *revs)
3854 string_list_sort(&exclude_packs);
3855 string_list_remove_duplicates(&exclude_packs, 0);
3856
3859 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
3857 + repo_for_each_pack(the_repository, p) {
3858 const char *pack_name = pack_basename(p);
3859
3860 if ((item = string_list_lookup(&include_packs, pack_name)))
@@ -4077,7 +4075,6 @@ static void enumerate_cruft_objects(void)
4075
4076 static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs)
4077 {
4080 - struct packfile_store *packs = the_repository->objects->packfiles;
4078 struct packed_git *p;
4079 struct rev_info revs;
4080 int ret;
@@ -4107,7 +4104,7 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs
4104 * Re-mark only the fresh packs as kept so that objects in
4105 * unknown packs do not halt the reachability traversal early.
4106 */
4110 - for (p = packfile_store_get_all_packs(packs); p; p = p->next)
4107 + repo_for_each_pack(the_repository, p)
4108 p->pack_keep_in_core = 0;
4109 mark_pack_kept_in_core(fresh_packs, 1);
4110
@@ -4124,7 +4121,6 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs
4121
4122 static void read_cruft_objects(void)
4123 {
4127 - struct packfile_store *packs = the_repository->objects->packfiles;
4124 struct strbuf buf = STRBUF_INIT;
4125 struct string_list discard_packs = STRING_LIST_INIT_DUP;
4126 struct string_list fresh_packs = STRING_LIST_INIT_DUP;
@@ -4145,7 +4141,7 @@ static void read_cruft_objects(void)
4141 string_list_sort(&discard_packs);
4142 string_list_sort(&fresh_packs);
4143
4148 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
4144 + repo_for_each_pack(the_repository, p) {
4145 const char *pack_name = pack_basename(p);
4146 struct string_list_item *item;
4147
@@ -4440,13 +4436,12 @@ static int loosened_object_can_be_discarded(const struct object_id *oid,
4436
4437 static void loosen_unused_packed_objects(void)
4438 {
4443 - struct packfile_store *packs = the_repository->objects->packfiles;
4439 struct packed_git *p;
4440 uint32_t i;
4441 uint32_t loosened_objects_nr = 0;
4442 struct object_id oid;
4443
4449 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
4444 + repo_for_each_pack(the_repository, p) {
4445 if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
4446 continue;
4447
@@ -4747,13 +4742,12 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)
4742
4743 static void add_extra_kept_packs(const struct string_list *names)
4744 {
4750 - struct packfile_store *packs = the_repository->objects->packfiles;
4745 struct packed_git *p;
4746
4747 if (!names->nr)
4748 return;
4749
4756 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
4750 + repo_for_each_pack(the_repository, p) {
4751 const char *name = basename(p->pack_name);
4752 int i;
4753
@@ -5191,10 +5185,9 @@ int cmd_pack_objects(int argc,
5185
5186 add_extra_kept_packs(&keep_pack_list);
5187 if (ignore_packed_keep_on_disk) {
5194 - struct packfile_store *packs = the_repository->objects->packfiles;
5188 struct packed_git *p;
5189
5197 - for (p = packfile_store_get_all_packs(packs); p; p = p->next)
5190 + repo_for_each_pack(the_repository, p)
5191 if (p->pack_local && p->pack_keep)
5192 break;
5193 if (!p) /* no keep-able packs found */
@@ -5206,10 +5199,9 @@ int cmd_pack_objects(int argc,
5199 * want to unset "local" based on looking at packs, as
5200 * it also covers non-local objects
5201 */
5209 - struct packfile_store *packs = the_repository->objects->packfiles;
5202 struct packed_git *p;
5203
5212 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
5204 + repo_for_each_pack(the_repository, p) {
5205 if (!p->pack_local) {
5206 have_non_local_packs = 1;
5207 break;
builtin/pack-redundant.c
+4 -10
@@ -566,29 +566,23 @@ static struct pack_list * add_pack(struct packed_git *p)
566
567 static struct pack_list * add_pack_file(const char *filename)
568 {
569 - struct packfile_store *packs = the_repository->objects->packfiles;
570 - struct packed_git *p = packfile_store_get_all_packs(packs);
569 + struct packed_git *p;
570
571 if (strlen(filename) < 40)
572 die("Bad pack filename: %s", filename);
573
575 - while (p) {
574 + repo_for_each_pack(the_repository, p)
575 if (strstr(p->pack_name, filename))
576 return add_pack(p);
578 - p = p->next;
579 - }
577 die("Filename %s not found in packed_git", filename);
578 }
579
580 static void load_all(void)
581 {
585 - struct packfile_store *packs = the_repository->objects->packfiles;
586 - struct packed_git *p = packfile_store_get_all_packs(packs);
582 + struct packed_git *p;
583
588 - while (p) {
584 + repo_for_each_pack(the_repository, p)
585 add_pack(p);
590 - p = p->next;
591 - }
586 }
587
588 int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) {
connected.c
+1 -2
@@ -74,10 +74,9 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
74 */
75 odb_reprepare(the_repository->objects);
76 do {
77 - struct packfile_store *packs = the_repository->objects->packfiles;
77 struct packed_git *p;
78
80 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
79 + repo_for_each_pack(the_repository, p) {
80 if (!p->pack_promisor)
81 continue;
82 if (find_pack_entry_one(oid, p))
http-backend.c
+2 -3
@@ -603,19 +603,18 @@ static void get_head(struct strbuf *hdr, char *arg UNUSED)
603 static void get_info_packs(struct strbuf *hdr, char *arg UNUSED)
604 {
605 size_t objdirlen = strlen(repo_get_object_directory(the_repository));
606 - struct packfile_store *packs = the_repository->objects->packfiles;
606 struct strbuf buf = STRBUF_INIT;
607 struct packed_git *p;
608 size_t cnt = 0;
609
610 select_getanyfile(hdr);
612 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
611 + repo_for_each_pack(the_repository, p) {
612 if (p->pack_local)
613 cnt++;
614 }
615
616 strbuf_grow(&buf, cnt * 53 + 2);
618 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
617 + repo_for_each_pack(the_repository, p) {
618 if (p->pack_local)
619 strbuf_addf(&buf, "P %s\n", p->pack_name + objdirlen + 6);
620 }
http.c
+1 -2
@@ -2416,7 +2416,6 @@ static char *fetch_pack_index(unsigned char *hash, const char *base_url)
2416 static int fetch_and_setup_pack_index(struct packed_git **packs_head,
2417 unsigned char *sha1, const char *base_url)
2418 {
2419 - struct packfile_store *packs = the_repository->objects->packfiles;
2419 struct packed_git *new_pack, *p;
2420 char *tmp_idx = NULL;
2421 int ret;
@@ -2425,7 +2424,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
2424 * If we already have the pack locally, no need to fetch its index or
2425 * even add it to list; we already have all of its objects.
2426 */
2428 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
2427 + repo_for_each_pack(the_repository, p) {
2428 if (hasheq(p->hash, sha1, the_repository->hash_algo))
2429 return 0;
2430 }
object-name.c
+5 -3
@@ -213,9 +213,11 @@ static void find_short_packed_object(struct disambiguate_state *ds)
213 unique_in_midx(m, ds);
214 }
215
216 - for (p = packfile_store_get_all_packs(ds->repo->objects->packfiles); p && !ds->ambiguous;
217 - p = p->next)
216 + repo_for_each_pack(ds->repo, p) {
217 + if (ds->ambiguous)
218 + break;
219 unique_in_pack(p, ds);
220 + }
221 }
222
223 static int finish_object_disambiguation(struct disambiguate_state *ds,
@@ -805,7 +807,7 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)
807 find_abbrev_len_for_midx(m, mad);
808 }
809
808 - for (p = packfile_store_get_all_packs(mad->repo->objects->packfiles); p; p = p->next)
810 + repo_for_each_pack(mad->repo, p)
811 find_abbrev_len_for_pack(p, mad);
812 }
813
pack-bitmap.c
+3 -3
@@ -664,7 +664,7 @@ static int open_pack_bitmap(struct repository *r,
664 struct packed_git *p;
665 int ret = -1;
666
667 - for (p = packfile_store_get_all_packs(r->objects->packfiles); p; p = p->next) {
667 + repo_for_each_pack(r, p) {
668 if (open_pack_bitmap_1(bitmap_git, p) == 0) {
669 ret = 0;
670 /*
@@ -3347,6 +3347,7 @@ static int verify_bitmap_file(const struct git_hash_algo *algop,
3347 int verify_bitmap_files(struct repository *r)
3348 {
3349 struct odb_source *source;
3350 + struct packed_git *p;
3351 int res = 0;
3352
3353 odb_prepare_alternates(r->objects);
@@ -3362,8 +3363,7 @@ int verify_bitmap_files(struct repository *r)
3363 free(midx_bitmap_name);
3364 }
3365
3365 - for (struct packed_git *p = packfile_store_get_all_packs(r->objects->packfiles);
3366 - p; p = p->next) {
3366 + repo_for_each_pack(r, p) {
3367 char *pack_bitmap_name = pack_bitmap_filename(p);
3368 res |= verify_bitmap_file(r->hash_algo, pack_bitmap_name);
3369 free(pack_bitmap_name);
pack-objects.c
+2 -3
@@ -86,7 +86,6 @@ struct object_entry *packlist_find(struct packing_data *pdata,
86
87 static void prepare_in_pack_by_idx(struct packing_data *pdata)
88 {
89 - struct packfile_store *packs = pdata->repo->objects->packfiles;
89 struct packed_git **mapping, *p;
90 int cnt = 0, nr = 1U << OE_IN_PACK_BITS;
91
@@ -96,13 +95,13 @@ static void prepare_in_pack_by_idx(struct packing_data *pdata)
95 * (i.e. in_pack_idx also zero) should return NULL.
96 */
97 mapping[cnt++] = NULL;
99 - for (p = packfile_store_get_all_packs(packs); p; p = p->next, cnt++) {
98 + repo_for_each_pack(pdata->repo, p) {
99 if (cnt == nr) {
100 free(mapping);
101 return;
102 }
103 p->index = cnt;
105 - mapping[cnt] = p;
104 + mapping[cnt++] = p;
105 }
106 pdata->in_pack_by_idx = mapping;
107 }
packfile.c
+2 -2
@@ -2099,7 +2099,7 @@ struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
2099 * covers, one kept and one not kept, but the midx returns only
2100 * the non-kept version.
2101 */
2102 - for (p = packfile_store_get_all_packs(r->objects->packfiles); p; p = p->next) {
2102 + repo_for_each_pack(r, p) {
2103 if ((p->pack_keep && (flags & ON_DISK_KEEP_PACKS)) ||
2104 (p->pack_keep_in_core && (flags & IN_CORE_KEEP_PACKS))) {
2105 ALLOC_GROW(packs, nr + 1, alloc);
@@ -2196,7 +2196,7 @@ int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
2196 int r = 0;
2197 int pack_errors = 0;
2198
2199 - for (p = packfile_store_get_all_packs(repo->objects->packfiles); p; p = p->next) {
2199 + repo_for_each_pack(repo, p) {
2200 if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
2201 continue;
2202 if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
packfile.h
+8
@@ -136,6 +136,14 @@ void packfile_store_reprepare(struct packfile_store *store);
136 void packfile_store_add_pack(struct packfile_store *store,
137 struct packed_git *pack);
138
139 +/*
140 + * Load and iterate through all packs of the given repository. This helper
141 + * function will yield packfiles from all object sources connected to the
142 + * repository.
143 + */
144 +#define repo_for_each_pack(repo, p) \
145 + for (p = packfile_store_get_all_packs(repo->objects->packfiles); p; p = p->next)
146 +
147 /*
148 * Get all packs managed by the given store, including packfiles that are
149 * referenced by multi-pack indices.
repack-cruft.c
+1 -2
@@ -7,12 +7,11 @@
7 static void combine_small_cruft_packs(FILE *in, off_t combine_cruft_below_size,
8 struct existing_packs *existing)
9 {
10 - struct packfile_store *packs = existing->repo->objects->packfiles;
10 struct packed_git *p;
11 struct strbuf buf = STRBUF_INIT;
12 size_t i;
13
15 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
14 + repo_for_each_pack(existing->repo, p) {
15 if (!(p->is_cruft && p->pack_local))
16 continue;
17
repack-geometry.c
+1 -2
@@ -29,11 +29,10 @@ void pack_geometry_init(struct pack_geometry *geometry,
29 struct existing_packs *existing,
30 const struct pack_objects_args *args)
31 {
32 - struct packfile_store *packs = existing->repo->objects->packfiles;
32 struct packed_git *p;
33 struct strbuf buf = STRBUF_INIT;
34
36 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
35 + repo_for_each_pack(existing->repo, p) {
36 if (args->local && !p->pack_local)
37 /*
38 * When asked to only repack local packfiles we skip
repack.c
+1 -2
@@ -123,11 +123,10 @@ int finish_pack_objects_cmd(const struct git_hash_algo *algop,
123 void existing_packs_collect(struct existing_packs *existing,
124 const struct string_list *extra_keep)
125 {
126 - struct packfile_store *packs = existing->repo->objects->packfiles;
126 struct packed_git *p;
127 struct strbuf buf = STRBUF_INIT;
128
130 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
129 + repo_for_each_pack(existing->repo, p) {
130 size_t i;
131 const char *base;
132
server-info.c
+1 -2
@@ -287,13 +287,12 @@ static int compare_info(const void *a_, const void *b_)
287
288 static void init_pack_info(struct repository *r, const char *infofile, int force)
289 {
290 - struct packfile_store *packs = r->objects->packfiles;
290 struct packed_git *p;
291 int stale;
292 int i;
293 size_t alloc = 0;
294
296 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
295 + repo_for_each_pack(r, p) {
296 /* we ignore things on alternate path since they are
297 * not available to the pullers in general.
298 */
t/helper/test-find-pack.c
+2 -1
@@ -39,11 +39,12 @@ int cmd__find_pack(int argc, const char **argv)
39 if (repo_get_oid(the_repository, argv[0], &oid))
40 die("cannot parse %s as an object name", argv[0]);
41
42 - for (p = packfile_store_get_all_packs(the_repository->objects->packfiles); p; p = p->next)
42 + repo_for_each_pack(the_repository, p) {
43 if (find_pack_entry_one(&oid, p)) {
44 printf("%s\n", p->pack_name);
45 actual_count++;
46 }
47 + }
48
49 if (count > -1 && count != actual_count)
50 die("bad packfile count %d instead of %d", actual_count, count);
t/helper/test-pack-mtimes.c
+1 -1
@@ -37,7 +37,7 @@ int cmd__pack_mtimes(int argc, const char **argv)
37 if (argc != 2)
38 usage(pack_mtimes_usage);
39
40 - for (p = packfile_store_get_all_packs(the_repository->objects->packfiles); p; p = p->next) {
40 + repo_for_each_pack(the_repository, p) {
41 strbuf_addstr(&buf, basename(p->pack_name));
42 strbuf_strip_suffix(&buf, ".pack");
43 strbuf_addstr(&buf, ".mtimes");