pathspec: pass directory indicator to match_pathspec_item()

This patch activates the DO_MATCH_DIRECTORY code in m_p_i(), which makes "git diff HEAD submodule/" and "git diff HEAD submodule" produce the same output. Previously only the version without trailing slash returns the difference (if any). That's the effect of new ce_path_match(). dir_path_match() is not executed by the new tests. And it should not introduce regressions. Previously if path "dir/" is passed in with pathspec "dir/", they obviously match. With new dir_path_match(), the path becomes _directory_ "dir" vs pathspec "dir/", which is not executed by the old code path in m_p_i(). The new code path is executed and produces the same result. The other case is pathspec "dir" and path "dir/" is now turned to "dir" (with DO_MATCH_DIRECTORY). Still the same result before or after the patch. So why change? Because of the next patch about clean.c. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Jan 24, 2014 at 20:40 UTC ae8d0824217bdf97c69ead49568cd03fc140627b
6 files changed +20 -9
builtin/clean.c
+1 -1
@@ -962,7 +962,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
962
963 if (pathspec.nr)
964 matches = match_pathspec(&pathspec, ent->name,
965 - len, 0, NULL);
965 + len, 0, NULL, 0);
966
967 if (S_ISDIR(st.st_mode)) {
968 if (remove_directories || (matches == MATCHED_EXACTLY)) {
builtin/ls-files.c
+3 -2
@@ -140,7 +140,8 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
140 die("git ls-files: internal error - cache entry not superset of prefix");
141
142 if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
143 - len, ps_matched))
143 + len, ps_matched,
144 + S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
145 return;
146
147 if (tag && *tag && show_valid_bit &&
@@ -197,7 +198,7 @@ static void show_ru_info(void)
198 if (len < max_prefix_len)
199 continue; /* outside of the prefix */
200 if (!match_pathspec(&pathspec, path, len,
200 - max_prefix_len, ps_matched))
201 + max_prefix_len, ps_matched, 0))
202 continue; /* uninterested */
203 for (i = 0; i < 3; i++) {
204 if (!ui->mode[i])
dir.c
+2 -2
@@ -360,10 +360,10 @@ static int do_match_pathspec(const struct pathspec *ps,
360
361 int match_pathspec(const struct pathspec *ps,
362 const char *name, int namelen,
363 - int prefix, char *seen)
363 + int prefix, char *seen, int is_dir)
364 {
365 int positive, negative;
366 - unsigned flags = 0;
366 + unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
367 positive = do_match_pathspec(ps, name, namelen,
368 prefix, seen, flags);
369 if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
dir.h
+7 -3
@@ -134,7 +134,7 @@ extern int no_wildcard(const char *string);
134 extern char *common_prefix(const struct pathspec *pathspec);
135 extern int match_pathspec(const struct pathspec *pathspec,
136 const char *name, int namelen,
137 - int prefix, char *seen);
137 + int prefix, char *seen, int is_dir);
138 extern int within_depth(const char *name, int namelen, int depth, int max_depth);
139
140 extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec);
@@ -209,14 +209,18 @@ static inline int ce_path_match(const struct cache_entry *ce,
209 const struct pathspec *pathspec,
210 char *seen)
211 {
212 - return match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
212 + return match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen,
213 + S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
214 }
215
216 static inline int dir_path_match(const struct dir_entry *ent,
217 const struct pathspec *pathspec,
218 int prefix, char *seen)
219 {
219 - return match_pathspec(pathspec, ent->name, ent->len, prefix, seen);
220 + int has_trailing_dir = ent->len && ent->name[ent->len - 1] == '/';
221 + int len = has_trailing_dir ? ent->len - 1 : ent->len;
222 + return match_pathspec(pathspec, ent->name, len, prefix, seen,
223 + has_trailing_dir);
224 }
225
226 #endif
rerere.c
+1 -1
@@ -673,7 +673,7 @@ int rerere_forget(struct pathspec *pathspec)
673 for (i = 0; i < conflict.nr; i++) {
674 struct string_list_item *it = &conflict.items[i];
675 if (!match_pathspec(pathspec, it->string,
676 - strlen(it->string), 0, NULL))
676 + strlen(it->string), 0, NULL, 0))
677 continue;
678 rerere_forget_one_path(it->string, &merge_rr);
679 }
t/t4010-diff-pathspec.sh
+6
@@ -127,4 +127,10 @@ test_expect_success 'diff-tree ignores trailing slash on submodule path' '
127 test_cmp expect actual
128 '
129
130 +test_expect_success 'diff-cache ignores trailing slash on submodule path' '
131 + git diff --name-only HEAD^ submod >expect &&
132 + git diff --name-only HEAD^ submod/ >actual &&
133 + test_cmp expect actual
134 +'
135 +
136 test_done