repack: move `write_cruft_pack()` out of the builtin

In an identical fashion as the previous commit, move the function `write_cruft_pack()` into its own compilation unit, and make the function visible through 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:29 UTC 09797bd9666bb9cc6232e414498578deb2697c2a
5 files changed +107 -94
Makefile
+1
@@ -1137,6 +1137,7 @@ LIB_OBJS += refs/ref-cache.o
1137 LIB_OBJS += refspec.o
1138 LIB_OBJS += remote.o
1139 LIB_OBJS += repack.o
1140 +LIB_OBJS += repack-cruft.o
1141 LIB_OBJS += repack-filtered.o
1142 LIB_OBJS += repack-geometry.o
1143 LIB_OBJS += repack-midx.o
builtin/repack.c
-94
@@ -106,100 +106,6 @@ static int repack_config(const char *var, const char *value,
106 return git_default_config(var, value, ctx, cb);
107 }
108
109 -static void combine_small_cruft_packs(FILE *in, size_t combine_cruft_below_size,
110 - struct existing_packs *existing)
111 -{
112 - struct packfile_store *packs = existing->repo->objects->packfiles;
113 - struct packed_git *p;
114 - struct strbuf buf = STRBUF_INIT;
115 - size_t i;
116 -
117 - for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
118 - if (!(p->is_cruft && p->pack_local))
119 - continue;
120 -
121 - strbuf_reset(&buf);
122 - strbuf_addstr(&buf, pack_basename(p));
123 - strbuf_strip_suffix(&buf, ".pack");
124 -
125 - if (!string_list_has_string(&existing->cruft_packs, buf.buf))
126 - continue;
127 -
128 - if (p->pack_size < combine_cruft_below_size) {
129 - fprintf(in, "-%s\n", pack_basename(p));
130 - } else {
131 - existing_packs_retain_cruft(existing, p);
132 - fprintf(in, "%s\n", pack_basename(p));
133 - }
134 - }
135 -
136 - for (i = 0; i < existing->non_kept_packs.nr; i++)
137 - fprintf(in, "-%s.pack\n",
138 - existing->non_kept_packs.items[i].string);
139 -
140 - strbuf_release(&buf);
141 -}
142 -
143 -static int write_cruft_pack(const struct write_pack_opts *opts,
144 - const char *cruft_expiration,
145 - unsigned long combine_cruft_below_size,
146 - struct string_list *names,
147 - struct existing_packs *existing)
148 -{
149 - struct child_process cmd = CHILD_PROCESS_INIT;
150 - struct string_list_item *item;
151 - FILE *in;
152 - int ret;
153 - const char *pack_prefix = write_pack_opts_pack_prefix(opts);
154 -
155 - prepare_pack_objects(&cmd, opts->po_args, opts->destination);
156 -
157 - strvec_push(&cmd.args, "--cruft");
158 - if (cruft_expiration)
159 - strvec_pushf(&cmd.args, "--cruft-expiration=%s",
160 - cruft_expiration);
161 -
162 - strvec_push(&cmd.args, "--non-empty");
163 -
164 - cmd.in = -1;
165 -
166 - ret = start_command(&cmd);
167 - if (ret)
168 - return ret;
169 -
170 - /*
171 - * names has a confusing double use: it both provides the list
172 - * of just-written new packs, and accepts the name of the cruft
173 - * pack we are writing.
174 - *
175 - * By the time it is read here, it contains only the pack(s)
176 - * that were just written, which is exactly the set of packs we
177 - * want to consider kept.
178 - *
179 - * If `--expire-to` is given, the double-use served by `names`
180 - * ensures that the pack written to `--expire-to` excludes any
181 - * objects contained in the cruft pack.
182 - */
183 - in = xfdopen(cmd.in, "w");
184 - for_each_string_list_item(item, names)
185 - fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
186 - if (combine_cruft_below_size && !cruft_expiration) {
187 - combine_small_cruft_packs(in, combine_cruft_below_size,
188 - existing);
189 - } else {
190 - for_each_string_list_item(item, &existing->non_kept_packs)
191 - fprintf(in, "-%s.pack\n", item->string);
192 - for_each_string_list_item(item, &existing->cruft_packs)
193 - fprintf(in, "-%s.pack\n", item->string);
194 - }
195 - for_each_string_list_item(item, &existing->kept_packs)
196 - fprintf(in, "%s.pack\n", item->string);
197 - fclose(in);
198 -
199 - return finish_pack_objects_cmd(existing->repo->hash_algo, opts, &cmd,
200 - names);
201 -}
202 -
109 int cmd_repack(int argc,
110 const char **argv,
111 const char *prefix,
meson.build
+1
@@ -463,6 +463,7 @@ libgit_sources = [
463 'reftable/writer.c',
464 'remote.c',
465 'repack.c',
466 + 'repack-cruft.c',
467 'repack-filtered.c',
468 'repack-geometry.c',
469 'repack-midx.c',
repack-cruft.c new
+99
@@ -0,0 +1,99 @@
1 +#include "git-compat-util.h"
2 +#include "repack.h"
3 +#include "packfile.h"
4 +#include "repository.h"
5 +#include "run-command.h"
6 +
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;
11 + struct packed_git *p;
12 + struct strbuf buf = STRBUF_INIT;
13 + size_t i;
14 +
15 + for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
16 + if (!(p->is_cruft && p->pack_local))
17 + continue;
18 +
19 + strbuf_reset(&buf);
20 + strbuf_addstr(&buf, pack_basename(p));
21 + strbuf_strip_suffix(&buf, ".pack");
22 +
23 + if (!string_list_has_string(&existing->cruft_packs, buf.buf))
24 + continue;
25 +
26 + if (p->pack_size < combine_cruft_below_size) {
27 + fprintf(in, "-%s\n", pack_basename(p));
28 + } else {
29 + existing_packs_retain_cruft(existing, p);
30 + fprintf(in, "%s\n", pack_basename(p));
31 + }
32 + }
33 +
34 + for (i = 0; i < existing->non_kept_packs.nr; i++)
35 + fprintf(in, "-%s.pack\n",
36 + existing->non_kept_packs.items[i].string);
37 +
38 + strbuf_release(&buf);
39 +}
40 +
41 +int write_cruft_pack(const struct write_pack_opts *opts,
42 + const char *cruft_expiration,
43 + unsigned long combine_cruft_below_size,
44 + struct string_list *names,
45 + struct existing_packs *existing)
46 +{
47 + struct child_process cmd = CHILD_PROCESS_INIT;
48 + struct string_list_item *item;
49 + FILE *in;
50 + int ret;
51 + const char *pack_prefix = write_pack_opts_pack_prefix(opts);
52 +
53 + prepare_pack_objects(&cmd, opts->po_args, opts->destination);
54 +
55 + strvec_push(&cmd.args, "--cruft");
56 + if (cruft_expiration)
57 + strvec_pushf(&cmd.args, "--cruft-expiration=%s",
58 + cruft_expiration);
59 +
60 + strvec_push(&cmd.args, "--non-empty");
61 +
62 + cmd.in = -1;
63 +
64 + ret = start_command(&cmd);
65 + if (ret)
66 + return ret;
67 +
68 + /*
69 + * names has a confusing double use: it both provides the list
70 + * of just-written new packs, and accepts the name of the cruft
71 + * pack we are writing.
72 + *
73 + * By the time it is read here, it contains only the pack(s)
74 + * that were just written, which is exactly the set of packs we
75 + * want to consider kept.
76 + *
77 + * If `--expire-to` is given, the double-use served by `names`
78 + * ensures that the pack written to `--expire-to` excludes any
79 + * objects contained in the cruft pack.
80 + */
81 + in = xfdopen(cmd.in, "w");
82 + for_each_string_list_item(item, names)
83 + fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
84 + if (combine_cruft_below_size && !cruft_expiration) {
85 + combine_small_cruft_packs(in, combine_cruft_below_size,
86 + existing);
87 + } else {
88 + for_each_string_list_item(item, &existing->non_kept_packs)
89 + fprintf(in, "-%s.pack\n", item->string);
90 + for_each_string_list_item(item, &existing->cruft_packs)
91 + fprintf(in, "-%s.pack\n", item->string);
92 + }
93 + for_each_string_list_item(item, &existing->kept_packs)
94 + fprintf(in, "%s.pack\n", item->string);
95 + fclose(in);
96 +
97 + return finish_pack_objects_cmd(existing->repo->hash_algo, opts, &cmd,
98 + names);
99 +}
repack.h
+6
@@ -137,4 +137,10 @@ int write_filtered_pack(const struct write_pack_opts *opts,
137 struct existing_packs *existing,
138 struct string_list *names);
139
140 +int write_cruft_pack(const struct write_pack_opts *opts,
141 + const char *cruft_expiration,
142 + unsigned long combine_cruft_below_size,
143 + struct string_list *names,
144 + struct existing_packs *existing);
145 +
146 #endif /* REPACK_H */