Skip to content

Commit cbca060

Browse files
bmwillgitster
authored andcommitted
ls-files: prevent prune_cache from overeagerly pruning submodules
Since (ae8d082 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>
1 parent c08397e commit cbca060

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

builtin/ls-files.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
9797
{
9898
int len = max_prefix_len;
9999

100-
if (len >= ent->len)
100+
if (len > ent->len)
101101
die("git ls-files: internal error - directory entry not superset of prefix");
102102

103103
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)
238238
strbuf_addstr(&name, super_prefix);
239239
strbuf_addstr(&name, ce->name);
240240

241-
if (len >= ce_namelen(ce))
241+
if (len > ce_namelen(ce))
242242
die("git ls-files: internal error - cache entry not superset of prefix");
243243

244244
if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
@@ -403,6 +403,25 @@ static void prune_cache(const char *prefix, size_t prefixlen)
403403
active_nr = last - pos;
404404
}
405405

406+
static int get_common_prefix_len(const char *common_prefix)
407+
{
408+
int common_prefix_len;
409+
410+
if (!common_prefix)
411+
return 0;
412+
413+
common_prefix_len = strlen(common_prefix);
414+
415+
/*
416+
* If the prefix has a trailing slash, strip it so that submodules wont
417+
* be pruned from the index.
418+
*/
419+
if (common_prefix[common_prefix_len - 1] == '/')
420+
common_prefix_len--;
421+
422+
return common_prefix_len;
423+
}
424+
406425
/*
407426
* Read the tree specified with --with-tree option
408427
* (typically, HEAD) into stage #1 and then
@@ -624,8 +643,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
624643
"--error-unmatch");
625644

626645
parse_pathspec(&pathspec, 0,
627-
PATHSPEC_PREFER_CWD |
628-
PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
646+
PATHSPEC_PREFER_CWD,
629647
prefix, argv);
630648

631649
/*
@@ -637,7 +655,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
637655
max_prefix = NULL;
638656
else
639657
max_prefix = common_prefix(&pathspec);
640-
max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
658+
max_prefix_len = get_common_prefix_len(max_prefix);
659+
660+
prune_cache(max_prefix, max_prefix_len);
641661

642662
/* Treat unmatching pathspec elements as errors */
643663
if (pathspec.nr && error_unmatch)
@@ -651,7 +671,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
651671
show_killed || show_modified || show_resolve_undo))
652672
show_cached = 1;
653673

654-
prune_cache(max_prefix, max_prefix_len);
655674
if (with_tree) {
656675
/*
657676
* Basic sanity check; show-stages and show-unmerged

0 commit comments

Comments
 (0)