t/helper: teach pack-deltas to list delta entries
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>
Taylor Blau committed
Jul 12, 2026 at 18:11 UTC
0ff1a605b864b806655421f293ba5d732d7b81a9
2 files changed
+75
-2
t/helper/test-pack-deltas.c
+69
@@ -7,6 +7,7 @@
7
#include "hash.h"
8
#include "hex.h"
9
#include "pack.h"
10
+#include "packfile.h"
11
#include "pack-objects.h"
12
#include "parse-options.h"
13
#include "setup.h"
@@ -15,6 +16,7 @@
16
17
static const char *usage_str[] = {
18
"test-tool pack-deltas --num-objects <num-objects>",
19
+ "test-tool pack-deltas --list-deltas <pack>.idx",
20
NULL
21
};
22
@@ -80,19 +82,86 @@ static void write_ref_delta(struct hashfile *f,
82
free(delta_buf);
83
}
84
85
+static int list_delta(const struct object_id *oid,
86
+ struct packed_git *p,
87
+ uint32_t pos,
88
+ void *_w_curs)
89
+{
90
+ struct pack_window **w_curs = _w_curs;
91
+ off_t obj_offset = nth_packed_object_offset(p, pos);
92
+ off_t cur = obj_offset;
93
+ size_t size;
94
+ enum object_type type = unpack_object_header(p, w_curs, &cur,
95
+ &size);
96
+
97
+ if (type < 0)
98
+ die("unable to parse object at position %"PRIu32, pos);
99
+ if (type != OBJ_REF_DELTA && type != OBJ_OFS_DELTA)
100
+ return 0;
101
+
102
+ if (type == OBJ_REF_DELTA) {
103
+ struct object_id base_oid;
104
+ const unsigned char *base = use_pack(p, w_curs, cur,
105
+ NULL);
106
+
107
+ oidread(&base_oid, base, p->repo->hash_algo);
108
+ printf("%s REF_DELTA %s\n", oid_to_hex(oid),
109
+ oid_to_hex(&base_oid));
110
+ } else {
111
+ off_t base_offset = get_delta_base(p, w_curs, &cur,
112
+ type, obj_offset);
113
+
114
+ if (!base_offset)
115
+ die("unable to read base of object %s", oid_to_hex(oid));
116
+ printf("%s OFS_DELTA %"PRIuMAX"\n", oid_to_hex(oid),
117
+ (uintmax_t)base_offset);
118
+ }
119
+
120
+ return 0;
121
+}
122
+
123
+static void list_deltas(const char *idx_name)
124
+{
125
+ struct packed_git *p;
126
+ struct pack_window *w_curs = NULL;
127
+
128
+ p = add_packed_git(the_repository, idx_name, strlen(idx_name), 1);
129
+ if (!p || open_pack_index(p))
130
+ die("unable to open pack index %s", idx_name);
131
+
132
+ if (for_each_object_in_pack(p, list_delta, &w_curs,
133
+ ODB_FOR_EACH_OBJECT_PACK_ORDER))
134
+ die("unable to iterate over objects in %s", idx_name);
135
+
136
+ unuse_pack(&w_curs);
137
+ close_pack(p);
138
+ free(p);
139
+}
140
+
141
int cmd__pack_deltas(int argc, const char **argv)
142
{
143
int num_objects = -1;
144
+ int list_deltas_mode = 0;
145
struct hashfile *f;
146
struct strbuf line = STRBUF_INIT;
147
struct option options[] = {
148
OPT_INTEGER('n', "num-objects", &num_objects, N_("the number of objects to write")),
149
+ OPT_BOOL(0, "list-deltas", &list_deltas_mode,
150
+ N_("list REF_DELTA and OFS_DELTA entries")),
151
OPT_END()
152
};
153
154
argc = parse_options(argc, argv, NULL,
155
options, usage_str, 0);
156
157
+ if (list_deltas_mode) {
158
+ if (argc != 1 || num_objects >= 0)
159
+ usage_with_options(usage_str, options);
160
+ setup_git_directory(the_repository);
161
+ list_deltas(argv[0]);
162
+ return 0;
163
+ }
164
+
165
if (argc || num_objects < 0)
166
usage_with_options(usage_str, options);
167
t/t5300-pack-object.sh
+6
-2
@@ -190,7 +190,9 @@ test_expect_success 'unpack without delta (core.fsyncmethod=batch)' '
190
191
test_expect_success 'pack with REF_DELTA' '
192
packname_2=$(git pack-objects --progress test-2 <obj-list 2>stderr) &&
193
- check_deltas stderr -gt 0
193
+ check_deltas stderr -gt 0 &&
194
+ test-tool pack-deltas --list-deltas test-2-$packname_2.idx >deltas &&
195
+ test_grep " REF_DELTA " deltas
196
'
197
198
test_expect_success 'unpack with REF_DELTA' '
@@ -204,7 +206,9 @@ test_expect_success 'unpack with REF_DELTA (core.fsyncmethod=batch)' '
206
test_expect_success 'pack with OFS_DELTA' '
207
packname_3=$(git pack-objects --progress --delta-base-offset test-3 \
208
<obj-list 2>stderr) &&
207
- check_deltas stderr -gt 0
209
+ check_deltas stderr -gt 0 &&
210
+ test-tool pack-deltas --list-deltas test-3-$packname_3.idx >deltas &&
211
+ test_grep " OFS_DELTA " deltas
212
'
213
214
test_expect_success 'unpack with OFS_DELTA' '