From: Derrick Stolee <dsto...@microsoft.com>

The sparse-checkout feature in "cone mode" can use the fact that
the recursive patterns are "connected" to the root via parent
patterns to decide if a directory is entirely contained in the
sparse-checkout or entirely removed.

In these cases, we can skip hashing the paths within those
directories and simply set the skipworktree bit to the correct
value.

Signed-off-by: Derrick Stolee <dsto...@microsoft.com>
---
 dir.c          |  4 ++--
 dir.h          |  1 +
 unpack-trees.c | 38 +++++++++++++++++++++++---------------
 3 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/dir.c b/dir.c
index 35c1ca9e24..2ef92a50a0 100644
--- a/dir.c
+++ b/dir.c
@@ -1270,7 +1270,7 @@ enum pattern_match_result path_matches_pattern_list(
 
        if (hashmap_contains_path(&pl->recursive_hashmap,
                                  &parent_pathname)) {
-               result = MATCHED;
+               result = MATCHED_RECURSIVE;
                goto done;
        }
 
@@ -1292,7 +1292,7 @@ enum pattern_match_result path_matches_pattern_list(
        if (hashmap_contains_parent(&pl->recursive_hashmap,
                                    pathname,
                                    &parent_pathname))
-               result = MATCHED;
+               result = MATCHED_RECURSIVE;
 
 done:
        strbuf_release(&parent_pathname);
diff --git a/dir.h b/dir.h
index 8e232085cd..77a43dbf89 100644
--- a/dir.h
+++ b/dir.h
@@ -264,6 +264,7 @@ enum pattern_match_result {
        UNDECIDED = -1,
        NOT_MATCHED = 0,
        MATCHED = 1,
+       MATCHED_RECURSIVE = 2,
 };
 
 /*
diff --git a/unpack-trees.c b/unpack-trees.c
index a90d71845d..c0dca20865 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1283,15 +1283,17 @@ static int clear_ce_flags_dir(struct index_state 
*istate,
        struct cache_entry **cache_end;
        int dtype = DT_DIR;
        int rc;
-       enum pattern_match_result ret;
-       ret = path_matches_pattern_list(prefix->buf, prefix->len,
-                                       basename, &dtype, pl, istate);
+       enum pattern_match_result ret, orig_ret;
+       orig_ret = path_matches_pattern_list(prefix->buf, prefix->len,
+                                            basename, &dtype, pl, istate);
 
        strbuf_addch(prefix, '/');
 
        /* If undecided, use matching result of parent dir in defval */
-       if (ret == UNDECIDED)
+       if (orig_ret == UNDECIDED)
                ret = default_match;
+       else
+               ret = orig_ret;
 
        for (cache_end = cache; cache_end != cache + nr; cache_end++) {
                struct cache_entry *ce = *cache_end;
@@ -1299,17 +1301,23 @@ static int clear_ce_flags_dir(struct index_state 
*istate,
                        break;
        }
 
-       /*
-        * TODO: check pl, if there are no patterns that may conflict
-        * with ret (iow, we know in advance the incl/excl
-        * decision for the entire directory), clear flag here without
-        * calling clear_ce_flags_1(). That function will call
-        * the expensive path_matches_pattern_list() on every entry.
-        */
-       rc = clear_ce_flags_1(istate, cache, cache_end - cache,
-                             prefix,
-                             select_mask, clear_mask,
-                             pl, ret);
+       if (pl->use_cone_patterns && orig_ret == MATCHED_RECURSIVE) {
+               struct cache_entry **ce = cache;
+               rc = (cache_end - cache) / sizeof(struct cache_entry *);
+
+               while (ce < cache_end) {
+                       (*ce)->ce_flags &= ~clear_mask;
+                       ce++;
+               }
+       } else if (pl->use_cone_patterns && orig_ret == NOT_MATCHED) {
+               rc = (cache_end - cache) / sizeof(struct cache_entry *);
+       } else {
+               rc = clear_ce_flags_1(istate, cache, cache_end - cache,
+                                     prefix,
+                                     select_mask, clear_mask,
+                                     pl, ret);
+       }
+
        strbuf_setlen(prefix, prefix->len - 1);
        return rc;
 }
-- 
gitgitgadget

Reply via email to