]> git.ipfire.org Git - thirdparty/git.git/commitdiff
read-tree: narrow scope of index expansion for '--prefix'
authorVictoria Dye <vdye@github.com>
Tue, 1 Mar 2022 20:24:29 +0000 (20:24 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Mar 2022 20:36:01 +0000 (12:36 -0800)
When 'git read-tree' is provided with a prefix, expand the index only if the
prefix is equivalent to a sparse directory or contained within one. If the
index is not expanded in these cases, 'ce_in_traverse_path' will indicate
that the relevant sparse directory is not in the prefix/traverse path,
skipping past it and not unpacking the appropriate tree(s).

If the prefix is in-cone, its sparse subdirectories (if any) will be
traversed correctly without index expansion.

The behavior of 'git read-tree' with prefixes 1) inside of cone, 2) equal to
a sparse directory, and 3) inside a sparse directory are all tested as part
of the 't/t1092-sparse-checkout-compatibility.sh' test 'read-tree --prefix',
ensuring that the sparse index case works the way it did prior to this
change as well as matching non-sparse index sparse-checkout.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/read-tree.c
t/t1092-sparse-checkout-compatibility.sh
unpack-trees.c

index 0a52cab77522e21550e8c9a73ca271a43b3caa52..ec6d038242aeceb35d09ca3da5f018df48b30b1e 100644 (file)
@@ -217,8 +217,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
        if (opts.merge && !opts.index_only)
                setup_work_tree();
 
-       /* TODO: audit sparse index behavior in unpack_trees */
-       if (opts.skip_sparse_checkout || opts.prefix)
+       if (opts.skip_sparse_checkout)
                ensure_full_index(&the_index);
 
        if (opts.merge) {
index 86241b01a59a923106aaad15fba5f2e404fd1a3b..d98558f32389431bb027eb69cb42b9956716400a 100755 (executable)
@@ -1417,7 +1417,13 @@ test_expect_success 'sparse index is not expanded: read-tree' '
        do
                ensure_not_expanded read-tree -mu $MERGE_TREES &&
                ensure_not_expanded reset --hard || return 1
-       done
+       done &&
+
+       rm -rf sparse-index/deep/deeper2 &&
+       ensure_not_expanded add . &&
+       ensure_not_expanded commit -m "test" &&
+
+       ensure_not_expanded read-tree --prefix=deep/deeper2 -u deepest
 '
 
 test_expect_success 'ls-files' '
index 360844bda3ab976c73e9443b318b58dfc400f475..f3667d85ec50be75868f176ceedb08822df18933 100644 (file)
@@ -1693,6 +1693,41 @@ static void populate_from_existing_patterns(struct unpack_trees_options *o,
                o->pl = pl;
 }
 
+static void update_sparsity_for_prefix(const char *prefix,
+                                      struct index_state *istate)
+{
+       int prefix_len = strlen(prefix);
+       struct strbuf ce_prefix = STRBUF_INIT;
+
+       if (!istate->sparse_index)
+               return;
+
+       while (prefix_len > 0 && prefix[prefix_len - 1] == '/')
+               prefix_len--;
+
+       if (prefix_len <= 0)
+               BUG("Invalid prefix passed to update_sparsity_for_prefix");
+
+       strbuf_grow(&ce_prefix, prefix_len + 1);
+       strbuf_add(&ce_prefix, prefix, prefix_len);
+       strbuf_addch(&ce_prefix, '/');
+
+       /*
+        * If the prefix points to a sparse directory or a path inside a sparse
+        * directory, the index should be expanded. This is accomplished in one
+        * of two ways:
+        * - if the prefix is inside a sparse directory, it will be expanded by
+        *   the 'ensure_full_index(...)' call in 'index_name_pos(...)'.
+        * - if the prefix matches an existing sparse directory entry,
+        *   'index_name_pos(...)' will return its index position, triggering
+        *   the 'ensure_full_index(...)' below.
+        */
+       if (!path_in_cone_mode_sparse_checkout(ce_prefix.buf, istate) &&
+           index_name_pos(istate, ce_prefix.buf, ce_prefix.len) >= 0)
+               ensure_full_index(istate);
+
+       strbuf_release(&ce_prefix);
+}
 
 static int verify_absent(const struct cache_entry *,
                         enum unpack_trees_error_types,
@@ -1739,6 +1774,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                setup_standard_excludes(o->dir);
        }
 
+       if (o->prefix)
+               update_sparsity_for_prefix(o->prefix, o->src_index);
+
        if (!core_apply_sparse_checkout || !o->update)
                o->skip_sparse_checkout = 1;
        if (!o->skip_sparse_checkout && !o->pl) {