Git development
 help / color / mirror / Atom feed
From: Mirko Faina <mroik@delayed.space>
To: git@vger.kernel.org
Cc: Mirko Faina <mroik@delayed.space>, Jeff King <peff@peff.net>,
	Junio C Hamano <gitster@pobox.com>,
	Elijah Newren <newren@gmail.com>,
	Derrick Stolee <stolee@gmail.com>
Subject: [RFC PATCH 4/6] dir.c: teach add_pattern() reject precious pattern
Date: Thu,  8 Oct 2026 14:07:00 +0200	[thread overview]
Message-ID: <b4e2d50f6f5da34a9720d23f487f0db41d2bf3ee.1791460418.git.mroik@delayed.space> (raw)
In-Reply-To: <cover.1791460418.git.mroik@delayed.space>

There are some places where we want to disallow precious files patterns
altogether. This is the case with $GIT_DIR/info/sparse-checkout.

Teach add_pattern() a flag to indicate if we want it to reject
precious files patterns. If that's the case it fails the same way it
would when we encounter a pattern that starts with '!$', with a warning.

Signed-off-by: Mirko Faina <mroik@delayed.space>
---
 builtin/clean.c                    |  4 ++--
 builtin/ls-files.c                 |  2 +-
 builtin/sparse-checkout.c          | 15 +++++++++------
 dir.c                              | 20 +++++++++++++++-----
 dir.h                              |  5 +++--
 t/helper/test-path-walk.c          |  2 +-
 t/t1091-sparse-checkout-builtin.sh |  8 ++++++++
 7 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/builtin/clean.c b/builtin/clean.c
index 1d5e7e5366..73408da5c2 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -707,7 +707,7 @@ static int filter_by_patterns_cmd(void)
 			item = &ignore_list.items[i];
 			if (!*item->string)
 				continue;
-			add_pattern(item->string, "", 0, pl, -(i+1));
+			add_pattern(item->string, "", 0, pl, -(i+1), 0);
 		}
 
 		changed = 0;
@@ -1018,7 +1018,7 @@ int cmd_clean(int argc,
 
 	pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
 	for (i = 0; i < exclude_list.nr; i++)
-		add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
+		add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1), 0);
 
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_CWD,
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index b044520f9e..d1cc7e92f4 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -685,7 +685,7 @@ int cmd_ls_files(int argc,
 			ls_files_usage, 0);
 	pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
 	for (i = 0; i < exclude_list.nr; i++) {
-		add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
+		add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args, 0);
 	}
 
 	if (format && (show_stage || show_others || show_killed ||
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 83981e2b1e..615007148e 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -455,6 +455,8 @@ static struct sparse_checkout_init_opts {
 	int sparse_index;
 } init_opts;
 
+#define PATTERN_DISALLOW_PRECIOUS (1<<1)
+
 static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
 				struct repository *repo)
 {
@@ -487,7 +489,8 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
 	memset(&pl, 0, sizeof(pl));
 
 	sparse_filename = get_sparse_checkout_filename();
-	res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
+	res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL,
+					     PATTERN_DISALLOW_PRECIOUS);
 
 	/* If we already have a sparse-checkout file, use it. */
 	if (res >= 0) {
@@ -515,8 +518,8 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
 
 	free(sparse_filename);
 
-	add_pattern("/*", empty_base, 0, &pl, 0);
-	add_pattern("!/*/", empty_base, 0, &pl, 0);
+	add_pattern("/*", empty_base, 0, &pl, 0, 0);
+	add_pattern("!/*/", empty_base, 0, &pl, 0, 0);
 	pl.use_cone_patterns = init_opts.cone_mode;
 
 	return write_patterns_and_update(repo, &pl);
@@ -618,12 +621,12 @@ static void add_patterns_from_input(struct pattern_list *pl,
 			struct strbuf line = STRBUF_INIT;
 
 			while (!strbuf_getline(&line, file))
-				add_pattern(line.buf, empty_base, 0, pl, 0);
+				add_pattern(line.buf, empty_base, 0, pl, 0, 0);
 
 			strbuf_release(&line);
 		} else {
 			for (i = 0; i < argc; i++)
-				add_pattern(argv[i], empty_base, 0, pl, 0);
+				add_pattern(argv[i], empty_base, 0, pl, 0, 0);
 		}
 	}
 }
@@ -1079,7 +1082,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
 	pl.use_cone_patterns = 0;
 	cfg->apply_sparse_checkout = 1;
 
-	add_pattern("/*", empty_base, 0, &pl, 0);
+	add_pattern("/*", empty_base, 0, &pl, 0, 0);
 
 	prepare_repo_settings(the_repository);
 	repo->settings.sparse_index = 0;
diff --git a/dir.c b/dir.c
index c6f1bed429..9aba1716a6 100644
--- a/dir.c
+++ b/dir.c
@@ -993,7 +993,8 @@ int hashmap_contains_parent(struct hashmap *map,
  * which are negated precious-files.
  */
 void add_pattern(const char *string, const char *base,
-		 int baselen, struct pattern_list *pl, int srcpos)
+		 int baselen, struct pattern_list *pl, int srcpos,
+		 int disable_precious)
 {
 	struct path_pattern *pattern;
 	int patternlen;
@@ -1004,6 +1005,12 @@ void add_pattern(const char *string, const char *base,
 		warning(_("pattern '%s' is problematic, skipping"), string);
 		return;
 	}
+
+	if (disable_precious && (flags & PATTERN_FLAG_PRECIOUS)) {
+		warning(_("'$%s' precious-files pattern not allowed here, skipping"),
+			string);
+		return;
+	}
 	FLEX_ALLOC_MEM(pattern, pattern, string, patternlen);
 	pattern->patternlen = patternlen;
 	pattern->nowildcardlen = nowildcardlen;
@@ -1162,6 +1169,7 @@ static void invalidate_directory(struct untracked_cache *uc,
 
 /* Flags for add_patterns() */
 #define PATTERN_NOFOLLOW (1<<0)
+#define PATTERN_DISALLOW_PRECIOUS (1<<1)
 
 /*
  * Given a file with name "fname", read it (either from disk, or from
@@ -1244,14 +1252,15 @@ static int add_patterns(const char *fname, const char *base, int baselen,
 		return -1;
 	}
 
-	add_patterns_from_buffer(buf, size, base, baselen, pl);
+	add_patterns_from_buffer(buf, size, base, baselen, pl,
+				 flags & PATTERN_DISALLOW_PRECIOUS);
 	free(buf);
 	return 0;
 }
 
 int add_patterns_from_buffer(char *buf, size_t size,
 			     const char *base, int baselen,
-			     struct pattern_list *pl)
+			     struct pattern_list *pl, int disable_precious)
 {
 	char *orig = buf;
 	int i, lineno = 1;
@@ -1270,7 +1279,8 @@ int add_patterns_from_buffer(char *buf, size_t size,
 			if (entry != buf + i && entry[0] != '#') {
 				buf[i - (i && buf[i-1] == '\r')] = 0;
 				trim_trailing_spaces(entry);
-				add_pattern(entry, base, baselen, pl, lineno);
+				add_pattern(entry, base, baselen, pl, lineno,
+					    disable_precious);
 			}
 			lineno++;
 			entry = buf + i + 1;
@@ -1307,7 +1317,7 @@ int add_patterns_from_blob_to_list(
 		return -1;
 	}
 
-	add_patterns_from_buffer(buf, size, base, baselen, pl);
+	add_patterns_from_buffer(buf, size, base, baselen, pl, 0);
 	free(buf);
 	return 0;
 }
diff --git a/dir.h b/dir.h
index 5cda2cdba7..a6977149b8 100644
--- a/dir.h
+++ b/dir.h
@@ -464,10 +464,11 @@ int add_patterns_from_blob_to_list(struct object_id *oid,
 				   struct pattern_list *pl);
 int add_patterns_from_buffer(char *buf, size_t size,
 			     const char *base, int baselen,
-			     struct pattern_list *pl);
+			     struct pattern_list *pl, int disable_precious);
 int parse_path_pattern(const char **string, int *patternlen, enum pattern_flags *flags, int *nowildcardlen);
 void add_pattern(const char *string, const char *base,
-		 int baselen, struct pattern_list *pl, int srcpos);
+		 int baselen, struct pattern_list *pl, int srcpos,
+		 int disable_precious);
 void clear_pattern_list(struct pattern_list *pl);
 void dir_clear(struct dir_struct *dir);
 
diff --git a/t/helper/test-path-walk.c b/t/helper/test-path-walk.c
index 4233badb58..fefe885ec6 100644
--- a/t/helper/test-path-walk.c
+++ b/t/helper/test-path-walk.c
@@ -124,7 +124,7 @@ int cmd__path_walk(int argc, const char **argv)
 		info.pl->use_cone_patterns = 1;
 
 		strbuf_fread(&in, 2048, stdin);
-		add_patterns_from_buffer(in.buf, in.len, "", 0, info.pl);
+		add_patterns_from_buffer(in.buf, in.len, "", 0, info.pl, 0);
 		strbuf_release(&in);
 	}
 
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 74b1761e0c..caae112037 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -252,6 +252,14 @@ test_expect_success 'sparse-checkout disable' '
 	check_files repo a deep folder1 folder2
 '
 
+test_expect_success 'skip precious-file pattern in $GIT_DIR/info/sparse-checkout' "
+	test_when_finished rm actual .git/info/sparse-checkout &&
+	test_when_finished git sparse-checkout disable &&
+	echo \"$/ciao\" > .git/info/sparse-checkout &&
+	git sparse-checkout init >actual 2>&1 &&
+	test_grep \"warning: '$/ciao' precious-files pattern not allowed here, skipping\" actual
+"
+
 test_expect_success 'sparse-index enabled and disabled' '
 	git -C repo sparse-checkout init --cone --sparse-index &&
 	test_cmp_config -C repo true index.sparse &&
-- 
2.56.0


  parent reply	other threads:[~2026-10-08 12:16 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-08 12:06 [RFC PATCH 0/6] Introduce precious files Mirko Faina
2026-10-08 12:06 ` [RFC PATCH 1/6] precious-files.txt: new document proposing new precious file type Mirko Faina
2026-10-08 12:06 ` [RFC PATCH 2/6] dir.h: replace pattern macros with enum in attr.h Mirko Faina
2026-10-08 12:06 ` [RFC PATCH 3/6] dir.c: teach parse_path_pattern() precious files Mirko Faina
2026-10-08 12:07 ` Mirko Faina [this message]
2026-10-08 12:07 ` [RFC PATCH 5/6] unpack-trees: teach check_ok_to_remove() precious Mirko Faina
2026-10-08 12:07 ` [RFC PATCH 6/6] builtin/ls-files.c: support for precious files Mirko Faina
2026-10-08 12:12 ` [RFC PATCH 0/6] Introduce " Mirko Faina

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=b4e2d50f6f5da34a9720d23f487f0db41d2bf3ee.1791460418.git.mroik@delayed.space \
    --to=mroik@delayed.space \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=newren@gmail.com \
    --cc=peff@peff.net \
    --cc=stolee@gmail.com \
    /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