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

[PATCH] pathspec: stop --*-pathspecs impact on internal parse_pathspec() uses

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Oct 26, 2013, 02:09 UTC
Message-ID
<1382753360-32037-1-git-send-email-pclouds@gmail.com>
In-Reply-To
<20131025034947.GA4959@sigill.intra.peff.net>

Normally parse_pathspec() is used on command line arguments where it can do fancy thing like parsing magic on each argument or adding magic for all pathspecs based on --*-pathspecs options.

There's another use of parse_pathspec(), where pathspec is needed, but the input is known to be pure paths. In this case we usually don't want --*-pathspecs to interfere. And we definitely do not want to parse magic in these paths, regardless of --literal-pathspecs.

Add new flag PATHSPEC_LITERAL_PATH for this purpose. When it's set, --*-pathspecs are ignored, no magic is parsed. And if the caller allows PATHSPEC_LITERAL (i.e. the next calls can take literal magic), then PATHSPEC_LITERAL will be set.

This fixes cases where git chokes when GIT_*_PATHSPECS are set because parse_pathspec() indicates it won't take any magic. But GIT_*_PATHSPECS add them anyway. These are

   export GIT_LITERAL_PATHSPECS=1
   git blame -- something
   git log --follow something
   git log --merge

"git ls-files --with-tree=path" (aka parse_pathspec() in overlay_tree_on_cache()) is safe because the input is empty, and producing one pathspec due to PATHSPEC_PREFER_CWD does not take any magic into account.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Jeff, how about this?
 
 It's similar to your last suggestion (i.e.  relaxing the magic mask
 about literal magic). In addition, it forces literal magic
 unconditionally in this case, which I think is the right thing to do.
 And it will fix other --*-pathspecs as well.
 builtin/blame.c            | 4 +++-
 pathspec.c                 | 9 ++++++++-
 pathspec.h                 | 7 +++++++
 revision.c                 | 3 ++-
 t/t6130-pathspec-noglob.sh | 7 +++++++
 tree-diff.c                | 4 +++-
 6 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/builtin/blame.c b/builtin/blame.c
index 6da7233..1407ae7 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -409,7 +409,9 @@ static struct origin *find_origin(struct scoreboard *sb,
 	paths[0] = origin->path;
 	paths[1] = NULL;
 
-	parse_pathspec(&diff_opts.pathspec, PATHSPEC_ALL_MAGIC, 0, "", paths);
+	parse_pathspec(&diff_opts.pathspec,
+		       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+		       PATHSPEC_LITERAL_PATH, "", paths);
 	diff_setup_done(&diff_opts);
 
 	if (is_null_sha1(origin->commit->object.sha1))
diff --git a/pathspec.c b/pathspec.c
index ad1a9f5..4cf2bd3 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -128,7 +128,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 		die(_("global 'literal' pathspec setting is incompatible "
 		      "with all other global pathspec settings"));
 
-	if (elt[0] != ':' || literal_global) {
+	if (flags & PATHSPEC_LITERAL_PATH)
+		global_magic = 0;
+
+	if (elt[0] != ':' || literal_global ||
+	    (flags & PATHSPEC_LITERAL_PATH)) {
 		; /* nothing to do */
 	} else if (elt[1] == '(') {
 		/* longhand */
@@ -405,6 +409,9 @@ void parse_pathspec(struct pathspec *pathspec,
 		item[i].magic = prefix_pathspec(item + i, &short_magic,
 						argv + i, flags,
 						prefix, prefixlen, entry);
+		if ((flags & PATHSPEC_LITERAL_PATH) &&
+		    !(magic_mask & PATHSPEC_LITERAL))
+			item[i].magic |= PATHSPEC_LITERAL;
 		if (item[i].magic & magic_mask)
 			unsupported_magic(entry,
 					  item[i].magic & magic_mask,
diff --git a/pathspec.h b/pathspec.h
index 944baeb..a75e924 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -58,6 +58,13 @@ struct pathspec {
 #define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)
 #define PATHSPEC_PREFIX_ORIGIN (1<<6)
 #define PATHSPEC_KEEP_ORDER (1<<7)
+/*
+ * For the callers that just need pure paths from somewhere else, not
+ * from command line. Global --*-pathspecs options are ignored. No
+ * magic is parsed in each pathspec either. If PATHSPEC_LITERAL is
+ * allowed, then it will automatically set for every pathspec.
+ */
+#define PATHSPEC_LITERAL_PATH (1<<8)
 
 extern void parse_pathspec(struct pathspec *pathspec,
 			   unsigned magic_mask,
diff --git a/revision.c b/revision.c
index 0173e01..9b9e22e 100644
--- a/revision.c
+++ b/revision.c
@@ -1372,7 +1372,8 @@ static void prepare_show_merge(struct rev_info *revs)
 			i++;
 	}
 	free_pathspec(&revs->prune_data);
-	parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC, 0, "", prune);
+	parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+		       PATHSPEC_LITERAL_PATH, "", prune);
 	revs->limited = 1;
 }
 
diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh
index ea00d71..6583532 100755
--- a/t/t6130-pathspec-noglob.sh
+++ b/t/t6130-pathspec-noglob.sh
@@ -108,6 +108,13 @@ test_expect_success 'no-glob environment variable works' '
 	test_cmp expect actual
 '
 
+test_expect_success 'blame takes global pathspec flags' '
+	git --literal-pathspecs blame -- foo &&
+	git --icase-pathspecs   blame -- foo &&
+	git --glob-pathspecs    blame -- foo &&
+	git --noglob-pathspecs  blame -- foo
+'
+
 test_expect_success 'setup xxx/bar' '
 	mkdir xxx &&
 	test_commit xxx xxx/bar
diff --git a/tree-diff.c b/tree-diff.c
index ccf9d7c..456660c 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -254,7 +254,9 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
 			path[0] = p->one->path;
 			path[1] = NULL;
 			free_pathspec(&opt->pathspec);
-			parse_pathspec(&opt->pathspec, PATHSPEC_ALL_MAGIC, 0, "", path);
+			parse_pathspec(&opt->pathspec,
+				       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+				       PATHSPEC_LITERAL_PATH, "", path);
 
 			/*
 			 * The caller expects us to return a set of vanilla
-- 
1.8.2.83.gc99314b
Previous: Duy NguyenNext: Jeff King
Message 6 of 8 in “[BUG] "git --literal-pathspecs blame" broken in master”
  1. Jeff KingOct 25, 2013
  2. Jeff KingOct 25, 2013
  3. Duy NguyenOct 25, 2013
  4. Jeff KingOct 25, 2013
  5. Duy NguyenOct 25, 2013
  6. pathspec: stop --*-pathspecs impact on internal parse_pathspec() usesNguyễn Thái Ngọc Duy, Oct 26, 2013
  7. Jeff KingOct 26, 2013
  8. pathspec: stop --*-pathspecs impact on internal parse_pathspec() usesNguyễn Thái Ngọc Duy, Oct 26, 2013

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.