Skip to content

Commit 092228e

Browse files
committed
Merge branch 'jk/cat-file-batch-all-wo-replace'
"git cat-file --batch" with the "--batch-all-objects" option is supposed to iterate over all the objects found in a repository, but it used to translate these object names using the replace mechanism, which defeats the point of enumerating all objects in the repository. This has been corrected. * jk/cat-file-batch-all-wo-replace: cat-file: use packed_object_info() for --batch-all-objects cat-file: split ordered/unordered batch-all-objects callbacks cat-file: disable refs/replace with --batch-all-objects cat-file: mention --unordered along with --batch-all-objects t1006: clean up broken objects
2 parents 853ec9a + bf97289 commit 092228e

File tree

3 files changed

+119
-16
lines changed

3 files changed

+119
-16
lines changed

Documentation/git-cat-file.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,10 @@ OPTIONS
9494
Instead of reading a list of objects on stdin, perform the
9595
requested batch operation on all objects in the repository and
9696
any alternate object stores (not just reachable objects).
97-
Requires `--batch` or `--batch-check` be specified. Note that
98-
the objects are visited in order sorted by their hashes.
97+
Requires `--batch` or `--batch-check` be specified. By default,
98+
the objects are visited in order sorted by their hashes; see
99+
also `--unordered` below. Objects are presented as-is, without
100+
respecting the "replace" mechanism of linkgit:git-replace[1].
99101

100102
--buffer::
101103
Normally batch output is flushed after each object is output, so

builtin/cat-file.c

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -355,18 +355,34 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
355355
}
356356
}
357357

358+
/*
359+
* If "pack" is non-NULL, then "offset" is the byte offset within the pack from
360+
* which the object may be accessed (though note that we may also rely on
361+
* data->oid, too). If "pack" is NULL, then offset is ignored.
362+
*/
358363
static void batch_object_write(const char *obj_name,
359364
struct strbuf *scratch,
360365
struct batch_options *opt,
361-
struct expand_data *data)
366+
struct expand_data *data,
367+
struct packed_git *pack,
368+
off_t offset)
362369
{
363-
if (!data->skip_object_info &&
364-
oid_object_info_extended(the_repository, &data->oid, &data->info,
365-
OBJECT_INFO_LOOKUP_REPLACE) < 0) {
366-
printf("%s missing\n",
367-
obj_name ? obj_name : oid_to_hex(&data->oid));
368-
fflush(stdout);
369-
return;
370+
if (!data->skip_object_info) {
371+
int ret;
372+
373+
if (pack)
374+
ret = packed_object_info(the_repository, pack, offset,
375+
&data->info);
376+
else
377+
ret = oid_object_info_extended(the_repository,
378+
&data->oid, &data->info,
379+
OBJECT_INFO_LOOKUP_REPLACE);
380+
if (ret < 0) {
381+
printf("%s missing\n",
382+
obj_name ? obj_name : oid_to_hex(&data->oid));
383+
fflush(stdout);
384+
return;
385+
}
370386
}
371387

372388
strbuf_reset(scratch);
@@ -428,7 +444,7 @@ static void batch_one_object(const char *obj_name,
428444
return;
429445
}
430446

431-
batch_object_write(obj_name, scratch, opt, data);
447+
batch_object_write(obj_name, scratch, opt, data, NULL, 0);
432448
}
433449

434450
struct object_cb_data {
@@ -442,7 +458,8 @@ static int batch_object_cb(const struct object_id *oid, void *vdata)
442458
{
443459
struct object_cb_data *data = vdata;
444460
oidcpy(&data->expand->oid, oid);
445-
batch_object_write(NULL, data->scratch, data->opt, data->expand);
461+
batch_object_write(NULL, data->scratch, data->opt, data->expand,
462+
NULL, 0);
446463
return 0;
447464
}
448465

@@ -463,29 +480,36 @@ static int collect_packed_object(const struct object_id *oid,
463480
return 0;
464481
}
465482

466-
static int batch_unordered_object(const struct object_id *oid, void *vdata)
483+
static int batch_unordered_object(const struct object_id *oid,
484+
struct packed_git *pack, off_t offset,
485+
void *vdata)
467486
{
468487
struct object_cb_data *data = vdata;
469488

470489
if (oidset_insert(data->seen, oid))
471490
return 0;
472491

473-
return batch_object_cb(oid, data);
492+
oidcpy(&data->expand->oid, oid);
493+
batch_object_write(NULL, data->scratch, data->opt, data->expand,
494+
pack, offset);
495+
return 0;
474496
}
475497

476498
static int batch_unordered_loose(const struct object_id *oid,
477499
const char *path,
478500
void *data)
479501
{
480-
return batch_unordered_object(oid, data);
502+
return batch_unordered_object(oid, NULL, 0, data);
481503
}
482504

483505
static int batch_unordered_packed(const struct object_id *oid,
484506
struct packed_git *pack,
485507
uint32_t pos,
486508
void *data)
487509
{
488-
return batch_unordered_object(oid, data);
510+
return batch_unordered_object(oid, pack,
511+
nth_packed_object_offset(pack, pos),
512+
data);
489513
}
490514

491515
static int batch_objects(struct batch_options *opt)
@@ -529,6 +553,8 @@ static int batch_objects(struct batch_options *opt)
529553
if (has_promisor_remote())
530554
warning("This repository uses promisor remotes. Some objects may not be loaded.");
531555

556+
read_replace_refs = 0;
557+
532558
cb.opt = opt;
533559
cb.expand = &data;
534560
cb.scratch = &output;

t/t1006-cat-file.sh

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@ test_expect_success "Size of broken object is correct" '
331331
git cat-file -s --allow-unknown-type $bogus_sha1 >actual &&
332332
test_cmp expect actual
333333
'
334+
335+
test_expect_success 'clean up broken object' '
336+
rm .git/objects/$(test_oid_to_path $bogus_sha1)
337+
'
338+
334339
bogus_type="abcdefghijklmnopqrstuvwxyz1234679"
335340
bogus_content="bogus"
336341
bogus_size=$(strlen "$bogus_content")
@@ -348,6 +353,10 @@ test_expect_success "Size of large broken object is correct when type is large"
348353
test_cmp expect actual
349354
'
350355

356+
test_expect_success 'clean up broken object' '
357+
rm .git/objects/$(test_oid_to_path $bogus_sha1)
358+
'
359+
351360
# Tests for git cat-file --follow-symlinks
352361
test_expect_success 'prep for symlink tests' '
353362
echo_without_newline "$hello_content" >morx &&
@@ -608,4 +617,70 @@ test_expect_success 'cat-file --batch="batman" with --batch-all-objects will wor
608617
cmp expect actual
609618
'
610619

620+
test_expect_success 'set up replacement object' '
621+
orig=$(git rev-parse HEAD) &&
622+
git cat-file commit $orig >orig &&
623+
{
624+
cat orig &&
625+
echo extra
626+
} >fake &&
627+
fake=$(git hash-object -t commit -w fake) &&
628+
orig_size=$(git cat-file -s $orig) &&
629+
fake_size=$(git cat-file -s $fake) &&
630+
git replace $orig $fake
631+
'
632+
633+
test_expect_success 'cat-file --batch respects replace objects' '
634+
git cat-file --batch >actual <<-EOF &&
635+
$orig
636+
EOF
637+
{
638+
echo "$orig commit $fake_size" &&
639+
cat fake &&
640+
echo
641+
} >expect &&
642+
test_cmp expect actual
643+
'
644+
645+
test_expect_success 'cat-file --batch-check respects replace objects' '
646+
git cat-file --batch-check >actual <<-EOF &&
647+
$orig
648+
EOF
649+
echo "$orig commit $fake_size" >expect &&
650+
test_cmp expect actual
651+
'
652+
653+
# Pull the entry for object with oid "$1" out of the output of
654+
# "cat-file --batch", including its object content (which requires
655+
# parsing and reading a set amount of bytes, hence perl).
656+
extract_batch_output () {
657+
perl -ne '
658+
BEGIN { $oid = shift }
659+
if (/^$oid \S+ (\d+)$/) {
660+
print;
661+
read STDIN, my $buf, $1;
662+
print $buf;
663+
print "\n";
664+
}
665+
' "$@"
666+
}
667+
668+
test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
669+
git cat-file --batch-all-objects --batch >actual.raw &&
670+
extract_batch_output $orig <actual.raw >actual &&
671+
{
672+
echo "$orig commit $orig_size" &&
673+
cat orig &&
674+
echo
675+
} >expect &&
676+
test_cmp expect actual
677+
'
678+
679+
test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace' '
680+
git cat-file --batch-all-objects --batch-check >actual.raw &&
681+
grep ^$orig actual.raw >actual &&
682+
echo "$orig commit $orig_size" >expect &&
683+
test_cmp expect actual
684+
'
685+
611686
test_done

0 commit comments

Comments
 (0)