diff --git a/builtin/clean.c b/builtin/clean.c index f59c753a4644c314395f26d1c8fac81be29e111b..4c9680acb6ded634d44d7712b6f6798c866f236e 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -962,7 +962,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) if (pathspec.nr) matches = match_pathspec(&pathspec, ent->name, - len, 0, NULL); + len, 0, NULL, 0); if (S_ISDIR(st.st_mode)) { if (remove_directories || (matches == MATCHED_EXACTLY)) { diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 02db0e1ae82fb4fb675d940df3cd68c19c817b50..47c38808a26a4602f8bd2c7d87f67770a625c679 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -140,7 +140,8 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce) die("git ls-files: internal error - cache entry not superset of prefix"); if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce), - len, ps_matched)) + len, ps_matched, + S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) return; if (tag && *tag && show_valid_bit && @@ -197,7 +198,7 @@ static void show_ru_info(void) if (len < max_prefix_len) continue; /* outside of the prefix */ if (!match_pathspec(&pathspec, path, len, - max_prefix_len, ps_matched)) + max_prefix_len, ps_matched, 0)) continue; /* uninterested */ for (i = 0; i < 3; i++) { if (!ui->mode[i]) diff --git a/dir.c b/dir.c index 5359d75e8baed3717da556e7dd65f979b058f541..98bb50fbabb69d25443df8ca4d29e11dea746a60 100644 --- a/dir.c +++ b/dir.c @@ -360,10 +360,10 @@ static int do_match_pathspec(const struct pathspec *ps, int match_pathspec(const struct pathspec *ps, const char *name, int namelen, - int prefix, char *seen) + int prefix, char *seen, int is_dir) { int positive, negative; - unsigned flags = 0; + unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0; positive = do_match_pathspec(ps, name, namelen, prefix, seen, flags); if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive) diff --git a/dir.h b/dir.h index c31ed9af785abbb6af6b2959b43fdc0fe0de051c..55e53456afab4c9fb8441144ac7393458b553006 100644 --- a/dir.h +++ b/dir.h @@ -134,7 +134,7 @@ extern int no_wildcard(const char *string); extern char *common_prefix(const struct pathspec *pathspec); extern int match_pathspec(const struct pathspec *pathspec, const char *name, int namelen, - int prefix, char *seen); + int prefix, char *seen, int is_dir); extern int within_depth(const char *name, int namelen, int depth, int max_depth); 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, const struct pathspec *pathspec, char *seen) { - return match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen); + return match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen, + S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)); } static inline int dir_path_match(const struct dir_entry *ent, const struct pathspec *pathspec, int prefix, char *seen) { - return match_pathspec(pathspec, ent->name, ent->len, prefix, seen); + int has_trailing_dir = ent->len && ent->name[ent->len - 1] == '/'; + int len = has_trailing_dir ? ent->len - 1 : ent->len; + return match_pathspec(pathspec, ent->name, len, prefix, seen, + has_trailing_dir); } #endif diff --git a/rerere.c b/rerere.c index 34a21c431bef5c5915be77a2a0a2b8fc238bd6ac..d55aa8a01b4a4f200f24972795f2887644a06d43 100644 --- a/rerere.c +++ b/rerere.c @@ -673,7 +673,7 @@ int rerere_forget(struct pathspec *pathspec) for (i = 0; i < conflict.nr; i++) { struct string_list_item *it = &conflict.items[i]; if (!match_pathspec(pathspec, it->string, - strlen(it->string), 0, NULL)) + strlen(it->string), 0, NULL, 0)) continue; rerere_forget_one_path(it->string, &merge_rr); } diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 15a491295ed3b85cb4a66d46e720e352787a8344..d30ff34be7ebaf01ef22ce63cc2d1beeccf6a057 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -127,4 +127,10 @@ test_expect_success 'diff-tree ignores trailing slash on submodule path' ' test_cmp expect actual ' +test_expect_success 'diff-cache ignores trailing slash on submodule path' ' + git diff --name-only HEAD^ submod >expect && + git diff --name-only HEAD^ submod/ >actual && + test_cmp expect actual +' + test_done