builtin/repack.c: remove ref snapshotting from builtin

When writing a MIDX, 'git repack' takes a snapshot of the repository's references and writes the result out to a file, which it then passes to 'git multi-pack-index write' via the '--refs-snapshot'. This is done in order to make bitmap selections with respect to what we are packing, thus avoiding a race where an incoming reference update causes us to try and write a bitmap for a commit not present in the MIDX. Extract this functionality out into a new repack-midx.c compilation unit, and expose the necessary functions via the repack.h API. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Oct 15, 2025 at 18:28 UTC ccb7f822d520472026a12250e1390683706a8154
5 files changed +83 -68
Makefile
+1
@@ -1138,6 +1138,7 @@ LIB_OBJS += refspec.o
1138 LIB_OBJS += remote.o
1139 LIB_OBJS += repack.o
1140 LIB_OBJS += repack-geometry.o
1141 +LIB_OBJS += repack-midx.o
1142 LIB_OBJS += repack-promisor.o
1143 LIB_OBJS += replace-object.o
1144 LIB_OBJS += repo-settings.o
builtin/repack.c
-68
@@ -178,74 +178,6 @@ static int midx_has_unknown_packs(char **midx_pack_names,
178 return 0;
179 }
180
181 -struct midx_snapshot_ref_data {
182 - struct repository *repo;
183 - struct tempfile *f;
184 - struct oidset seen;
185 - int preferred;
186 -};
187 -
188 -static int midx_snapshot_ref_one(const char *refname UNUSED,
189 - const char *referent UNUSED,
190 - const struct object_id *oid,
191 - int flag UNUSED, void *_data)
192 -{
193 - struct midx_snapshot_ref_data *data = _data;
194 - struct object_id peeled;
195 -
196 - if (!peel_iterated_oid(data->repo, oid, &peeled))
197 - oid = &peeled;
198 -
199 - if (oidset_insert(&data->seen, oid))
200 - return 0; /* already seen */
201 -
202 - if (odb_read_object_info(data->repo->objects, oid, NULL) != OBJ_COMMIT)
203 - return 0;
204 -
205 - fprintf(data->f->fp, "%s%s\n", data->preferred ? "+" : "",
206 - oid_to_hex(oid));
207 -
208 - return 0;
209 -}
210 -
211 -static void midx_snapshot_refs(struct repository *repo, struct tempfile *f)
212 -{
213 - struct midx_snapshot_ref_data data;
214 - const struct string_list *preferred = bitmap_preferred_tips(repo);
215 -
216 - data.repo = repo;
217 - data.f = f;
218 - data.preferred = 0;
219 - oidset_init(&data.seen, 0);
220 -
221 - if (!fdopen_tempfile(f, "w"))
222 - die(_("could not open tempfile %s for writing"),
223 - get_tempfile_path(f));
224 -
225 - if (preferred) {
226 - struct string_list_item *item;
227 -
228 - data.preferred = 1;
229 - for_each_string_list_item(item, preferred)
230 - refs_for_each_ref_in(get_main_ref_store(repo),
231 - item->string,
232 - midx_snapshot_ref_one, &data);
233 - data.preferred = 0;
234 - }
235 -
236 - refs_for_each_ref(get_main_ref_store(repo),
237 - midx_snapshot_ref_one, &data);
238 -
239 - if (close_tempfile_gently(f)) {
240 - int save_errno = errno;
241 - delete_tempfile(&f);
242 - errno = save_errno;
243 - die_errno(_("could not close refs snapshot tempfile"));
244 - }
245 -
246 - oidset_clear(&data.seen);
247 -}
248 -
181 static void midx_included_packs(struct string_list *include,
182 struct existing_packs *existing,
183 char **midx_pack_names,
meson.build
+1
@@ -464,6 +464,7 @@ libgit_sources = [
464 'remote.c',
465 'repack.c',
466 'repack-geometry.c',
467 + 'repack-midx.c',
468 'repack-promisor.c',
469 'replace-object.c',
470 'repo-settings.c',
repack-midx.c new
+77
@@ -0,0 +1,77 @@
1 +#include "git-compat-util.h"
2 +#include "repack.h"
3 +#include "hash.h"
4 +#include "hex.h"
5 +#include "odb.h"
6 +#include "oidset.h"
7 +#include "pack-bitmap.h"
8 +#include "refs.h"
9 +#include "tempfile.h"
10 +
11 +struct midx_snapshot_ref_data {
12 + struct repository *repo;
13 + struct tempfile *f;
14 + struct oidset seen;
15 + int preferred;
16 +};
17 +
18 +static int midx_snapshot_ref_one(const char *refname UNUSED,
19 + const char *referent UNUSED,
20 + const struct object_id *oid,
21 + int flag UNUSED, void *_data)
22 +{
23 + struct midx_snapshot_ref_data *data = _data;
24 + struct object_id peeled;
25 +
26 + if (!peel_iterated_oid(data->repo, oid, &peeled))
27 + oid = &peeled;
28 +
29 + if (oidset_insert(&data->seen, oid))
30 + return 0; /* already seen */
31 +
32 + if (odb_read_object_info(data->repo->objects, oid, NULL) != OBJ_COMMIT)
33 + return 0;
34 +
35 + fprintf(data->f->fp, "%s%s\n", data->preferred ? "+" : "",
36 + oid_to_hex(oid));
37 +
38 + return 0;
39 +}
40 +
41 +void midx_snapshot_refs(struct repository *repo, struct tempfile *f)
42 +{
43 + struct midx_snapshot_ref_data data;
44 + const struct string_list *preferred = bitmap_preferred_tips(repo);
45 +
46 + data.repo = repo;
47 + data.f = f;
48 + data.preferred = 0;
49 + oidset_init(&data.seen, 0);
50 +
51 + if (!fdopen_tempfile(f, "w"))
52 + die(_("could not open tempfile %s for writing"),
53 + get_tempfile_path(f));
54 +
55 + if (preferred) {
56 + struct string_list_item *item;
57 +
58 + data.preferred = 1;
59 + for_each_string_list_item(item, preferred)
60 + refs_for_each_ref_in(get_main_ref_store(repo),
61 + item->string,
62 + midx_snapshot_ref_one, &data);
63 + data.preferred = 0;
64 + }
65 +
66 + refs_for_each_ref(get_main_ref_store(repo),
67 + midx_snapshot_ref_one, &data);
68 +
69 + if (close_tempfile_gently(f)) {
70 + int save_errno = errno;
71 + delete_tempfile(&f);
72 + errno = save_errno;
73 + die_errno(_("could not close refs snapshot tempfile"));
74 + }
75 +
76 + oidset_clear(&data.seen);
77 +}
repack.h
+4
@@ -98,4 +98,8 @@ void pack_geometry_remove_redundant(struct pack_geometry *geometry,
98 const char *packdir);
99 void pack_geometry_release(struct pack_geometry *geometry);
100
101 +struct tempfile;
102 +
103 +void midx_snapshot_refs(struct repository *repo, struct tempfile *f);
104 +
105 #endif /* REPACK_H */