{"thread":{"id":"63331","subject":"[PATCH v2] Dir: Fix and test wildcard pathspec handling","startedAt":"2025-04-22T16:05:58Z","lastAt":"2025-05-05T15:03:18Z","messageCount":7,"participants":["K Jayatheerth","Junio C Hamano","JAYATHEERTH K"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"516515","messageId":"20250422160547.577524-1-jayatheerthkulkarni2005@gmail.com","threadId":"63331","inReplyTo":null,"subject":"[PATCH v2] Dir: Fix and test wildcard pathspec handling","fromName":"K Jayatheerth","fromEmail":"jayatheerthkulkarni2005@gmail.com","sentAt":"2025-04-22T16:05:47Z","receivedAt":"2025-04-22T16:05:58Z","isPatch":true,"sender":{"key":"jayatheerthkulkarni2005@gmail.com","avatar":"https://avatars.githubusercontent.com/u/148841023?v=4"},"body":"Ensure wildcards expand, even with literal file match.\nFixes 'git add f*' skipping files like 'foo' if 'f*' exists.\nUse 'f\\*' to add the literal.\nTests added for add and commit where dir.c logic applies.\nSkips windows specific test.\n\nreported-by: piotrsiupa <piotrsiupa@gmail.com>\nMentored-by: Jeff King <peff@peff.net>\nSigned-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>\n---\n dir.c                                 |   3 +-\n t/meson.build                         |   1 +\n t/t6137-pathspec-wildcards-literal.sh | 282 ++++++++++++++++++++++++++\n 3 files changed, 285 insertions(+), 1 deletion(-)\n create mode 100755 t/t6137-pathspec-wildcards-literal.sh\n\ndiff --git a/dir.c b/dir.c\nindex 28b0e03feb..9405fee83a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -519,7 +519,8 @@ static int do_match_pathspec(struct index_state *istate,\n \t\t    ( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))\n \t\t\tcontinue;\n \n-\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n+\t\tif (seen && seen[i] == MATCHED_EXACTLY &&\n+\t\t\tps->items[i].nowildcard_len == ps->items[i].len)\n \t\t\tcontinue;\n \t\t/*\n \t\t * Make exclude patterns optional and never report\ndiff --git a/t/meson.build b/t/meson.build\nindex bfb744e886..61285852e9 100644\n--- a/t/meson.build\n+++ b/t/meson.build\n@@ -788,6 +788,7 @@ integration_tests = [\n   't6134-pathspec-in-submodule.sh',\n   't6135-pathspec-with-attrs.sh',\n   't6136-pathspec-in-bare.sh',\n+  't6137-pathspec-wildcards-literal.sh',\n   't6200-fmt-merge-msg.sh',\n   't6300-for-each-ref.sh',\n   't6301-for-each-ref-errors.sh',\ndiff --git a/t/t6137-pathspec-wildcards-literal.sh b/t/t6137-pathspec-wildcards-literal.sh\nnew file mode 100755\nindex 0000000000..abf837bf6c\n--- /dev/null\n+++ b/t/t6137-pathspec-wildcards-literal.sh\n@@ -0,0 +1,282 @@\n+#!/bin/sh\n+\n+test_description='test wildcards and literals with various git commands'\n+\n+. ./test-lib.sh\n+\n+test_have_prereq FUNNYNAMES || {\n+    skip_all='skipping: needs FUNNYNAMES (non-Windows only)'\n+    test_done\n+}\n+\n+reset_git_repo () {\n+    rm -rf .git &&\n+    git init &&\n+    rm -rf \"actual_files\" \"expected_files\"\n+}\n+\n+end_test_properly() {\n+    cd .. &&\n+    rm -rf \"testdir\"\n+}\n+\n+\n+test_expect_success 'setup' '\n+    mkdir testdir &&\n+    cd testdir &&\n+    touch \"*\" \"?\" \"[abc]\" \"f*\" \"f?z\" \"a\" &&\n+    touch \"**\" \"foo*bar\" \"hello?world\" \"f**\" \"hello_world\" &&\n+    git init\n+'\n+\n+test_expect_success 'check * wildcard in git add' '\n+    git init &&\n+    git add \"*\" &&\n+    cat >expected_files <<EOF &&\n+*\n+**\n+?\n+[abc]\n+a\n+f*\n+f**\n+f?z\n+foo*bar\n+hello?world\n+hello_world\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check \\* literal in git add' '\n+    reset_git_repo &&\n+    git add \"\\*\" &&\n+    cat >expected_files <<EOF &&\n+*\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check f* wildcard in git add' '\n+    reset_git_repo &&\n+    git add \"f*\" &&\n+    cat >expected_files <<EOF &&\n+f*\n+f**\n+f?z\n+foo*bar\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check f\\* literal in git add' '\n+    reset_git_repo &&\n+    git add \"f\\*\" &&\n+    cat >expected_files <<EOF &&\n+f*\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check f** wildcard in git add' '\n+    reset_git_repo &&\n+    git add \"f**\" &&\n+    cat >expected_files <<EOF &&\n+f*\n+f**\n+f?z\n+foo*bar\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check f\\*\\* literal in git add' '\n+    reset_git_repo &&\n+    git add \"f\\*\\*\" &&\n+    cat >expected_files <<EOF &&\n+f**\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check ? wildcard in git add' '\n+    reset_git_repo &&\n+    git add \"?\" &&\n+    cat >expected_files <<EOF &&\n+*\n+?\n+a\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check \\? literal in git add' '\n+    reset_git_repo &&\n+    git add \"\\?\" &&\n+    cat >expected_files <<EOF &&\n+?\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check hello?world wildcard in git add' '\n+    reset_git_repo &&\n+    git add \"hello?world\" &&\n+    cat >expected_files <<EOF &&\n+hello?world\n+hello_world\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'check hello\\?world literal in git add' '\n+    reset_git_repo &&\n+    git add \"hello\\?world\" &&\n+    cat >expected_files <<EOF &&\n+hello?world\n+EOF\n+    git ls-files >actual_files &&\n+    test_cmp expected_files actual_files\n+'\n+\n+test_expect_success 'commit: wildcard *' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"*\" &&\n+    cat >expected_files <<-\\EOF &&\n+*\n+**\n+?\n+[abc]\n+a\n+f*\n+f**\n+f?z\n+foo*bar\n+hello?world\n+hello_world\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: literal *' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"\\*\" &&\n+    cat >expected_files <<-\\EOF &&\n+*\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: wildcard f*' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"f*\" &&\n+    cat >expected_files <<-\\EOF &&\n+f*\n+f**\n+f?z\n+foo*bar\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: literal f\\*' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"f\\*\" &&\n+    cat >expected_files <<-\\EOF &&\n+f*\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: wildcard pathspec limits commit' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"f**\" &&\n+    cat >expected_files <<-\\EOF &&\n+f*\n+f**\n+f?z\n+foo*bar\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: literal f\\*\\*' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"f\\*\\*\" &&\n+    cat >expected_files <<-\\EOF &&\n+f**\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: wildcard ?' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"?\" &&\n+    cat >expected_files <<-\\EOF &&\n+*\n+?\n+a\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'commit: literal \\?' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"\\?\" &&\n+    cat >expected_files <<-\\EOF &&\n+?\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'check hello?world wildcard in git commit' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"hello?world\" &&\n+    cat >expected_files <<-\\EOF &&\n+hello?world\n+hello_world\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+test_expect_success 'check hello\\?world literal in git commit' '\n+    reset_git_repo &&\n+    git add . &&\n+    git commit --allow-empty -m \"Test\" -- \"hello\\?world\" &&\n+    cat >expected_files <<-\\EOF &&\n+hello?world\n+EOF\n+    git ls-tree -r --name-only HEAD > actual_files &&\n+    test_cmp expected_files actual_files \n+'\n+\n+end_test_properly\n+\n+test_done\n-- \n2.49.0.223.ga3111b2db4.dirty\n\n"},{"id":"516523","messageId":"xmqqecxk3u5l.fsf@gitster.g","threadId":"63331","inReplyTo":"20250422160547.577524-1-jayatheerthkulkarni2005@gmail.com","subject":"Re: [PATCH v2] Dir: Fix and test wildcard pathspec handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-04-22T18:53:10Z","receivedAt":"2025-04-22T18:53:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"K Jayatheerth <jayatheerthkulkarni2005@gmail.com> writes:\n\n> Subject: Re: [PATCH v2] Dir: Fix and test wildcard pathspec handling\n\nSubject: dir.c: literal match with wildcard in pathspec should still glob\n\nor something?  \"Fix\" implies something may have been broken and the\nchange was an attempt to correct it, but otherwise it does not say\nanything about what was wrong and how it was improved.\n\n\n\n\n> Ensure wildcards expand, even with literal file match.\n> Fixes 'git add f*' skipping files like 'foo' if 'f*' exists.\n\nThe usual way to compose a log message of this project is to\n\n - Give an observation on how the current system work in the present\n   tense (so no need to say \"Currently X is Y\", just \"X is Y\"), and\n   discuss what you perceive as a problem in it.\n\n - Propose a solution (optional---often, problem description\n   trivially leads to an obvious solution in reader's minds).\n\n - Give commands to the codebase to \"become like so\".\n\nin this order.  In the above, a clear problem description, an\nobservation on how the current behaviour is not what you want to\nsee, is missing.\n\n    With a path with wildcard characters, e.g. 'f*o', exists in the\n    working tree, \"git add -- 'f*o'\" stops after happily finding\n    that there is 'f*o' and adding it to the index, without\n    realizing there may be other paths, e.g. 'foooo', that may match\n    the given pathspec.\n\n    This is because dir.c:do_match_pathspec() disables further\n    matches with pathspec when it finds an exact match.\n\nor something.  The first paragraph gives end-user visible behaviour\n(so that readers can try it at home if they wanted to), and then you\nadd a bit of explanation of the reason why it happens in the current\ncode.\n\nThen it would be rather obvious how to correct it, so you probably\ndo not have to repeat what you did in the code in the log message in\nthis case.\n\n> Use 'f\\*' to add the literal.\n\nThe proposed log message is not a place to give an introductory\nshell syntax lesson to your readers.\n\nRemember, what you _did_ in the patch can be read by readers.  What\nthey may need help reading your patch is _why_ you did them, which\nmay not be obvious at times.  For example,\n\n> Tests added for add and commit where dir.c logic applies.\n\nyour readers can see you only covered \"add\" and \"commit\" in the new\ntests, but they cannot read your mind to find out why you did not\nadd tests for, say, \"git rm f\\*\".  If you want to say this line, it\nshould explain how add and commit are affected by the code (and\npossibly, how other commands are not affected, but that is\noptional).\n\n> Skips windows specific test.\n\nAgain, from the code we can read the test runs only on platforms\nthat can do FUNNYNAMES (not necessarily Windows-specific).  If you\nwant to say this line, it should explain why.\n\n    As some file systems are incapable of holding files with\n    wildcard letters in their names, guard the whole test script\n    with FUNNYNAMES prerequisite.\n\nor something.\n\nTo those who have been intimately following the discussion, it often\nis understandable without some of the above, but we are not writing\nfor those who review the patches.  We are primarily writing for future\nreaders of \"git log\" who are not aware of the review discussion we\nhave on list, so we should give something to prepare them by setting\nthe stage and stating the objective first, before going into how the\npatch solved it.\n\n> reported-by: piotrsiupa <piotrsiupa@gmail.com>\n> Mentored-by: Jeff King <peff@peff.net>\n> Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>\n\nUnless this is part of a project done as some mentorship program\nlike GSoC and Outreachy, Helped-by: would be more appropriate.  It\nis not like Peff is assigned as your mentor for working on this\nparticular \"fix wildcard\" project, is it?\n\n> -\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n> +\t\tif (seen && seen[i] == MATCHED_EXACTLY &&\n> +\t\t\tps->items[i].nowildcard_len == ps->items[i].len)\n>  \t\t\tcontinue;\n\nWe usually align the first letter of this second line with the first\nletter of the same expression (i.e. \"seen\"), so this looks a bit\nunconventionally indented, but the logic is correct, it seems.  If\nthe entire pathspec is without wildcard, then there is no reason to\nspend more cycles to look for more matches, but otherwise, we may\nfind other paths that may match, so we do not continue and perform\nthe rest of the loop.\n\nOK.\n\n> diff --git a/t/t6137-pathspec-wildcards-literal.sh b/t/t6137-pathspec-wildcards-literal.sh\n> new file mode 100755\n> index 0000000000..abf837bf6c\n> --- /dev/null\n> +++ b/t/t6137-pathspec-wildcards-literal.sh\n> @@ -0,0 +1,282 @@\n> +#!/bin/sh\n> +\n> +test_description='test wildcards and literals with various git commands'\n> +\n> +. ./test-lib.sh\n> +\n> +test_have_prereq FUNNYNAMES || {\n> +    skip_all='skipping: needs FUNNYNAMES (non-Windows only)'\n> +    test_done\n> +}\n\nDo not do 4-space indentation.  We indent with HT (tab).\n\ncf. Documentation/CodingGuidelines\n\n> +reset_git_repo () {\n> +    rm -rf .git &&\n> +    git init &&\n> +    rm -rf \"actual_files\" \"expected_files\"\n\nIf you have the habit of using \"-r\" unnecessarily, lose it.\n\n\trm -f actual_files expected_files\n\nAlso it is easier to readers if you leave these \"obviously literal\"\nnames without quoted.\n\n> +}\n> +\n> +end_test_properly() {\n\nStyle.\n\n\n> +    cd .. &&\n> +    rm -rf \"testdir\"\n> +}\n> +\n> +\n> +test_expect_success 'setup' '\n> +    mkdir testdir &&\n> +    cd testdir &&\n> +    touch \"*\" \"?\" \"[abc]\" \"f*\" \"f?z\" \"a\" &&\n> +    touch \"**\" \"foo*bar\" \"hello?world\" \"f**\" \"hello_world\" &&\n> +    git init\n> +'\n\nThis is a bad pattern.  What happens if any of the statements failed\nbefore or after you did \"cd testdir\"?  The next and subsequent test\nmay or may not run inside \"testdir\".  The call to end_test at the end\nwould then go one level up (usually leading you to the t/ directory)\nand try to clean things up there, which is not what you want.\n\n> +test_expect_success 'check * wildcard in git add' '\n> +    git init &&\n\nIn the previous you did \"init\".  What is the reason why you do\nanother in the same directory?\n\nRather, do things perhaps like this?\n\n\tgit init test-add-asterisk &&\n\t(\n\t\tcd test-add-asterisk &&\n                prepare_test_files &&\n\t\tgit add \\* &&\n\t\tcat >expect <<-\\EOF &&\n\t\t*\n\t\t**\n\t\t?\n\t\t...\n\t\tEOF\n\t\tgit ls-files >actual &&\n\t\ttest_cmp expect actual\n\t)\n\nThat way, each test will be more independent from other tests.\n\nAlso unless you have to test with large quantity of data and want to\nremove them from the disk as soon as you are done, do not sprinkle\nyour test with unnecessary \"remove the repository and test data\"\ncode.  It is easier when tests do break if you leave them be.\n\nAlso notice the use of \"-\" prefix to cause the leading tabs stripped\nfrom the HERE-DOC lines, and quoting of EOF (here I used \\EOF for\nbrevity and because it is customary to do so but you could use \"EOF\"\nor 'EOF') that causes the HERE-DOC text to taken literally.  They\nare both conventions used in this project to make the here-doc text\neasier to read.\n\nThe prepare_test_files helper may do\n\n\tprepare_test_files () {\n\t\tfor f in \"*\" \"?\" \"[abc]\" \"f*\" ...\n\t\tdo\n\t\t\t>\"$f\" || return\n\t\tdone\n\t}\t\n\nI'll stop here.\n\nThanks.\n"},{"id":"517166","messageId":"20250503060736.587286-1-jayatheerthkulkarni2005@gmail.com","threadId":"63331","inReplyTo":"xmqqecxk3u5l.fsf@gitster.g","subject":"[PATCH] dir.c: literal match with wildcard in pathspec should still glob","fromName":"K Jayatheerth","fromEmail":"jayatheerthkulkarni2005@gmail.com","sentAt":"2025-05-03T06:07:36Z","receivedAt":"2025-05-03T06:07:58Z","isPatch":true,"sender":{"key":"jayatheerthkulkarni2005@gmail.com","avatar":"https://avatars.githubusercontent.com/u/148841023?v=4"},"body":"With a path with wildcard characters, e.g. 'f*o', exists in the\nworking tree, \"git add -- 'f*o'\" stops after happily finding\nthat there is 'f*o' and adding it to the index, without\nrealizing there may be other paths, e.g. 'foooo', that may match\nthe given pathspec.\n\nThis is because dir.c:do_match_pathspec() disables further\nmatches with pathspec when it finds an exact match.\n\nReported-by: piotrsiupa <piotrsiupa@gmail.com>\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>\n---\n dir.c                                 |   3 +-\n t/meson.build                         |   1 +\n t/t6137-pathspec-wildcards-literal.sh | 429 ++++++++++++++++++++++++++\n 3 files changed, 432 insertions(+), 1 deletion(-)\n create mode 100755 t/t6137-pathspec-wildcards-literal.sh\n\ndiff --git a/dir.c b/dir.c\nindex 28b0e03feb..9405fee83a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -519,7 +519,8 @@ static int do_match_pathspec(struct index_state *istate,\n \t\t    ( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))\n \t\t\tcontinue;\n \n-\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n+\t\tif (seen && seen[i] == MATCHED_EXACTLY &&\n+\t\t\tps->items[i].nowildcard_len == ps->items[i].len)\n \t\t\tcontinue;\n \t\t/*\n \t\t * Make exclude patterns optional and never report\ndiff --git a/t/meson.build b/t/meson.build\nindex bfb744e886..61285852e9 100644\n--- a/t/meson.build\n+++ b/t/meson.build\n@@ -788,6 +788,7 @@ integration_tests = [\n   't6134-pathspec-in-submodule.sh',\n   't6135-pathspec-with-attrs.sh',\n   't6136-pathspec-in-bare.sh',\n+  't6137-pathspec-wildcards-literal.sh',\n   't6200-fmt-merge-msg.sh',\n   't6300-for-each-ref.sh',\n   't6301-for-each-ref-errors.sh',\ndiff --git a/t/t6137-pathspec-wildcards-literal.sh b/t/t6137-pathspec-wildcards-literal.sh\nnew file mode 100755\nindex 0000000000..20abad5667\n--- /dev/null\n+++ b/t/t6137-pathspec-wildcards-literal.sh\n@@ -0,0 +1,429 @@\n+#!/bin/sh\n+test_description='test wildcards and literals with git add/commit (subshell style)'\n+\n+. ./test-lib.sh\n+\n+test_have_prereq FUNNYNAMES || {\n+\tskip_all='skipping: needs FUNNYNAMES (non-Windows only)'\n+\ttest_done\n+}\n+\n+prepare_test_files () {\n+\tfor f in \"*\" \"**\" \"?\" \"[abc]\" \"a\" \"f*\" \"f**\" \"f?z\" \"foo*bar\" \"hello?world\" \"hello_world\"\n+\tdo\n+\t\t>\"$f\" || return\n+\tdone\n+}\n+\n+test_expect_success 'add wildcard *' '\n+\tgit init test-asterisk &&\n+\t(\n+\t\tcd test-asterisk &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t**\n+\t\t?\n+\t\t[abc]\n+\t\ta\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal \\*' '\n+\tgit init test-asterisk-literal &&\n+\t(\n+\t\tcd test-asterisk-literal &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard **' '\n+\tgit init test-dstar &&\n+\t(\n+\t\tcd test-dstar &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"**\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t**\n+\t\t?\n+\t\t[abc]\n+\t\ta\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard ?' '\n+\tgit init test-qmark &&\n+\t(\n+\t\tcd test-qmark &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"?\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\t*\n+\t\t?\n+\t\ta\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard [abc]' '\n+\tgit init test-brackets &&\n+\t(\n+\t\tcd test-brackets &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"[abc]\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\t[abc]\n+\t\ta\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard f*' '\n+\tgit init test-f-wild &&\n+\t(\n+\t\tcd test-f-wild &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f*\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal f\\*' '\n+\tgit init test-f-lit &&\n+\t(\n+\t\tcd test-f-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f\\*\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tf*\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard f**' '\n+\tgit init test-fdstar &&\n+\t(\n+\t\tcd test-fdstar &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f**\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal f\\*\\*' '\n+\tgit init test-fdstar-lit &&\n+\t(\n+\t\tcd test-fdstar-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f\\*\\*\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tf**\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard f?z' '\n+\tgit init test-fqz &&\n+\t(\n+\t\tcd test-fqz &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f?z\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tf?z\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal \\? literal' '\n+\tgit init test-q-lit &&\n+\t(\n+\t\tcd test-q-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"\\?\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\t?\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard foo*bar' '\n+\tgit init test-foobar &&\n+\t(\n+\t\tcd test-foobar &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"foo*bar\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard hello?world' '\n+\tgit init test-hellowild &&\n+\t(\n+\t\tcd test-hellowild &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"hello?world\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal hello\\?world' '\n+\tgit init test-hellolit &&\n+\t(\n+\t\tcd test-hellolit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"hello\\?world\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\thello?world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal [abc]' '\n+\tgit init test-brackets-lit &&\n+\t(\n+\t\tcd test-brackets-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"\\[abc\\]\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\t[abc]\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard *' '\n+\tgit init test-c-asterisk &&\n+\t(\n+\t\tcd test-c-asterisk &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c1\" -- \"*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t**\n+\t\t?\n+\t\t[abc]\n+\t\ta\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal *' '\n+\tgit init test-c-asterisk-lit &&\n+\t(\n+\t\tcd test-c-asterisk-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c2\" -- \"\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard f*' '\n+\tgit init test-c-fwild &&\n+\t(\n+\t\tcd test-c-fwild &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c3\" -- \"f*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal f\\*' '\n+\tgit init test-c-flit &&\n+\t(\n+\t\tcd test-c-flit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c4\" -- \"f\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf*\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard pathspec limits commit' '\n+\tgit init test-c-pathlimit &&\n+\t(\n+\t\tcd test-c-pathlimit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c5\" -- \"f**\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal f\\*\\*' '\n+\tgit init test-c-fdstar-lit &&\n+\t(\n+\t\tcd test-c-fdstar-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c6\" -- \"f\\*\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf**\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard ?' '\n+\tgit init test-c-qwild &&\n+\t(\n+\t\tcd test-c-qwild &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c7\" -- \"?\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t?\n+\t\ta\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD | sort >actual &&\n+\t\tsort expect >expect.sorted &&\n+\t\ttest_cmp expect.sorted actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal \\?' '\n+\tgit init test-c-qlit &&\n+\t(\n+\t\tcd test-c-qlit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c8\" -- \"\\?\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t?\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard hello?world' '\n+\tgit init test-c-hellowild &&\n+\t(\n+\t\tcd test-c-hellowild &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c9\" -- \"hello?world\"  &&\n+\t\tcat >expect <<-EOF &&\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD | sort >actual &&\n+\t\tsort expect >expect.sorted &&\n+\t\ttest_cmp expect.sorted actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal hello\\?world' '\n+\tgit init test-c-hellolit &&\n+\t(\n+\t\tcd test-c-hellolit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c10\" -- \"hello\\?world\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\thello?world\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_done\n-- \n2.49.GIT\n\n"},{"id":"517167","messageId":"CA+rGoLfFCi-q52ABUr=0O=pu+qSikcomSk1akHWUkfAfSf=pZg@mail.gmail.com","threadId":"63331","inReplyTo":"20250503060736.587286-1-jayatheerthkulkarni2005@gmail.com","subject":"Re: [PATCH] dir.c: literal match with wildcard in pathspec should still glob","fromName":"JAYATHEERTH K","fromEmail":"jayatheerthkulkarni2005@gmail.com","sentAt":"2025-05-03T06:24:40Z","receivedAt":"2025-05-03T06:24:52Z","isPatch":true,"sender":{"key":"jayatheerthkulkarni2005@gmail.com","avatar":"https://avatars.githubusercontent.com/u/148841023?v=4"},"body":"On Sat, May 3, 2025 at 11:37 AM K Jayatheerth\n<jayatheerthkulkarni2005@gmail.com> wrote:\n>\n> With a path with wildcard characters, e.g. 'f*o', exists in the\n> working tree, \"git add -- 'f*o'\" stops after happily finding\n> that there is 'f*o' and adding it to the index, without\n> realizing there may be other paths, e.g. 'foooo', that may match\n> the given pathspec.\n>\n> This is because dir.c:do_match_pathspec() disables further\n> matches with pathspec when it finds an exact match.\n>\n> Reported-by: piotrsiupa <piotrsiupa@gmail.com>\n> Helped-by: Jeff King <peff@peff.net>\n> Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>\n> ---\n>  dir.c                                 |   3 +-\n>  t/meson.build                         |   1 +\n>  t/t6137-pathspec-wildcards-literal.sh | 429 ++++++++++++++++++++++++++\n>  3 files changed, 432 insertions(+), 1 deletion(-)\n>  create mode 100755 t/t6137-pathspec-wildcards-literal.sh\n>\n> diff --git a/dir.c b/dir.c\n> index 28b0e03feb..9405fee83a 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -519,7 +519,8 @@ static int do_match_pathspec(struct index_state *istate,\n>                     ( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))\n>                         continue;\n>\n> -               if (seen && seen[i] == MATCHED_EXACTLY)\n> +               if (seen && seen[i] == MATCHED_EXACTLY &&\n> +                       ps->items[i].nowildcard_len == ps->items[i].len)\n>                         continue;\n\nFor some reason on my computer when I check the formatted patch the\nps-> line\nalign with the (seen && ...) line perfectly\nAgain when I send the mail it is shifted forward,\nI ensured to use tab space instead of 4 spaces as previously asked.\n\n-Jayatheerth\n"},{"id":"517252","messageId":"xmqqwmavqfvp.fsf@gitster.g","threadId":"63331","inReplyTo":"CA+rGoLfFCi-q52ABUr=0O=pu+qSikcomSk1akHWUkfAfSf=pZg@mail.gmail.com","subject":"Re: [PATCH] dir.c: literal match with wildcard in pathspec should still glob","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-05-05T14:41:30Z","receivedAt":"2025-05-05T14:41:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"JAYATHEERTH K <jayatheerthkulkarni2005@gmail.com> writes:\n\n>> +               if (seen && seen[i] == MATCHED_EXACTLY &&\n>> +                       ps->items[i].nowildcard_len == ps->items[i].len)\n>>                         continue;\n>\n> For some reason on my computer when I check the formatted patch the\n> ps-> line\n> align with the (seen && ...) line perfectly\n\nBecause the quoted patch in the message I am responding to has tabs\nexpanded already, probably by your mailer, I looked at what you\noriginally posted, and it has these lines:\n\n-\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n+\t\tif (seen && seen[i] == MATCHED_EXACTLY &&\n+\t\t\tps->items[i].nowildcard_len == ps->items[i].len)\n \t\t\tcontinue;\n\nRemoving the prefix '+'/'-'/' ', and replacing HT with ^I for\nvisibility, the above looks like this:\n\n^I^Iif (seen && seen[i] == MATCHED_EXACTLY)\n^I^Iif (seen && seen[i] == MATCHED_EXACTLY &&\n^I^I^Ips->items[i].nowildcard_len == ps->items[i].len)\n^I^I^Icontinue;\n\nAs the display width in monospace for \"if (\" is 4 spaces, \"seen\" and\n\"ps->\" would align only if the third HT expands to 4 spaces on your\nsystem.\n\nPerhaps because you are telling your editor or terminal that your\ntab, unlike everybody else's, is 4-space wide or something?\n"},{"id":"517253","messageId":"20250505150203.28408-1-jayatheerthkulkarni2005@gmail.com","threadId":"63331","inReplyTo":"xmqqwmavqfvp.fsf@gitster.g","subject":"[PATCH] dir.c: literal match with wildcard in pathspec should still glob","fromName":"K Jayatheerth","fromEmail":"jayatheerthkulkarni2005@gmail.com","sentAt":"2025-05-05T15:02:03Z","receivedAt":"2025-05-05T15:02:17Z","isPatch":true,"sender":{"key":"jayatheerthkulkarni2005@gmail.com","avatar":"https://avatars.githubusercontent.com/u/148841023?v=4"},"body":"With a path with wildcard characters, e.g. 'f*o', exists in the\nworking tree, \"git add -- 'f*o'\" stops after happily finding\nthat there is 'f*o' and adding it to the index, without\nrealizing there may be other paths, e.g. 'foooo', that may match\nthe given pathspec.\n\nThis is because dir.c:do_match_pathspec() disables further\nmatches with pathspec when it finds an exact match.\n\nReported-by: piotrsiupa <piotrsiupa@gmail.com>\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>\n---\n dir.c                                 |   3 +-\n t/meson.build                         |   1 +\n t/t6137-pathspec-wildcards-literal.sh | 429 ++++++++++++++++++++++++++\n 3 files changed, 432 insertions(+), 1 deletion(-)\n create mode 100755 t/t6137-pathspec-wildcards-literal.sh\n\ndiff --git a/dir.c b/dir.c\nindex 28b0e03feb..e162947d0a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -519,7 +519,8 @@ static int do_match_pathspec(struct index_state *istate,\n \t\t    ( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))\n \t\t\tcontinue;\n \n-\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n+\t\tif (seen && seen[i] == MATCHED_EXACTLY && \n+\t\t   ps->items[i].nowildcard_len == ps->items[i].len)\n \t\t\tcontinue;\n \t\t/*\n \t\t * Make exclude patterns optional and never report\ndiff --git a/t/meson.build b/t/meson.build\nindex bfb744e886..61285852e9 100644\n--- a/t/meson.build\n+++ b/t/meson.build\n@@ -788,6 +788,7 @@ integration_tests = [\n   't6134-pathspec-in-submodule.sh',\n   't6135-pathspec-with-attrs.sh',\n   't6136-pathspec-in-bare.sh',\n+  't6137-pathspec-wildcards-literal.sh',\n   't6200-fmt-merge-msg.sh',\n   't6300-for-each-ref.sh',\n   't6301-for-each-ref-errors.sh',\ndiff --git a/t/t6137-pathspec-wildcards-literal.sh b/t/t6137-pathspec-wildcards-literal.sh\nnew file mode 100755\nindex 0000000000..20abad5667\n--- /dev/null\n+++ b/t/t6137-pathspec-wildcards-literal.sh\n@@ -0,0 +1,429 @@\n+#!/bin/sh\n+test_description='test wildcards and literals with git add/commit (subshell style)'\n+\n+. ./test-lib.sh\n+\n+test_have_prereq FUNNYNAMES || {\n+\tskip_all='skipping: needs FUNNYNAMES (non-Windows only)'\n+\ttest_done\n+}\n+\n+prepare_test_files () {\n+\tfor f in \"*\" \"**\" \"?\" \"[abc]\" \"a\" \"f*\" \"f**\" \"f?z\" \"foo*bar\" \"hello?world\" \"hello_world\"\n+\tdo\n+\t\t>\"$f\" || return\n+\tdone\n+}\n+\n+test_expect_success 'add wildcard *' '\n+\tgit init test-asterisk &&\n+\t(\n+\t\tcd test-asterisk &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t**\n+\t\t?\n+\t\t[abc]\n+\t\ta\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal \\*' '\n+\tgit init test-asterisk-literal &&\n+\t(\n+\t\tcd test-asterisk-literal &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard **' '\n+\tgit init test-dstar &&\n+\t(\n+\t\tcd test-dstar &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"**\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t**\n+\t\t?\n+\t\t[abc]\n+\t\ta\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard ?' '\n+\tgit init test-qmark &&\n+\t(\n+\t\tcd test-qmark &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"?\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\t*\n+\t\t?\n+\t\ta\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard [abc]' '\n+\tgit init test-brackets &&\n+\t(\n+\t\tcd test-brackets &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"[abc]\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\t[abc]\n+\t\ta\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard f*' '\n+\tgit init test-f-wild &&\n+\t(\n+\t\tcd test-f-wild &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f*\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal f\\*' '\n+\tgit init test-f-lit &&\n+\t(\n+\t\tcd test-f-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f\\*\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tf*\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard f**' '\n+\tgit init test-fdstar &&\n+\t(\n+\t\tcd test-fdstar &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f**\" &&\n+\t\tcat >expect <<-\\EOF | sort &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-files | sort >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal f\\*\\*' '\n+\tgit init test-fdstar-lit &&\n+\t(\n+\t\tcd test-fdstar-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f\\*\\*\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tf**\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard f?z' '\n+\tgit init test-fqz &&\n+\t(\n+\t\tcd test-fqz &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"f?z\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tf?z\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal \\? literal' '\n+\tgit init test-q-lit &&\n+\t(\n+\t\tcd test-q-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"\\?\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\t?\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard foo*bar' '\n+\tgit init test-foobar &&\n+\t(\n+\t\tcd test-foobar &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"foo*bar\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add wildcard hello?world' '\n+\tgit init test-hellowild &&\n+\t(\n+\t\tcd test-hellowild &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"hello?world\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal hello\\?world' '\n+\tgit init test-hellolit &&\n+\t(\n+\t\tcd test-hellolit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"hello\\?world\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\thello?world\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add literal [abc]' '\n+\tgit init test-brackets-lit &&\n+\t(\n+\t\tcd test-brackets-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add \"\\[abc\\]\" &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\t[abc]\n+\t\tEOF\n+\t\tgit ls-files >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard *' '\n+\tgit init test-c-asterisk &&\n+\t(\n+\t\tcd test-c-asterisk &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c1\" -- \"*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t**\n+\t\t?\n+\t\t[abc]\n+\t\ta\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal *' '\n+\tgit init test-c-asterisk-lit &&\n+\t(\n+\t\tcd test-c-asterisk-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c2\" -- \"\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard f*' '\n+\tgit init test-c-fwild &&\n+\t(\n+\t\tcd test-c-fwild &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c3\" -- \"f*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal f\\*' '\n+\tgit init test-c-flit &&\n+\t(\n+\t\tcd test-c-flit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c4\" -- \"f\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf*\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard pathspec limits commit' '\n+\tgit init test-c-pathlimit &&\n+\t(\n+\t\tcd test-c-pathlimit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c5\" -- \"f**\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf*\n+\t\tf**\n+\t\tf?z\n+\t\tfoo*bar\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal f\\*\\*' '\n+\tgit init test-c-fdstar-lit &&\n+\t(\n+\t\tcd test-c-fdstar-lit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c6\" -- \"f\\*\\*\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\tf**\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard ?' '\n+\tgit init test-c-qwild &&\n+\t(\n+\t\tcd test-c-qwild &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c7\" -- \"?\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t*\n+\t\t?\n+\t\ta\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD | sort >actual &&\n+\t\tsort expect >expect.sorted &&\n+\t\ttest_cmp expect.sorted actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal \\?' '\n+\tgit init test-c-qlit &&\n+\t(\n+\t\tcd test-c-qlit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c8\" -- \"\\?\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\t?\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'commit: wildcard hello?world' '\n+\tgit init test-c-hellowild &&\n+\t(\n+\t\tcd test-c-hellowild &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c9\" -- \"hello?world\"  &&\n+\t\tcat >expect <<-EOF &&\n+\t\thello?world\n+\t\thello_world\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD | sort >actual &&\n+\t\tsort expect >expect.sorted &&\n+\t\ttest_cmp expect.sorted actual\n+\t)\n+'\n+\n+test_expect_success 'commit: literal hello\\?world' '\n+\tgit init test-c-hellolit &&\n+\t(\n+\t\tcd test-c-hellolit &&\n+\t\tprepare_test_files &&\n+\t\tgit add . &&\n+\t\tgit commit -m \"c10\" -- \"hello\\?world\" &&\n+\t\tcat >expect <<-EOF &&\n+\t\thello?world\n+\t\tEOF\n+\t\tgit ls-tree -r --name-only HEAD >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_done\n-- \n2.49.GIT\n\n"},{"id":"517254","messageId":"CA+rGoLe5-Jk=nQ_hv0gVgNH4BTdcHDZ1SP7_Xo9rPUkNADFNPQ@mail.gmail.com","threadId":"63331","inReplyTo":"xmqqwmavqfvp.fsf@gitster.g","subject":"Re: [PATCH] dir.c: literal match with wildcard in pathspec should still glob","fromName":"JAYATHEERTH K","fromEmail":"jayatheerthkulkarni2005@gmail.com","sentAt":"2025-05-05T15:03:06Z","receivedAt":"2025-05-05T15:03:18Z","isPatch":true,"sender":{"key":"jayatheerthkulkarni2005@gmail.com","avatar":"https://avatars.githubusercontent.com/u/148841023?v=4"},"body":"On Mon, May 5, 2025 at 8:11 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> JAYATHEERTH K <jayatheerthkulkarni2005@gmail.com> writes:\n>\n> >> +               if (seen && seen[i] == MATCHED_EXACTLY &&\n> >> +                       ps->items[i].nowildcard_len == ps->items[i].len)\n> >>                         continue;\n> >\n> > For some reason on my computer when I check the formatted patch the\n> > ps-> line\n> > align with the (seen && ...) line perfectly\n>\n> Because the quoted patch in the message I am responding to has tabs\n> expanded already, probably by your mailer, I looked at what you\n> originally posted, and it has these lines:\n>\n> -               if (seen && seen[i] == MATCHED_EXACTLY)\n> +               if (seen && seen[i] == MATCHED_EXACTLY &&\n> +                       ps->items[i].nowildcard_len == ps->items[i].len)\n>                         continue;\n>\n> Removing the prefix '+'/'-'/' ', and replacing HT with ^I for\n> visibility, the above looks like this:\n>\n> ^I^Iif (seen && seen[i] == MATCHED_EXACTLY)\n> ^I^Iif (seen && seen[i] == MATCHED_EXACTLY &&\n> ^I^I^Ips->items[i].nowildcard_len == ps->items[i].len)\n> ^I^I^Icontinue;\n>\n> As the display width in monospace for \"if (\" is 4 spaces, \"seen\" and\n> \"ps->\" would align only if the third HT expands to 4 spaces on your\n> system.\n>\n> Perhaps because you are telling your editor or terminal that your\n> tab, unlike everybody else's, is 4-space wide or something?\n\nThank you for the clarification.\nYes it was the 4 tab thing, my editor has default as 4 therefore the confusion.\n\n-Jayatheerth\n"}]}