cat-file: provide %(deltabase) batch format

It can be useful for debugging or analysis to see which objects are stored as delta bases on top of others. This information is available by running `git verify-pack`, but that is extremely expensive (and is harder than necessary to parse). Instead, let's make it available as a cat-file query format, which makes it fast and simple to get the bases for a subset of the objects. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Dec 21, 2013 at 09:25 UTC 65ea9c3c3d0e74b1f8c0c1d9fea6988550133dba
3 files changed +49 -3
Documentation/git-cat-file.txt
+9 -3
@@ -109,6 +109,11 @@ newline. The available atoms are:
109 The size, in bytes, that the object takes up on disk. See the
110 note about on-disk sizes in the `CAVEATS` section below.
111
112 +`deltabase`::
113 + If the object is stored as a delta on-disk, this expands to the
114 + 40-hex sha1 of the delta base object. Otherwise, expands to the
115 + null sha1 (40 zeroes). See `CAVEATS` below.
116 +
117 `rest`::
118 If this atom is used in the output string, input lines are split
119 at the first whitespace boundary. All characters before that
@@ -152,10 +157,11 @@ should be taken in drawing conclusions about which refs or objects are
157 responsible for disk usage. The size of a packed non-delta object may be
158 much larger than the size of objects which delta against it, but the
159 choice of which object is the base and which is the delta is arbitrary
155 -and is subject to change during a repack. Note also that multiple copies
156 -of an object may be present in the object database; in this case, it is
157 -undefined which copy's size will be reported.
160 +and is subject to change during a repack.
161
162 +Note also that multiple copies of an object may be present in the object
163 +database; in this case, it is undefined which copy's size or delta base
164 +will be reported.
165
166 GIT
167 ---
builtin/cat-file.c
+6
@@ -118,6 +118,7 @@ struct expand_data {
118 unsigned long size;
119 unsigned long disk_size;
120 const char *rest;
121 + unsigned char delta_base_sha1[20];
122
123 /*
124 * If mark_query is true, we do not expand anything, but rather
@@ -174,6 +175,11 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
175 data->split_on_whitespace = 1;
176 else if (data->rest)
177 strbuf_addstr(sb, data->rest);
178 + } else if (is_atom("deltabase", atom, len)) {
179 + if (data->mark_query)
180 + data->info.delta_base_sha1 = data->delta_base_sha1;
181 + else
182 + strbuf_addstr(sb, sha1_to_hex(data->delta_base_sha1));
183 } else
184 die("unknown format element: %.*s", len, atom);
185 }
t/t1006-cat-file.sh
+34
@@ -240,4 +240,38 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" '
240 "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
241 '
242
243 +test_expect_success 'setup blobs which are likely to delta' '
244 + test-genrandom foo 10240 >foo &&
245 + { cat foo; echo plus; } >foo-plus &&
246 + git add foo foo-plus &&
247 + git commit -m foo &&
248 + cat >blobs <<-\EOF
249 + HEAD:foo
250 + HEAD:foo-plus
251 + EOF
252 +'
253 +
254 +test_expect_success 'confirm that neither loose blob is a delta' '
255 + cat >expect <<-EOF
256 + $_z40
257 + $_z40
258 + EOF
259 + git cat-file --batch-check="%(deltabase)" <blobs >actual &&
260 + test_cmp expect actual
261 +'
262 +
263 +# To avoid relying too much on the current delta heuristics,
264 +# we will check only that one of the two objects is a delta
265 +# against the other, but not the order. We can do so by just
266 +# asking for the base of both, and checking whether either
267 +# sha1 appears in the output.
268 +test_expect_success '%(deltabase) reports packed delta bases' '
269 + git repack -ad &&
270 + git cat-file --batch-check="%(deltabase)" <blobs >actual &&
271 + {
272 + grep "$(git rev-parse HEAD:foo)" actual ||
273 + grep "$(git rev-parse HEAD:foo-plus)" actual
274 + }
275 +'
276 +
277 test_done