|
41 | 41 | #include "promisor-remote.h"
|
42 | 42 | #include "pack-mtimes.h"
|
43 | 43 | #include "parse-options.h"
|
| 44 | +#include "blob.h" |
| 45 | +#include "tree.h" |
| 46 | +#include "path-walk.h" |
44 | 47 |
|
45 | 48 | /*
|
46 | 49 | * Objects we are going to pack are collected in the `to_pack` structure.
|
@@ -217,6 +220,7 @@ static int delta_search_threads;
|
217 | 220 | static int pack_to_stdout;
|
218 | 221 | static int sparse;
|
219 | 222 | static int thin;
|
| 223 | +static int path_walk; |
220 | 224 | static int num_preferred_base;
|
221 | 225 | static struct progress *progress_state;
|
222 | 226 |
|
@@ -4191,6 +4195,105 @@ static void mark_bitmap_preferred_tips(void)
|
4191 | 4195 | }
|
4192 | 4196 | }
|
4193 | 4197 |
|
| 4198 | +static inline int is_oid_uninteresting(struct repository *repo, |
| 4199 | + struct object_id *oid) |
| 4200 | +{ |
| 4201 | + struct object *o = lookup_object(repo, oid); |
| 4202 | + return !o || (o->flags & UNINTERESTING); |
| 4203 | +} |
| 4204 | + |
| 4205 | +static int add_objects_by_path(const char *path, |
| 4206 | + struct oid_array *oids, |
| 4207 | + enum object_type type, |
| 4208 | + void *data) |
| 4209 | +{ |
| 4210 | + struct object_entry **delta_list = NULL; |
| 4211 | + size_t oe_start = to_pack.nr_objects; |
| 4212 | + size_t oe_end; |
| 4213 | + unsigned int sub_list_nr; |
| 4214 | + unsigned int *processed = data; |
| 4215 | + |
| 4216 | + /* |
| 4217 | + * First, add all objects to the packing data, including the ones |
| 4218 | + * marked UNINTERESTING (translated to 'exclude') as they can be |
| 4219 | + * used as delta bases. |
| 4220 | + */ |
| 4221 | + for (size_t i = 0; i < oids->nr; i++) { |
| 4222 | + int exclude; |
| 4223 | + struct object_info oi = OBJECT_INFO_INIT; |
| 4224 | + struct object_id *oid = &oids->oid[i]; |
| 4225 | + |
| 4226 | + /* Skip objects that do not exist locally. */ |
| 4227 | + if (exclude_promisor_objects && |
| 4228 | + oid_object_info_extended(the_repository, oid, &oi, |
| 4229 | + OBJECT_INFO_FOR_PREFETCH) < 0) |
| 4230 | + continue; |
| 4231 | + |
| 4232 | + exclude = is_oid_uninteresting(the_repository, oid); |
| 4233 | + |
| 4234 | + if (exclude && !thin) |
| 4235 | + continue; |
| 4236 | + |
| 4237 | + add_object_entry(oid, type, path, exclude); |
| 4238 | + } |
| 4239 | + |
| 4240 | + oe_end = to_pack.nr_objects; |
| 4241 | + |
| 4242 | + /* We can skip delta calculations if it is a no-op. */ |
| 4243 | + if (oe_end == oe_start || !window) |
| 4244 | + return 0; |
| 4245 | + |
| 4246 | + sub_list_nr = 0; |
| 4247 | + if (oe_end > oe_start) |
| 4248 | + ALLOC_ARRAY(delta_list, oe_end - oe_start); |
| 4249 | + |
| 4250 | + for (size_t i = 0; i < oe_end - oe_start; i++) { |
| 4251 | + struct object_entry *entry = to_pack.objects + oe_start + i; |
| 4252 | + |
| 4253 | + if (!should_attempt_deltas(entry)) |
| 4254 | + continue; |
| 4255 | + |
| 4256 | + delta_list[sub_list_nr++] = entry; |
| 4257 | + } |
| 4258 | + |
| 4259 | + /* |
| 4260 | + * Find delta bases among this list of objects that all match the same |
| 4261 | + * path. This causes the delta compression to be interleaved in the |
| 4262 | + * object walk, which can lead to confusing progress indicators. This is |
| 4263 | + * also incompatible with threaded delta calculations. In the future, |
| 4264 | + * consider creating a list of regions in the full to_pack.objects array |
| 4265 | + * that could be picked up by the threaded delta computation. |
| 4266 | + */ |
| 4267 | + if (sub_list_nr && window) { |
| 4268 | + QSORT(delta_list, sub_list_nr, type_size_sort); |
| 4269 | + find_deltas(delta_list, &sub_list_nr, window, depth, processed); |
| 4270 | + } |
| 4271 | + |
| 4272 | + free(delta_list); |
| 4273 | + return 0; |
| 4274 | +} |
| 4275 | + |
| 4276 | +static void get_object_list_path_walk(struct rev_info *revs) |
| 4277 | +{ |
| 4278 | + struct path_walk_info info = PATH_WALK_INFO_INIT; |
| 4279 | + unsigned int processed = 0; |
| 4280 | + |
| 4281 | + info.revs = revs; |
| 4282 | + info.path_fn = add_objects_by_path; |
| 4283 | + info.path_fn_data = &processed; |
| 4284 | + |
| 4285 | + /* |
| 4286 | + * Allow the --[no-]sparse option to be interesting here, if only |
| 4287 | + * for testing purposes. Paths with no interesting objects will not |
| 4288 | + * contribute to the resulting pack, but only create noisy preferred |
| 4289 | + * base objects. |
| 4290 | + */ |
| 4291 | + info.prune_all_uninteresting = sparse; |
| 4292 | + |
| 4293 | + if (walk_objects_by_path(&info)) |
| 4294 | + die(_("failed to pack objects via path-walk")); |
| 4295 | +} |
| 4296 | + |
4194 | 4297 | static void get_object_list(struct rev_info *revs, int ac, const char **av)
|
4195 | 4298 | {
|
4196 | 4299 | struct setup_revision_opt s_r_opt = {
|
@@ -4246,15 +4349,19 @@ static void get_object_list(struct rev_info *revs, int ac, const char **av)
|
4246 | 4349 | if (write_bitmap_index)
|
4247 | 4350 | mark_bitmap_preferred_tips();
|
4248 | 4351 |
|
4249 |
| - if (prepare_revision_walk(revs)) |
4250 |
| - die(_("revision walk setup failed")); |
4251 |
| - mark_edges_uninteresting(revs, show_edge, sparse); |
4252 |
| - |
4253 | 4352 | if (!fn_show_object)
|
4254 | 4353 | fn_show_object = show_object;
|
4255 |
| - traverse_commit_list(revs, |
4256 |
| - show_commit, fn_show_object, |
4257 |
| - NULL); |
| 4354 | + |
| 4355 | + if (path_walk) { |
| 4356 | + get_object_list_path_walk(revs); |
| 4357 | + } else { |
| 4358 | + if (prepare_revision_walk(revs)) |
| 4359 | + die(_("revision walk setup failed")); |
| 4360 | + mark_edges_uninteresting(revs, show_edge, sparse); |
| 4361 | + traverse_commit_list(revs, |
| 4362 | + show_commit, fn_show_object, |
| 4363 | + NULL); |
| 4364 | + } |
4258 | 4365 |
|
4259 | 4366 | if (unpack_unreachable_expiration) {
|
4260 | 4367 | revs->ignore_missing_links = 1;
|
@@ -4464,6 +4571,8 @@ int cmd_pack_objects(int argc,
|
4464 | 4571 | N_("use the sparse reachability algorithm")),
|
4465 | 4572 | OPT_BOOL(0, "thin", &thin,
|
4466 | 4573 | N_("create thin packs")),
|
| 4574 | + OPT_BOOL(0, "path-walk", &path_walk, |
| 4575 | + N_("use the path-walk API to walk objects when possible")), |
4467 | 4576 | OPT_BOOL(0, "shallow", &shallow,
|
4468 | 4577 | N_("create packs suitable for shallow fetches")),
|
4469 | 4578 | OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep_on_disk,
|
@@ -4549,7 +4658,30 @@ int cmd_pack_objects(int argc,
|
4549 | 4658 | window = 0;
|
4550 | 4659 |
|
4551 | 4660 | strvec_push(&rp, "pack-objects");
|
4552 |
| - if (thin) { |
| 4661 | + |
| 4662 | + if (path_walk) { |
| 4663 | + const char *option = NULL; |
| 4664 | + if (filter_options.choice) |
| 4665 | + option = "--filter"; |
| 4666 | + else if (use_delta_islands) |
| 4667 | + option = "--delta-islands"; |
| 4668 | + else if (shallow) |
| 4669 | + option = "--shallow"; |
| 4670 | + |
| 4671 | + if (option) { |
| 4672 | + warning(_("cannot use %s with %s"), |
| 4673 | + option, "--path-walk"); |
| 4674 | + path_walk = 0; |
| 4675 | + } |
| 4676 | + } |
| 4677 | + if (path_walk) { |
| 4678 | + strvec_push(&rp, "--boundary"); |
| 4679 | + /* |
| 4680 | + * We must disable the bitmaps because we are removing |
| 4681 | + * the --objects / --objects-edge[-aggressive] options. |
| 4682 | + */ |
| 4683 | + use_bitmap_index = 0; |
| 4684 | + } else if (thin) { |
4553 | 4685 | use_internal_rev_list = 1;
|
4554 | 4686 | strvec_push(&rp, shallow
|
4555 | 4687 | ? "--objects-edge-aggressive"
|
|
0 commit comments