Thread (1 message) 1 message, 1 author, 8h ago
DORMANTno replies

[PATCH 1/4] t/helper: teach pack-deltas to list delta entries

From: Taylor Blau <hidden>
Date: 2026-07-13 01:11:56
Subsystem: the rest · Maintainer: Linus Torvalds

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 <redacted>
---
 t/helper/test-pack-deltas.c | 69 +++++++++++++++++++++++++++++++++++++
 t/t5300-pack-object.sh      |  8 +++--
 2 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c
index 840797cf0d..4ba6fe2dd3 100644
--- a/t/helper/test-pack-deltas.c
+++ b/t/helper/test-pack-deltas.c
@@ -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);
 
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 73445782e7..4bee490ff6 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -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' '
-- 
2.55.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help