git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PROPOSAL] .gitignore syntax modification

From
Nguyen Thai Ngoc Duy <pclouds@gmail.com>
Date
Oct 13, 2010, 12:15 UTC
Message-ID
<20101013121552.GA29486@do>
In-Reply-To
<F06C63D1-26AE-4278-96CE-2F6B2D6DD300@sb.org>
On Tue, Oct 12, 2010 at 07:32:54PM -0700, Kevin Ballard wrote:
Show 9 quoted lines
> As soon as I find the time, I'll be working on a patch for this. I
> only wrote up the proposal because I want to make sure that what I
> end up implementing is actually something that will be accepted. At
> this point I'm actually in favor of simply assuming all paths that
> don't start with / can be matched at any level but I recognize that
> this is a change to existing functionality, though I personally
> think that all patterns that are meant to match only at the current
> level should be prefixed with / anyway. Would such a change to
> existing behavior be rejected out-of-hand?

Yes, patterns that only match current level should be prefixed with a slash. There are also other cases apart from "current level only" and "any level": foo/a* will match only second level, not any level.

I was thinking of doing like this. It's not complete (not even build) but it shows the idea. I don't think this way it will change existing behaviors. Performance is something I haven't thought through.

Anyway, what do you think? I'm afraid I don't have time to work on this. The pathspec unification work still needs to be done.

-- 
Duy


>From 058ed97a52a3a155655193d0ecd94506781c93c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com>
Date: Wed, 13 Oct 2010 19:01:11 +0700
Subject: [PATCH 1/3] excluded_from_list: split the core exclude code out as a separate function

---
 dir.c |  114 ++++++++++++++++++++++++++++++++++------------------------------
 1 files changed, 61 insertions(+), 53 deletions(-)

diff --git a/dir.c b/dir.c
index a44c7b3..56974e5 100644
--- a/dir.c
+++ b/dir.c
@@ -343,6 +343,64 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 	dir->basebuf[baselen] = '\0';
 }
 
+static int excluded_from_list_1(const char *pathname, int pathlen, const char *basename, struct exclude *x, int *dtype)
+{
+	const char *exclude = x->pattern;
+	int to_exclude = x->to_exclude;
+
+	if (x->flags & EXC_FLAG_MUSTBEDIR) {
+		if (!dtype) {
+			if (!prefixcmp(pathname, exclude))
+				return to_exclude;
+			else
+				return -1;
+		}
+		if (*dtype == DT_UNKNOWN)
+			*dtype = get_dtype(NULL, pathname, pathlen);
+		if (*dtype != DT_DIR)
+			return -1;
+	}
+
+	if (x->flags & EXC_FLAG_NODIR) {
+		/* match basename */
+		if (x->flags & EXC_FLAG_NOWILDCARD) {
+			if (!strcmp(exclude, basename))
+				return to_exclude;
+		} else if (x->flags & EXC_FLAG_ENDSWITH) {
+			if (x->patternlen - 1 <= pathlen &&
+			    !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1))
+				return to_exclude;
+		} else {
+			if (fnmatch(exclude, basename, 0) == 0)
+				return to_exclude;
+		}
+	}
+	else {
+		/* match with FNM_PATHNAME:
+		 * exclude has base (baselen long) implicitly
+		 * in front of it.
+		 */
+		int baselen = x->baselen;
+		if (*exclude == '/')
+			exclude++;
+
+		if (pathlen < baselen ||
+		    (baselen && pathname[baselen-1] != '/') ||
+		    strncmp(pathname, x->base, baselen))
+		    return -1;
+
+		if (x->flags & EXC_FLAG_NOWILDCARD) {
+			if (!strcmp(exclude, pathname + baselen))
+				return to_exclude;
+		} else {
+			if (fnmatch(exclude, pathname+baselen,
+				    FNM_PATHNAME) == 0)
+			    return to_exclude;
+		}
+	}
+	return -1;
+}
+
 /* Scan the list and let the last match determine the fate.
  * Return 1 for exclude, 0 for include and -1 for undecided.
  */
@@ -355,59 +413,9 @@ int excluded_from_list(const char *pathname,
 	if (el->nr) {
 		for (i = el->nr - 1; 0 <= i; i--) {
 			struct exclude *x = el->excludes[i];
-			const char *exclude = x->pattern;
-			int to_exclude = x->to_exclude;
-
-			if (x->flags & EXC_FLAG_MUSTBEDIR) {
-				if (!dtype) {
-					if (!prefixcmp(pathname, exclude))
-						return to_exclude;
-					else
-						continue;
-				}
-				if (*dtype == DT_UNKNOWN)
-					*dtype = get_dtype(NULL, pathname, pathlen);
-				if (*dtype != DT_DIR)
-					continue;
-			}
-
-			if (x->flags & EXC_FLAG_NODIR) {
-				/* match basename */
-				if (x->flags & EXC_FLAG_NOWILDCARD) {
-					if (!strcmp(exclude, basename))
-						return to_exclude;
-				} else if (x->flags & EXC_FLAG_ENDSWITH) {
-					if (x->patternlen - 1 <= pathlen &&
-					    !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1))
-						return to_exclude;
-				} else {
-					if (fnmatch(exclude, basename, 0) == 0)
-						return to_exclude;
-				}
-			}
-			else {
-				/* match with FNM_PATHNAME:
-				 * exclude has base (baselen long) implicitly
-				 * in front of it.
-				 */
-				int baselen = x->baselen;
-				if (*exclude == '/')
-					exclude++;
-
-				if (pathlen < baselen ||
-				    (baselen && pathname[baselen-1] != '/') ||
-				    strncmp(pathname, x->base, baselen))
-				    continue;
-
-				if (x->flags & EXC_FLAG_NOWILDCARD) {
-					if (!strcmp(exclude, pathname + baselen))
-						return to_exclude;
-				} else {
-					if (fnmatch(exclude, pathname+baselen,
-						    FNM_PATHNAME) == 0)
-					    return to_exclude;
-				}
-			}
+			int to_exclude = excluded_from_list_1(pathname, pathlen, basename, x, dtype);
+			if (to_exclude != -1)
+				return to_exclude;
 		}
 	}
 	return -1; /* undecided */
-- 
1.7.0.2.445.gcbdb3



>From afa6ef0ee1a299aef486367792f6dcc6e4e686d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com>
Date: Wed, 13 Oct 2010 19:10:35 +0700
Subject: [PATCH 2/3] Set EXC_FLAG_STARSTAR if a pattern starts with "**/"

---
 dir.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/dir.c b/dir.c
index 56974e5..241fbce 100644
--- a/dir.c
+++ b/dir.c
@@ -171,6 +171,10 @@ void add_exclude(const char *string, const char *base,
 		to_exclude = 0;
 		string++;
 	}
+	if (*string == '*' && string[1] == '*' && string[2] == '/') {
+		flags |= EXC_FLAG_STARSTAR;
+		string += 3;
+	}
 	len = strlen(string);
 	if (len && string[len - 1] == '/') {
 		char *s;
@@ -180,7 +184,7 @@ void add_exclude(const char *string, const char *base,
 		s[len - 1] = '\0';
 		string = s;
 		x->pattern = s;
-		flags = EXC_FLAG_MUSTBEDIR;
+		flags |= EXC_FLAG_MUSTBEDIR;
 	} else {
 		x = xmalloc(sizeof(*x));
 		x->pattern = string;
@@ -190,7 +194,7 @@ void add_exclude(const char *string, const char *base,
 	x->base = base;
 	x->baselen = baselen;
 	x->flags = flags;
-	if (!strchr(string, '/'))
+	if (!(x->flags & EXC_FLAG_STARSTAR) && !strchr(string, '/'))
 		x->flags |= EXC_FLAG_NODIR;
 	if (no_wildcard(string))
 		x->flags |= EXC_FLAG_NOWILDCARD;
-- 
1.7.0.2.445.gcbdb3



>From c11a949328b90aca3398f730a50eab35033f0334 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= <pclouds@gmail.com>
Date: Wed, 13 Oct 2010 19:06:07 +0700
Subject: [PATCH 3/3] excluded_from_list: support EXC_FLAG_STARSTAR

if that flag is set, try to match all full pathname, then skip one
directory and try again until it completely fails.
---
 dir.c |   20 +++++++++++++++++---
 1 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/dir.c b/dir.c
index 241fbce..11c3e7d 100644
--- a/dir.c
+++ b/dir.c
@@ -417,9 +417,23 @@ int excluded_from_list(const char *pathname,
 	if (el->nr) {
 		for (i = el->nr - 1; 0 <= i; i--) {
 			struct exclude *x = el->excludes[i];
-			int to_exclude = excluded_from_list_1(pathname, pathlen, basename, x, dtype);
-			if (to_exclude != -1)
-				return to_exclude;
+			const char *new_pathname = pathname;
+			int new_pathlen = pathlen;
+
+			while (1) {
+				int to_exclude = excluded_from_list_1(new_pathname, new_pathlen, basename, x, dtype);
+				if (to_exclude != -1)
+					return to_exclude;
+				if (x->flags & EXC_FLAG_STARSTAR) {
+					const char *p = strchr(new_pathname, '/');
+					if (p) {
+						new_pathlen -= p - new_pathname - 1;
+						new_pathname = p + 1;
+						continue;
+					}
+				}
+				break;
+			}
 		}
 	}
 	return -1; /* undecided */
-- 
1.7.0.2.445.gcbdb3
Previous: Junio C HamanoNext: Kevin Ballard
Message 10 of 13 in “[PROPOSAL] .gitignore syntax modification”
  1. Kevin BallardOct 8, 2010
  2. MaaartinOct 8, 2010
  3. Kevin BallardOct 9, 2010
  4. MaaartinOct 11, 2010
  5. Nguyen Thai Ngoc DuyOct 13, 2010
  6. Kevin BallardOct 13, 2010
  7. Jonathan NiederOct 13, 2010
  8. Kevin BallardOct 13, 2010
  9. Junio C HamanoOct 13, 2010
  10. Nguyen Thai Ngoc DuyOct 13, 2010
  11. Kevin BallardOct 15, 2010
  12. Nguyen Thai Ngoc DuyOct 15, 2010
  13. Kevin BallardOct 15, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.