cat-file.c: add batch handling for submodules

When an object specification is passed to 'cat-file --batch[-check]'
referring to a submodule (e.g. 'HEAD:path/to/my/submodule'), the current
behavior of the command is to print the "missing" error message. However, it
is often valuable for callers to distinguish between paths that are actually
missing and "the submodule tree entry exists, but the object does not exist
in the repository".

To disambiguate without needing to invoke a separate Git process (e.g.
'ls-tree'), print the message "<oid> submodule" for such objects instead of
"<object> missing". In addition to the change from "missing" to "submodule",
the new message differs from the old in that it always prints the resolved
tree entry's OID, rather than the input object specification.

Note that this implementation maintains a distinction between submodules
where the commit OID is not present in the repo, and submodules where the
commit OID *is* present; the former will now print "<object> submodule", but
the latter will still print the full object content.

Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
next
Victoria Dye 2025-06-02 18:55:55 +00:00 committed by Junio C Hamano
parent aba1438435
commit b0b910e052
3 changed files with 37 additions and 1 deletions

View File

@ -373,6 +373,14 @@ If a name is specified that might refer to more than one object (an ambiguous sh
<object> SP ambiguous LF
------------

If a name is specified that refers to a submodule entry in a tree and the
target object does not exist in the repository, then `cat-file` will ignore
any custom format and print (with the object ID of the submodule):

------------
<oid> SP submodule LF
------------

If `--follow-symlinks` is used, and a symlink in the repository points
outside the repository, then `cat-file` will ignore any custom format
and print:

View File

@ -496,7 +496,10 @@ static void batch_object_write(const char *obj_name,
&data->oid, &data->info,
OBJECT_INFO_LOOKUP_REPLACE);
if (ret < 0) {
report_object_status(opt, obj_name, &data->oid, "missing");
if (data->mode == S_IFGITLINK)
report_object_status(opt, oid_to_hex(&data->oid), &data->oid, "submodule");
else
report_object_status(opt, obj_name, &data->oid, "missing");
return;
}


View File

@ -1220,6 +1220,31 @@ test_expect_success 'cat-file --batch-check respects replace objects' '
test_cmp expect actual
'

test_expect_success 'batch-check with a submodule' '
# FIXME: this call to mktree is incompatible with compatObjectFormat
# because the submodule OID cannot be mapped to the compat hash algo.
test_unconfig extensions.compatobjectformat &&
printf "160000 commit $(test_oid deadbeef)\tsub\n" >tree-with-sub &&
tree=$(git mktree <tree-with-sub) &&
test_config extensions.compatobjectformat $test_compat_hash_algo &&

git cat-file --batch-check >actual <<-EOF &&
$tree:sub
EOF
printf "$(test_oid deadbeef) submodule\n" >expect &&
test_cmp expect actual
'

test_expect_success 'batch-check with a submodule, object exists' '
printf "160000 commit $commit_oid\tsub\n" >tree-with-sub &&
tree=$(git mktree <tree-with-sub) &&
git cat-file --batch-check >actual <<-EOF &&
$tree:sub
EOF
printf "$commit_oid commit $commit_size\n" >expect &&
test_cmp expect actual
'

# Pull the entry for object with oid "$1" out of the output of
# "cat-file --batch", including its object content (which requires
# parsing and reading a set amount of bytes, hence perl).