Re: gitignore pattern matching issue with Windows
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Jul 28, 2025, 22:36 UTC
- Message-ID
- <xmqqa54ot02t.fsf@gitster.g>
- In-Reply-To
- <CAK2EJNO-FY+TzAnwtOhAgbWpnBP1d8yfjPidWSd=rVKM6rrdhQ@mail.gmail.com>
TDD Guru <tddguru@gmail.com> writes:
Show 7 quoted lines
> C:\gitbug>git check-ignore -v a > > C:\gitbug>git check-ignore -v b > > C:\gitbug>git check-ignore -v A > > C:\gitbug>git check-ignore -v B
I do not think this is not limited to Windows. The exclusion patterns use the wildmatch machinery, and its ignore-case behaviour seems iffy. The code expects that pattern characters to be lowercase in character classes in order to match their uppercase counterpart, which sounds like a bug.
$ cat >.gitignore <<\EOF
[ab]
[CD]
EOF
$ git -c core.ignorecase check-ignore -v A
$ git -c core.ignorecase check-ignore -v CHere is a totally untested patch to downcase the pattern characters to match against the text characters that are already downcased.
wildmatch.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git c/wildmatch.c w/wildmatch.c index 69a2ae7000..1a2d86b691 100644 --- c/wildmatch.c +++ w/wildmatch.c @@ -189,10 +189,14 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags) do { if (!p_ch) return WM_ABORT_ALL; + if ((flags & WM_CASEFOLD) && ISUPPER(p_ch)) + p_ch = tolower(p_ch); if (p_ch == '\\') { p_ch = *++p; if (!p_ch) return WM_ABORT_ALL; + if ((flags & WM_CASEFOLD) && ISUPPER(p_ch)) + p_ch = tolower(p_ch); if (t_ch == p_ch) matched = 1; } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') { @@ -201,6 +205,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags) p_ch = *++p; if (!p_ch) return WM_ABORT_ALL; + if ((flags & WM_CASEFOLD) && ISUPPER(p_ch)) + p_ch = tolower(p_ch); } if (t_ch <= p_ch && t_ch >= prev_ch) matched = 1; @@ -225,6 +231,11 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags) matched = 1; goto next; } + + /* + * [[:alnum:]] etc. must be spelled in + * lowercase even under icase matching rule. + */ if (CC_EQ(s,i, "alnum")) { if (ISALNUM(t_ch)) matched = 1;