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>
			
			
				maint
			
			
		
							parent
							
								
									c08397e3aa
								
							
						
					
					
						commit
						cbca060e10
					
				|  | @ -97,7 +97,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) | ||||||
| { | { | ||||||
| 	int len = max_prefix_len; | 	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"); | 		die("git ls-files: internal error - directory entry not superset of prefix"); | ||||||
|  |  | ||||||
| 	if (!dir_path_match(ent, &pathspec, len, ps_matched)) | 	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, super_prefix); | ||||||
| 	strbuf_addstr(&name, ce->name); | 	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"); | 		die("git ls-files: internal error - cache entry not superset of prefix"); | ||||||
|  |  | ||||||
| 	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && | 	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; | 	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 |  * Read the tree specified with --with-tree option | ||||||
|  * (typically, HEAD) into stage #1 and then |  * (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"); | 		    "--error-unmatch"); | ||||||
|  |  | ||||||
| 	parse_pathspec(&pathspec, 0, | 	parse_pathspec(&pathspec, 0, | ||||||
| 		       PATHSPEC_PREFER_CWD | | 		       PATHSPEC_PREFER_CWD, | ||||||
| 		       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, |  | ||||||
| 		       prefix, argv); | 		       prefix, argv); | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
|  | @ -637,7 +655,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) | ||||||
| 		max_prefix = NULL; | 		max_prefix = NULL; | ||||||
| 	else | 	else | ||||||
| 		max_prefix = common_prefix(&pathspec); | 		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 */ | 	/* Treat unmatching pathspec elements as errors */ | ||||||
| 	if (pathspec.nr && error_unmatch) | 	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_killed || show_modified || show_resolve_undo)) | ||||||
| 		show_cached = 1; | 		show_cached = 1; | ||||||
|  |  | ||||||
| 	prune_cache(max_prefix, max_prefix_len); |  | ||||||
| 	if (with_tree) { | 	if (with_tree) { | ||||||
| 		/* | 		/* | ||||||
| 		 * Basic sanity check; show-stages and show-unmerged | 		 * Basic sanity check; show-stages and show-unmerged | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Brandon Williams
						Brandon Williams