]> git.ipfire.org Git - thirdparty/git.git/commitdiff
dir.c: do not be fooled by :(exclude) pathspec elements
authorJunio C Hamano <gitster@pobox.com>
Tue, 4 Nov 2025 22:11:20 +0000 (14:11 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 4 Nov 2025 22:12:24 +0000 (14:12 -0800)
When exclude_matches_pathspec() tries to determine if an otherwise
excluded item matches the pathspec given, it goes through each
pathspec element and declares a hit, without checking if the element
is a negative ":(exclude)" element.  Fix it be applying the usual "a
path matches if it matches any one of positive pathspec element, and
if it matches none of negative pathspec elements" rule in the
function.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
dir.c
t/t2204-add-ignored.sh

diff --git a/dir.c b/dir.c
index 5b2181e5899ce951791aa5e46ccdbb2d71ce6144..5b1258a09df294049dba7562af6771bb2e3f98be 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -2219,6 +2219,8 @@ static int exclude_matches_pathspec(const char *path, int pathlen,
                                    const struct pathspec *pathspec)
 {
        int i;
+       int matches_exclude_magic = 0;
+       int matches_pathspec_elem = 0;
 
        if (!pathspec || !pathspec->nr)
                return 0;
@@ -2235,15 +2237,23 @@ static int exclude_matches_pathspec(const char *path, int pathlen,
        for (i = 0; i < pathspec->nr; i++) {
                const struct pathspec_item *item = &pathspec->items[i];
                int len = item->nowildcard_len;
+               int *matches;
+
+               if (item->magic & PATHSPEC_EXCLUDE)
+                       matches = &matches_exclude_magic;
+               else
+                       matches = &matches_pathspec_elem;
 
                if (len == pathlen &&
                    !ps_strncmp(item, item->match, path, pathlen))
-                       return 1;
+                       *matches = 1;
                if (len > pathlen &&
                    item->match[pathlen] == '/' &&
                    !ps_strncmp(item, item->match, path, pathlen))
-                       return 1;
+                       *matches = 1;
        }
+       if (matches_pathspec_elem && !matches_exclude_magic)
+               return 1;
        return 0;
 }
 
index 31eb233df51f5e7f145764a3aa8c5b1fd7142f80..aa55b219ab6dda3f64f0fe8ced3cc4b350c22df2 100755 (executable)
@@ -89,4 +89,21 @@ do
        '
 done
 
+test_expect_success "exclude magic would not interfere with .gitignore" '
+       test_write_lines dir file sub ign err out "*.o" >.gitignore &&
+       >foo.o &&
+       >foo.c &&
+       test_must_fail git add foo.o 2>err &&
+       test_grep "are ignored by one" err &&
+       test_grep "hint: Use -f" err &&
+
+       git add ":(exclude)foo.o" &&
+       git ls-files >actual &&
+       cat >expect <<-\EOF &&
+       .gitignore
+       foo.c
+       EOF
+       test_cmp expect actual
+'
+
 test_done