diff options
author | Brandon Williams <bmwill@google.com> | 2017-05-11 15:04:25 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2017-05-12 14:23:46 +0900 |
commit | cbca060e102aedcedbd1c4b5394aeed24885d5de (patch) | |
tree | c636c2a0f7f87109b54a38471b3923a9917475a3 /builtin | |
parent | pathspec: remove PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE flag (diff) | |
download | tgif-cbca060e102aedcedbd1c4b5394aeed24885d5de.tar.xz |
ls-files: prevent prune_cache from overeagerly pruning submodules
Since (ae8d08242 pathspec: pass directory indicator to
match_pathspec_item()) the path matching logic has been able to cope
with submodules without needing to strip off a trailing slash if a path
refers to a submodule.
ls-files is the only caller of 'parse_pathspec()' which relies on the
behavior of the PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag because it
uses the result to construct a common prefix of all provided pathspecs
which is then used to prune the index of all entries which don't have
that prefix. Since submodules entries in the index don't have a
trailing slash 'prune_cache()' will be overeager and prune a submodule
'sub' if the common prefix is 'sub/'. To correct this behavior, only
prune entries which don't match up to, but not including, a trailing
slash of the common prefix.
This is in preparation to remove the
PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP flag in a later patch.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/ls-files.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/builtin/ls-files.c b/builtin/ls-files.c index a6c70dbe9e..1f3d478443 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -97,7 +97,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) { int len = max_prefix_len; - if (len >= ent->len) + if (len > ent->len) die("git ls-files: internal error - directory entry not superset of prefix"); if (!dir_path_match(ent, &pathspec, len, ps_matched)) @@ -238,7 +238,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce) strbuf_addstr(&name, super_prefix); strbuf_addstr(&name, ce->name); - if (len >= ce_namelen(ce)) + if (len > ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && @@ -403,6 +403,25 @@ static void prune_cache(const char *prefix, size_t prefixlen) active_nr = last - pos; } +static int get_common_prefix_len(const char *common_prefix) +{ + int common_prefix_len; + + if (!common_prefix) + return 0; + + common_prefix_len = strlen(common_prefix); + + /* + * If the prefix has a trailing slash, strip it so that submodules wont + * be pruned from the index. + */ + if (common_prefix[common_prefix_len - 1] == '/') + common_prefix_len--; + + return common_prefix_len; +} + /* * Read the tree specified with --with-tree option * (typically, HEAD) into stage #1 and then @@ -624,8 +643,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) "--error-unmatch"); parse_pathspec(&pathspec, 0, - PATHSPEC_PREFER_CWD | - PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, + PATHSPEC_PREFER_CWD, prefix, argv); /* @@ -637,7 +655,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) max_prefix = NULL; else max_prefix = common_prefix(&pathspec); - max_prefix_len = max_prefix ? strlen(max_prefix) : 0; + max_prefix_len = get_common_prefix_len(max_prefix); + + prune_cache(max_prefix, max_prefix_len); /* Treat unmatching pathspec elements as errors */ if (pathspec.nr && error_unmatch) @@ -651,7 +671,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) show_killed || show_modified || show_resolve_undo)) show_cached = 1; - prune_cache(max_prefix, max_prefix_len); if (with_tree) { /* * Basic sanity check; show-stages and show-unmerged |