]> git.ipfire.org Git - thirdparty/git.git/commitdiff
t/helper: teach pack-deltas to list delta entries
authorTaylor Blau <ttaylorr@openai.com>
Mon, 13 Jul 2026 01:11:53 +0000 (18:11 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 13 Jul 2026 01:39:02 +0000 (18:39 -0700)
In the following commit(s), some tests will need to distinguish between
`REF_DELTA`s and `OFS_DELTA`s to exercise a new '--no-ref-delta' option
for 'pack-objects'.

Existing tools report delta relationships, but not how their bases are
represented in the pack.

Teach 'test-tool pack-deltas' a '--list-deltas' mode. For each delta
entry, print the object ID, its REF_DELTA or OFS_DELTA type, and the
base object ID or pack offset, respectively. This lets tests inspect
pack headers without open-coding a parser.

Signed-off-by: Taylor Blau <ttaylorr@openai.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/helper/test-pack-deltas.c
t/t5300-pack-object.sh

index 840797cf0dbabbef1d3a5f8efd3b43347bfafa34..4ba6fe2dd364824367586fbf7078e68cf9ba14e5 100644 (file)
@@ -7,6 +7,7 @@
 #include "hash.h"
 #include "hex.h"
 #include "pack.h"
+#include "packfile.h"
 #include "pack-objects.h"
 #include "parse-options.h"
 #include "setup.h"
@@ -15,6 +16,7 @@
 
 static const char *usage_str[] = {
        "test-tool pack-deltas --num-objects <num-objects>",
+       "test-tool pack-deltas --list-deltas <pack>.idx",
        NULL
 };
 
@@ -80,19 +82,86 @@ static void write_ref_delta(struct hashfile *f,
        free(delta_buf);
 }
 
+static int list_delta(const struct object_id *oid,
+                     struct packed_git *p,
+                     uint32_t pos,
+                     void *_w_curs)
+{
+       struct pack_window **w_curs = _w_curs;
+       off_t obj_offset = nth_packed_object_offset(p, pos);
+       off_t cur = obj_offset;
+       size_t size;
+       enum object_type type = unpack_object_header(p, w_curs, &cur,
+                                                     &size);
+
+       if (type < 0)
+               die("unable to parse object at position %"PRIu32, pos);
+       if (type != OBJ_REF_DELTA && type != OBJ_OFS_DELTA)
+               return 0;
+
+       if (type == OBJ_REF_DELTA) {
+               struct object_id base_oid;
+               const unsigned char *base = use_pack(p, w_curs, cur,
+                                                    NULL);
+
+               oidread(&base_oid, base, p->repo->hash_algo);
+               printf("%s REF_DELTA %s\n", oid_to_hex(oid),
+                      oid_to_hex(&base_oid));
+       } else {
+               off_t base_offset = get_delta_base(p, w_curs, &cur,
+                                                  type, obj_offset);
+
+               if (!base_offset)
+                       die("unable to read base of object %s", oid_to_hex(oid));
+               printf("%s OFS_DELTA %"PRIuMAX"\n", oid_to_hex(oid),
+                      (uintmax_t)base_offset);
+       }
+
+       return 0;
+}
+
+static void list_deltas(const char *idx_name)
+{
+       struct packed_git *p;
+       struct pack_window *w_curs = NULL;
+
+       p = add_packed_git(the_repository, idx_name, strlen(idx_name), 1);
+       if (!p || open_pack_index(p))
+               die("unable to open pack index %s", idx_name);
+
+       if (for_each_object_in_pack(p, list_delta, &w_curs,
+                                   ODB_FOR_EACH_OBJECT_PACK_ORDER))
+               die("unable to iterate over objects in %s", idx_name);
+
+       unuse_pack(&w_curs);
+       close_pack(p);
+       free(p);
+}
+
 int cmd__pack_deltas(int argc, const char **argv)
 {
        int num_objects = -1;
+       int list_deltas_mode = 0;
        struct hashfile *f;
        struct strbuf line = STRBUF_INIT;
        struct option options[] = {
                OPT_INTEGER('n', "num-objects", &num_objects, N_("the number of objects to write")),
+               OPT_BOOL(0, "list-deltas", &list_deltas_mode,
+                        N_("list REF_DELTA and OFS_DELTA entries")),
                OPT_END()
        };
 
        argc = parse_options(argc, argv, NULL,
                             options, usage_str, 0);
 
+       if (list_deltas_mode) {
+               if (argc != 1 || num_objects >= 0)
+                       usage_with_options(usage_str, options);
+               setup_git_directory(the_repository);
+               list_deltas(argv[0]);
+               return 0;
+       }
+
        if (argc || num_objects < 0)
                usage_with_options(usage_str, options);
 
index 73445782e74451287cf0ce62f3b4d01b002002f8..4bee490ff6ff2513c346a296b96f0c645f6b26b1 100755 (executable)
@@ -190,7 +190,9 @@ test_expect_success 'unpack without delta (core.fsyncmethod=batch)' '
 
 test_expect_success 'pack with REF_DELTA' '
        packname_2=$(git pack-objects --progress test-2 <obj-list 2>stderr) &&
-       check_deltas stderr -gt 0
+       check_deltas stderr -gt 0 &&
+       test-tool pack-deltas --list-deltas test-2-$packname_2.idx >deltas &&
+       test_grep " REF_DELTA " deltas
 '
 
 test_expect_success 'unpack with REF_DELTA' '
@@ -204,7 +206,9 @@ test_expect_success 'unpack with REF_DELTA (core.fsyncmethod=batch)' '
 test_expect_success 'pack with OFS_DELTA' '
        packname_3=$(git pack-objects --progress --delta-base-offset test-3 \
                        <obj-list 2>stderr) &&
-       check_deltas stderr -gt 0
+       check_deltas stderr -gt 0 &&
+       test-tool pack-deltas --list-deltas test-3-$packname_3.idx >deltas &&
+       test_grep " OFS_DELTA " deltas
 '
 
 test_expect_success 'unpack with OFS_DELTA' '