{"thread":{"id":"63867","subject":"gitignore pattern matching issue with Windows","startedAt":"2025-07-28T21:09:19Z","lastAt":"2025-07-28T22:36:12Z","messageCount":2,"participants":["TDD Guru","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"522902","messageId":"CAK2EJNO-FY+TzAnwtOhAgbWpnBP1d8yfjPidWSd=rVKM6rrdhQ@mail.gmail.com","threadId":"63867","inReplyTo":null,"subject":"gitignore pattern matching issue with Windows","fromName":"TDD Guru","fromEmail":"tddguru@gmail.com","sentAt":"2025-07-28T21:09:08Z","receivedAt":"2025-07-28T21:09:19Z","isPatch":false,"sender":{"key":"tddguru@gmail.com","avatar":null},"body":"  Git does not seem to properly handle the pattern [AB] but it does handle [ab].\n\nHere is the demonstration of the bug:\n\nC:\\gitbug>git --version\ngit version 2.50.1.windows.1\n\nC:\\gitbug>echo [ab] > .gitignore\n\nC:\\gitbug>type .gitignore\n[ab]\n\nC:\\gitbug>git check-ignore -v a\n.gitignore:1:[ab]       a\n\nC:\\gitbug>git check-ignore -v b\n.gitignore:1:[ab]       b\n\nC:\\gitbug>git check-ignore -v A\n.gitignore:1:[ab]       A\n\nC:\\gitbug>git check-ignore -v B\n.gitignore:1:[ab]       B\n\nC:\\gitbug>echo [AB] > .gitignore\n\nC:\\gitbug>type .gitignore\n[AB]\n\nC:\\gitbug>git check-ignore -v a\n\nC:\\gitbug>git check-ignore -v b\n\nC:\\gitbug>git check-ignore -v A\n\nC:\\gitbug>git check-ignore -v B\n\nC:\\gitbug>git config core.ignorecase\ntrue\n\nC:\\gitbug>ver\n\nMicrosoft Windows [Version 10.0.19045.6093]\n\nC:\\gitbug>\n\nRex McCarthy\n"},{"id":"522903","messageId":"xmqqa54ot02t.fsf@gitster.g","threadId":"63867","inReplyTo":"CAK2EJNO-FY+TzAnwtOhAgbWpnBP1d8yfjPidWSd=rVKM6rrdhQ@mail.gmail.com","subject":"Re: gitignore pattern matching issue with Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-07-28T22:36:10Z","receivedAt":"2025-07-28T22:36:12Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"TDD Guru <tddguru@gmail.com> writes:\n\n> C:\\gitbug>git check-ignore -v a\n>\n> C:\\gitbug>git check-ignore -v b\n>\n> C:\\gitbug>git check-ignore -v A\n>\n> C:\\gitbug>git check-ignore -v B\n\nI do not think this is not limited to Windows.  The exclusion\npatterns use the wildmatch machinery, and its ignore-case behaviour\nseems iffy.  The code expects that pattern characters to be\nlowercase in character classes in order to match their uppercase\ncounterpart, which sounds like a bug.\n\n    $ cat >.gitignore <<\\EOF\n    [ab]\n    [CD]\n    EOF\n    $ git -c core.ignorecase check-ignore -v A\n    $ git -c core.ignorecase check-ignore -v C\n\nHere is a totally untested patch to downcase the pattern characters\nto match against the text characters that are already downcased.\n\n wildmatch.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git c/wildmatch.c w/wildmatch.c\nindex 69a2ae7000..1a2d86b691 100644\n--- c/wildmatch.c\n+++ w/wildmatch.c\n@@ -189,10 +189,14 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\tdo {\n \t\t\t\tif (!p_ch)\n \t\t\t\t\treturn WM_ABORT_ALL;\n+\t\t\t\tif ((flags & WM_CASEFOLD) && ISUPPER(p_ch))\n+\t\t\t\t\tp_ch = tolower(p_ch);\n \t\t\t\tif (p_ch == '\\\\') {\n \t\t\t\t\tp_ch = *++p;\n \t\t\t\t\tif (!p_ch)\n \t\t\t\t\t\treturn WM_ABORT_ALL;\n+\t\t\t\t\tif ((flags & WM_CASEFOLD) && ISUPPER(p_ch))\n+\t\t\t\t\t\tp_ch = tolower(p_ch);\n \t\t\t\t\tif (t_ch == p_ch)\n \t\t\t\t\t\tmatched = 1;\n \t\t\t\t} else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {\n@@ -201,6 +205,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\t\t\t\tp_ch = *++p;\n \t\t\t\t\t\tif (!p_ch)\n \t\t\t\t\t\t\treturn WM_ABORT_ALL;\n+\t\t\t\t\t\tif ((flags & WM_CASEFOLD) && ISUPPER(p_ch))\n+\t\t\t\t\t\t\tp_ch = tolower(p_ch);\n \t\t\t\t\t}\n \t\t\t\t\tif (t_ch <= p_ch && t_ch >= prev_ch)\n \t\t\t\t\t\tmatched = 1;\n@@ -225,6 +231,11 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t\tgoto next;\n \t\t\t\t\t}\n+\n+\t\t\t\t\t/*\n+\t\t\t\t\t * [[:alnum:]] etc. must be spelled in\n+\t\t\t\t\t * lowercase even under icase matching rule.\n+\t\t\t\t\t */\n \t\t\t\t\tif (CC_EQ(s,i, \"alnum\")) {\n \t\t\t\t\t\tif (ISALNUM(t_ch))\n \t\t\t\t\t\t\tmatched = 1;\n"}]}