object-name: reject trees found in the index

The get_oid_with_context_1() method is used when parsing revision arguments. One particular case is to take a ":<path>" string and search the index for the given path. In the case of a sparse index, this might find a sparse directory entry, in which case the contained object is a tree. In the case of a full index, this search within the index would fail. In order to maintain identical return state as in a full index, inspect the discovered cache entry to see if it is a sparse directory and reject it. This requires being careful around the only_to_die option to be sure we die only at the correct time. This changes the behavior of 'git show :<sparse-dir>', but does not bring it entirely into alignment with a full index case. It specifically hits the wrong error message within diagnose_invalid_index_path(). That error message will be corrected in a future change. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Apr 26, 2022 at 20:43 UTC 561287d342cc55205b6cac33415ed96a6f112558
2 files changed +20 -10
object-name.c
+18 -1
@@ -1881,6 +1881,20 @@ static char *resolve_relative_path(struct repository *r, const char *rel)
1881 rel);
1882 }
1883
1884 +static int reject_tree_in_index(struct repository *repo,
1885 + int only_to_die,
1886 + const struct cache_entry *ce,
1887 + int stage,
1888 + const char *prefix,
1889 + const char *cp)
1890 +{
1891 + if (!S_ISSPARSEDIR(ce->ce_mode))
1892 + return 0;
1893 + if (only_to_die)
1894 + diagnose_invalid_index_path(repo, stage, prefix, cp);
1895 + return -1;
1896 +}
1897 +
1898 static enum get_oid_result get_oid_with_context_1(struct repository *repo,
1899 const char *name,
1900 unsigned flags,
@@ -1955,9 +1969,12 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
1969 memcmp(ce->name, cp, namelen))
1970 break;
1971 if (ce_stage(ce) == stage) {
1972 + free(new_path);
1973 + if (reject_tree_in_index(repo, only_to_die, ce,
1974 + stage, prefix, cp))
1975 + return -1;
1976 oidcpy(oid, &ce->oid);
1977 oc->mode = ce->ce_mode;
1960 - free(new_path);
1978 return 0;
1979 }
1980 pos++;
t/t1092-sparse-checkout-compatibility.sh
+2 -9
@@ -1165,15 +1165,8 @@ test_expect_success 'show (cached blobs/trees)' '
1165 test_must_fail git -C full-checkout show :folder1/ &&
1166 test_must_fail git -C sparse-checkout show :folder1/ &&
1167
1168 - git -C sparse-index show :folder1/ >actual &&
1169 - git -C full-checkout show HEAD:folder1 >expect &&
1170 -
1171 - # The output of "git show" includes the way we referenced the
1172 - # objects, so strip that out.
1173 - test_line_count = 4 actual &&
1174 - tail -n 2 actual >actual-trunc &&
1175 - tail -n 2 expect >expect-trunc &&
1176 - test_cmp expect-trunc actual-trunc
1168 + test_must_fail git -C sparse-index show :folder1/ 2>err &&
1169 + grep "is in the index, but not at stage 0" err
1170 '
1171
1172 test_expect_success 'submodule handling' '