pack-objects: perform name-hash traversal for unpacked objects

With '--unpacked', pack-objects adds loose objects (which don't appear in any of the excluded packs from '--stdin-packs') to the output pack without considering them as reachability tips for the name-hash traversal. This was an oversight in the original implementation of '--stdin-packs', since the code which enumerates and adds loose objects to the output pack (`add_unreachable_loose_objects()`) did not have access to the 'rev_info' struct found in `read_packs_list_from_stdin()`. Excluding unpacked objects from that traversal doesn't affect the correctness of the resulting pack, but it does make it harder to discover good deltas for loose objects. Now that the 'rev_info' struct is declared outside of `read_packs_list_from_stdin()`, we can pass it to `add_objects_in_unpacked_packs()` and add any loose objects as tips to the above-mentioned traversal, in theory producing slightly tighter packs as a result. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Jun 23, 2025 at 18:32 UTC d6220cce6beda5404effa7107b7544a3d8c6266a
1 file changed +12 -8
builtin/pack-objects.c
+12 -8
@@ -3879,7 +3879,7 @@ static void read_packs_list_from_stdin(struct rev_info *revs)
3879 string_list_clear(&exclude_packs, 0);
3880 }
3881
3882 -static void add_unreachable_loose_objects(void);
3882 +static void add_unreachable_loose_objects(struct rev_info *revs);
3883
3884 static void read_stdin_packs(int rev_list_unpacked)
3885 {
@@ -3906,7 +3906,7 @@ static void read_stdin_packs(int rev_list_unpacked)
3906 ignore_packed_keep_in_core = 1;
3907 read_packs_list_from_stdin(&revs);
3908 if (rev_list_unpacked)
3909 - add_unreachable_loose_objects();
3909 + add_unreachable_loose_objects(&revs);
3910
3911 if (prepare_revision_walk(&revs))
3912 die(_("revision walk setup failed"));
@@ -4025,7 +4025,7 @@ static void enumerate_cruft_objects(void)
4025 _("Enumerating cruft objects"), 0);
4026
4027 add_objects_in_unpacked_packs();
4028 - add_unreachable_loose_objects();
4028 + add_unreachable_loose_objects(NULL);
4029
4030 stop_progress(&progress_state);
4031 }
@@ -4303,8 +4303,9 @@ static void add_objects_in_unpacked_packs(void)
4303 }
4304
4305 static int add_loose_object(const struct object_id *oid, const char *path,
4306 - void *data UNUSED)
4306 + void *data)
4307 {
4308 + struct rev_info *revs = data;
4309 enum object_type type = oid_object_info(the_repository, oid, NULL);
4310
4311 if (type < 0) {
@@ -4325,6 +4326,10 @@ static int add_loose_object(const struct object_id *oid, const char *path,
4326 } else {
4327 add_object_entry(oid, type, "", 0);
4328 }
4329 +
4330 + if (revs && type == OBJ_COMMIT)
4331 + add_pending_oid(revs, NULL, oid, 0);
4332 +
4333 return 0;
4334 }
4335
@@ -4333,11 +4338,10 @@ static int add_loose_object(const struct object_id *oid, const char *path,
4338 * add_object_entry will weed out duplicates, so we just add every
4339 * loose object we find.
4340 */
4336 -static void add_unreachable_loose_objects(void)
4341 +static void add_unreachable_loose_objects(struct rev_info *revs)
4342 {
4343 for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
4339 - add_loose_object,
4340 - NULL, NULL, NULL);
4344 + add_loose_object, NULL, NULL, revs);
4345 }
4346
4347 static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
@@ -4684,7 +4688,7 @@ static void get_object_list(struct rev_info *revs, int ac, const char **av)
4688 if (keep_unreachable)
4689 add_objects_in_unpacked_packs();
4690 if (pack_loose_unreachable)
4687 - add_unreachable_loose_objects();
4691 + add_unreachable_loose_objects(NULL);
4692 if (unpack_unreachable)
4693 loosen_unused_packed_objects();
4694