git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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


  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).