cat-file: handle trivial --batch format with --batch-all-objects

The --batch code to print an object assumes we found out the type of the object from calling oid_object_info_extended(). This is true for the default format, but even in a custom format, we manually modify the object_info struct to ask for the type. This assumption was broken by 845de33a5b (cat-file: avoid noop calls to sha1_object_info_extended, 2016-05-18). That commit skips the call to oid_object_info_extended() entirely when --batch-all-objects is in use, and the custom format does not include any placeholders that require calling it. Or when the custom format only include placeholders like %(objectname) or %(rest), oid_object_info_extended() will not get the type of the object. This results in an error when we try to confirm that the type didn't change: $ git cat-file --batch=batman --batch-all-objects batman fatal: object 000023961a0c02d6e21dc51ea3484ff71abf1c74 changed type!? and also has other subtle effects (e.g., we'd fail to stream a blob, since we don't realize it's a blob in the first place). We can fix this by flipping the order of the setup. The check for "do we need to get the object info" must come _after_ we've decided whether we need to look up the type. Helped-by: Jeff King <peff@peff.net> Signed-off-by: ZheNing Hu <adlternative@gmail.com> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

ZheNing Hu committed Jun 3, 2021 at 16:29 UTC e16acc80a78ae5e931b94e861aff53a4af485f77
2 files changed +29 -6
builtin/cat-file.c
+7 -6
@@ -512,12 +512,6 @@ static int batch_objects(struct batch_options *opt)
512 if (opt->cmdmode)
513 data.split_on_whitespace = 1;
514
515 - if (opt->all_objects) {
516 - struct object_info empty = OBJECT_INFO_INIT;
517 - if (!memcmp(&data.info, &empty, sizeof(empty)))
518 - data.skip_object_info = 1;
519 - }
520 -
515 /*
516 * If we are printing out the object, then always fill in the type,
517 * since we will want to decide whether or not to stream.
@@ -525,6 +519,13 @@ static int batch_objects(struct batch_options *opt)
519 if (opt->print_contents)
520 data.info.typep = &data.type;
521
522 + if (opt->all_objects) {
523 + struct object_info empty = OBJECT_INFO_INIT;
524 +
525 + if (!memcmp(&data.info, &empty, sizeof(empty)))
526 + data.skip_object_info = 1;
527 + }
528 +
529 if (opt->all_objects) {
530 struct object_cb_data cb;
531
t/t1006-cat-file.sh
+22
@@ -586,4 +586,26 @@ test_expect_success 'cat-file --unordered works' '
586 test_cmp expect actual
587 '
588
589 +test_expect_success 'set up object list for --batch-all-objects tests' '
590 + git -C all-two cat-file --batch-all-objects --batch-check="%(objectname)" >objects
591 +'
592 +
593 +test_expect_success 'cat-file --batch="%(objectname)" with --batch-all-objects will work' '
594 + git -C all-two cat-file --batch="%(objectname)" <objects >expect &&
595 + git -C all-two cat-file --batch-all-objects --batch="%(objectname)" >actual &&
596 + cmp expect actual
597 +'
598 +
599 +test_expect_success 'cat-file --batch="%(rest)" with --batch-all-objects will work' '
600 + git -C all-two cat-file --batch="%(rest)" <objects >expect &&
601 + git -C all-two cat-file --batch-all-objects --batch="%(rest)" >actual &&
602 + cmp expect actual
603 +'
604 +
605 +test_expect_success 'cat-file --batch="batman" with --batch-all-objects will work' '
606 + git -C all-two cat-file --batch="batman" <objects >expect &&
607 + git -C all-two cat-file --batch-all-objects --batch="batman" >actual &&
608 + cmp expect actual
609 +'
610 +
611 test_done