diff options
author | Derrick Stolee <dstolee@microsoft.com> | 2021-07-14 13:12:34 (GMT) |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2021-07-14 20:42:49 (GMT) |
commit | 69bdbdb0ee25bd64bd3ad2fe241d434442e96f75 (patch) | |
tree | 7f2128154a7188a619d56a6d9ae9bd2c5a81b4a1 | |
parent | 523506df51e2e13c8c354dff1eea3378bac8dec8 (diff) | |
download | git-69bdbdb0ee25bd64bd3ad2fe241d434442e96f75.zip git-69bdbdb0ee25bd64bd3ad2fe241d434442e96f75.tar.gz git-69bdbdb0ee25bd64bd3ad2fe241d434442e96f75.tar.bz2 |
dir.c: accept a directory as part of cone-mode patterns
When we have sparse directory entries in the index, we want to compare
that directory against sparse-checkout patterns. Those pattern matching
algorithms are built expecting a file path, not a directory path. This
is especially important in the "cone mode" patterns which will match
files that exist within the "parent directories" as well as the
recursive directory matches.
If path_matches_pattern_list() is given a directory, we can add a fake
filename ("-") to the directory and get the same results as before,
assuming we are in cone mode. Since sparse index requires cone mode
patterns, this is an acceptable assumption.
Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | dir.c | 24 |
1 files changed, 19 insertions, 5 deletions
@@ -1376,7 +1376,7 @@ enum pattern_match_result path_matches_pattern_list( struct path_pattern *pattern; struct strbuf parent_pathname = STRBUF_INIT; int result = NOT_MATCHED; - const char *slash_pos; + size_t slash_pos; if (!pl->use_cone_patterns) { pattern = last_matching_pattern_from_list(pathname, pathlen, basename, @@ -1397,21 +1397,35 @@ enum pattern_match_result path_matches_pattern_list( strbuf_addch(&parent_pathname, '/'); strbuf_add(&parent_pathname, pathname, pathlen); + /* + * Directory entries are matched if and only if a file + * contained immediately within them is matched. For the + * case of a directory entry, modify the path to create + * a fake filename within this directory, allowing us to + * use the file-base matching logic in an equivalent way. + */ + if (parent_pathname.len > 0 && + parent_pathname.buf[parent_pathname.len - 1] == '/') { + slash_pos = parent_pathname.len - 1; + strbuf_add(&parent_pathname, "-", 1); + } else { + const char *slash_ptr = strrchr(parent_pathname.buf, '/'); + slash_pos = slash_ptr ? slash_ptr - parent_pathname.buf : 0; + } + if (hashmap_contains_path(&pl->recursive_hashmap, &parent_pathname)) { result = MATCHED_RECURSIVE; goto done; } - slash_pos = strrchr(parent_pathname.buf, '/'); - - if (slash_pos == parent_pathname.buf) { + if (!slash_pos) { /* include every file in root */ result = MATCHED; goto done; } - strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf); + strbuf_setlen(&parent_pathname, slash_pos); if (hashmap_contains_path(&pl->parent_hashmap, &parent_pathname)) { result = MATCHED; |