From: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
To: gitster@pobox.com
Cc: git@vger.kernel.org, jayatheerthkulkarni2005@gmail.com,
lucasseikioshiro@gmail.com, peff@peff.net, piotrsiupa@gmail.com,
sandals@crustytoothpaste.net
Subject: [PATCH] dir.c: literal match with wildcard in pathspec should still glob
Date: Mon, 5 May 2025 20:32:03 +0530 [thread overview]
Message-ID: <20250505150203.28408-1-jayatheerthkulkarni2005@gmail.com> (raw)
In-Reply-To: <xmqqwmavqfvp.fsf@gitster.g>
With a path with wildcard characters, e.g. 'f*o', exists in the
working tree, "git add -- 'f*o'" stops after happily finding
that there is 'f*o' and adding it to the index, without
realizing there may be other paths, e.g. 'foooo', that may match
the given pathspec.
This is because dir.c:do_match_pathspec() disables further
matches with pathspec when it finds an exact match.
Reported-by: piotrsiupa <piotrsiupa@gmail.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
---
dir.c | 3 +-
t/meson.build | 1 +
t/t6137-pathspec-wildcards-literal.sh | 429 ++++++++++++++++++++++++++
3 files changed, 432 insertions(+), 1 deletion(-)
create mode 100755 t/t6137-pathspec-wildcards-literal.sh
diff --git a/dir.c b/dir.c
index 28b0e03feb..e162947d0a 100644
--- a/dir.c
+++ b/dir.c
@@ -519,7 +519,8 @@ static int do_match_pathspec(struct index_state *istate,
( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))
continue;
- if (seen && seen[i] == MATCHED_EXACTLY)
+ if (seen && seen[i] == MATCHED_EXACTLY &&
+ ps->items[i].nowildcard_len == ps->items[i].len)
continue;
/*
* Make exclude patterns optional and never report
diff --git a/t/meson.build b/t/meson.build
index bfb744e886..61285852e9 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -788,6 +788,7 @@ integration_tests = [
't6134-pathspec-in-submodule.sh',
't6135-pathspec-with-attrs.sh',
't6136-pathspec-in-bare.sh',
+ 't6137-pathspec-wildcards-literal.sh',
't6200-fmt-merge-msg.sh',
't6300-for-each-ref.sh',
't6301-for-each-ref-errors.sh',
diff --git a/t/t6137-pathspec-wildcards-literal.sh b/t/t6137-pathspec-wildcards-literal.sh
new file mode 100755
index 0000000000..20abad5667
--- /dev/null
+++ b/t/t6137-pathspec-wildcards-literal.sh
@@ -0,0 +1,429 @@
+#!/bin/sh
+test_description='test wildcards and literals with git add/commit (subshell style)'
+
+. ./test-lib.sh
+
+test_have_prereq FUNNYNAMES || {
+ skip_all='skipping: needs FUNNYNAMES (non-Windows only)'
+ test_done
+}
+
+prepare_test_files () {
+ for f in "*" "**" "?" "[abc]" "a" "f*" "f**" "f?z" "foo*bar" "hello?world" "hello_world"
+ do
+ >"$f" || return
+ done
+}
+
+test_expect_success 'add wildcard *' '
+ git init test-asterisk &&
+ (
+ cd test-asterisk &&
+ prepare_test_files &&
+ git add "*" &&
+ cat >expect <<-EOF &&
+ *
+ **
+ ?
+ [abc]
+ a
+ f*
+ f**
+ f?z
+ foo*bar
+ hello?world
+ hello_world
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add literal \*' '
+ git init test-asterisk-literal &&
+ (
+ cd test-asterisk-literal &&
+ prepare_test_files &&
+ git add "\*" &&
+ cat >expect <<-EOF &&
+ *
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard **' '
+ git init test-dstar &&
+ (
+ cd test-dstar &&
+ prepare_test_files &&
+ git add "**" &&
+ cat >expect <<-EOF &&
+ *
+ **
+ ?
+ [abc]
+ a
+ f*
+ f**
+ f?z
+ foo*bar
+ hello?world
+ hello_world
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard ?' '
+ git init test-qmark &&
+ (
+ cd test-qmark &&
+ prepare_test_files &&
+ git add "?" &&
+ cat >expect <<-\EOF | sort &&
+ *
+ ?
+ a
+ EOF
+ git ls-files | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard [abc]' '
+ git init test-brackets &&
+ (
+ cd test-brackets &&
+ prepare_test_files &&
+ git add "[abc]" &&
+ cat >expect <<-\EOF | sort &&
+ [abc]
+ a
+ EOF
+ git ls-files | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard f*' '
+ git init test-f-wild &&
+ (
+ cd test-f-wild &&
+ prepare_test_files &&
+ git add "f*" &&
+ cat >expect <<-\EOF | sort &&
+ f*
+ f**
+ f?z
+ foo*bar
+ EOF
+ git ls-files | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add literal f\*' '
+ git init test-f-lit &&
+ (
+ cd test-f-lit &&
+ prepare_test_files &&
+ git add "f\*" &&
+ cat >expect <<-\EOF &&
+ f*
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard f**' '
+ git init test-fdstar &&
+ (
+ cd test-fdstar &&
+ prepare_test_files &&
+ git add "f**" &&
+ cat >expect <<-\EOF | sort &&
+ f*
+ f**
+ f?z
+ foo*bar
+ EOF
+ git ls-files | sort >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add literal f\*\*' '
+ git init test-fdstar-lit &&
+ (
+ cd test-fdstar-lit &&
+ prepare_test_files &&
+ git add "f\*\*" &&
+ cat >expect <<-\EOF &&
+ f**
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard f?z' '
+ git init test-fqz &&
+ (
+ cd test-fqz &&
+ prepare_test_files &&
+ git add "f?z" &&
+ cat >expect <<-\EOF &&
+ f?z
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add literal \? literal' '
+ git init test-q-lit &&
+ (
+ cd test-q-lit &&
+ prepare_test_files &&
+ git add "\?" &&
+ cat >expect <<-\EOF &&
+ ?
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard foo*bar' '
+ git init test-foobar &&
+ (
+ cd test-foobar &&
+ prepare_test_files &&
+ git add "foo*bar" &&
+ cat >expect <<-\EOF &&
+ foo*bar
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add wildcard hello?world' '
+ git init test-hellowild &&
+ (
+ cd test-hellowild &&
+ prepare_test_files &&
+ git add "hello?world" &&
+ cat >expect <<-\EOF &&
+ hello?world
+ hello_world
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add literal hello\?world' '
+ git init test-hellolit &&
+ (
+ cd test-hellolit &&
+ prepare_test_files &&
+ git add "hello\?world" &&
+ cat >expect <<-\EOF &&
+ hello?world
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'add literal [abc]' '
+ git init test-brackets-lit &&
+ (
+ cd test-brackets-lit &&
+ prepare_test_files &&
+ git add "\[abc\]" &&
+ cat >expect <<-\EOF &&
+ [abc]
+ EOF
+ git ls-files >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: wildcard *' '
+ git init test-c-asterisk &&
+ (
+ cd test-c-asterisk &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c1" -- "*" &&
+ cat >expect <<-EOF &&
+ *
+ **
+ ?
+ [abc]
+ a
+ f*
+ f**
+ f?z
+ foo*bar
+ hello?world
+ hello_world
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: literal *' '
+ git init test-c-asterisk-lit &&
+ (
+ cd test-c-asterisk-lit &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c2" -- "\*" &&
+ cat >expect <<-EOF &&
+ *
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: wildcard f*' '
+ git init test-c-fwild &&
+ (
+ cd test-c-fwild &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c3" -- "f*" &&
+ cat >expect <<-EOF &&
+ f*
+ f**
+ f?z
+ foo*bar
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: literal f\*' '
+ git init test-c-flit &&
+ (
+ cd test-c-flit &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c4" -- "f\*" &&
+ cat >expect <<-EOF &&
+ f*
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: wildcard pathspec limits commit' '
+ git init test-c-pathlimit &&
+ (
+ cd test-c-pathlimit &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c5" -- "f**" &&
+ cat >expect <<-EOF &&
+ f*
+ f**
+ f?z
+ foo*bar
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: literal f\*\*' '
+ git init test-c-fdstar-lit &&
+ (
+ cd test-c-fdstar-lit &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c6" -- "f\*\*" &&
+ cat >expect <<-EOF &&
+ f**
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: wildcard ?' '
+ git init test-c-qwild &&
+ (
+ cd test-c-qwild &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c7" -- "?" &&
+ cat >expect <<-EOF &&
+ *
+ ?
+ a
+ EOF
+ git ls-tree -r --name-only HEAD | sort >actual &&
+ sort expect >expect.sorted &&
+ test_cmp expect.sorted actual
+ )
+'
+
+test_expect_success 'commit: literal \?' '
+ git init test-c-qlit &&
+ (
+ cd test-c-qlit &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c8" -- "\?" &&
+ cat >expect <<-EOF &&
+ ?
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit: wildcard hello?world' '
+ git init test-c-hellowild &&
+ (
+ cd test-c-hellowild &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c9" -- "hello?world" &&
+ cat >expect <<-EOF &&
+ hello?world
+ hello_world
+ EOF
+ git ls-tree -r --name-only HEAD | sort >actual &&
+ sort expect >expect.sorted &&
+ test_cmp expect.sorted actual
+ )
+'
+
+test_expect_success 'commit: literal hello\?world' '
+ git init test-c-hellolit &&
+ (
+ cd test-c-hellolit &&
+ prepare_test_files &&
+ git add . &&
+ git commit -m "c10" -- "hello\?world" &&
+ cat >expect <<-EOF &&
+ hello?world
+ EOF
+ git ls-tree -r --name-only HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_done
--
2.49.GIT
next prev parent reply other threads:[~2025-05-05 15:02 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-22 16:05 [PATCH v2] Dir: Fix and test wildcard pathspec handling K Jayatheerth
2025-04-22 18:53 ` Junio C Hamano
2025-05-03 6:07 ` [PATCH] dir.c: literal match with wildcard in pathspec should still glob K Jayatheerth
2025-05-03 6:24 ` JAYATHEERTH K
2025-05-05 14:41 ` Junio C Hamano
2025-05-05 15:02 ` K Jayatheerth [this message]
2025-05-05 15:03 ` JAYATHEERTH K
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250505150203.28408-1-jayatheerthkulkarni2005@gmail.com \
--to=jayatheerthkulkarni2005@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=lucasseikioshiro@gmail.com \
--cc=peff@peff.net \
--cc=piotrsiupa@gmail.com \
--cc=sandals@crustytoothpaste.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).