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

[PATCH] archive: load index before pathspec checks

From
René Scharfe <l.s.r@web.de>
Date
Sep 21, 2024, 20:23 UTC
Message-ID
<66c3e9fa-ecfe-4af2-a970-c1afdbc2b7f2@web.de>
In-Reply-To
<4ace58897feee2d86839af1a36770e49810e59b8@rjp.ie>

git archive checks whether pathspec arguments match anything to avoid surprises due to typos and later loads the index to get attributes.

This order was OK when these features were introduced by ba053ea96c (archive: do not read .gitattributes in working directory, 2009-04-18) and d5f53d6d6f (archive: complain about path specs that don't match anything, 2009-12-12).

But when attribute matching was added to pathspec in b0db704652 (pathspec: allow querying for attributes, 2017-03-13), the pathspec checker in git archive did not support it fully, because it lacks the attributes from the index.

Load the index earlier, before the pathspec check, to support attr pathspecs.

Reported-by: Ronan Pigott <ronan@rjp.ie>
Signed-off-by: René Scharfe <l.s.r@web.de>
---
 archive.c           | 39 ++++++++++++++++++++-------------------
 t/t5000-tar-tree.sh | 12 ++++++++++++
 2 files changed, 32 insertions(+), 19 deletions(-)
diff --git a/archive.c b/archive.c
index 9ba96aae4f..58f86bf75c 100644
--- a/archive.c
+++ b/archive.c
@@ -304,8 +304,6 @@ int write_archive_entries(struct archiver_args *args,
 		write_archive_entry_fn_t write_entry)
 {
 	struct archiver_context context;
-	struct unpack_trees_options opts;
-	struct tree_desc t;
 	int err;
 	struct strbuf path_in_archive = STRBUF_INIT;
 	struct strbuf content = STRBUF_INIT;
@@ -331,23 +329,6 @@ int write_archive_entries(struct archiver_args *args,
 	context.args = args;
 	context.write_entry = write_entry;

-	/*
-	 * Setup index and instruct attr to read index only
-	 */
-	if (!args->worktree_attributes) {
-		memset(&opts, 0, sizeof(opts));
-		opts.index_only = 1;
-		opts.head_idx = -1;
-		opts.src_index = args->repo->index;
-		opts.dst_index = args->repo->index;
-		opts.fn = oneway_merge;
-		init_tree_desc(&t, &args->tree->object.oid,
-			       args->tree->buffer, args->tree->size);
-		if (unpack_trees(1, &t, &opts))
-			return -1;
-		git_attr_set_direction(GIT_ATTR_INDEX);
-	}
-
 	err = read_tree(args->repo, args->tree,
 			&args->pathspec,
 			queue_or_write_archive_entry,
@@ -540,6 +521,26 @@ static void parse_treeish_arg(const char **argv,
 	if (!tree)
 		die(_("not a tree object: %s"), oid_to_hex(&oid));

+	/*
+	 * Setup index and instruct attr to read index only
+	 */
+	if (!ar_args->worktree_attributes) {
+		struct unpack_trees_options opts;
+		struct tree_desc t;
+
+		memset(&opts, 0, sizeof(opts));
+		opts.index_only = 1;
+		opts.head_idx = -1;
+		opts.src_index = ar_args->repo->index;
+		opts.dst_index = ar_args->repo->index;
+		opts.fn = oneway_merge;
+		init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
+		if (unpack_trees(1, &t, &opts))
+			die(_("unable to checkout working tree"));
+
+		git_attr_set_direction(GIT_ATTR_INDEX);
+	}
+
 	ar_args->refname = ref;
 	ar_args->tree = tree;
 	ar_args->commit_oid = commit_oid;
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 7abba8a4b2..b9fda973f7 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -137,6 +137,8 @@ test_expect_success 'end-of-options is correctly eaten' '

 test_expect_success 'populate workdir' '
 	mkdir a &&
+	echo "a files_named_a" >.gitattributes &&
+	git add .gitattributes &&
 	echo simple textfile >a/a &&
 	ten=0123456789 &&
 	hundred="$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten" &&
@@ -450,6 +452,16 @@ test_expect_success 'allow pathspecs that resolve to the current directory' '
 	test_cmp expect actual
 '

+test_expect_success 'attr pathspec in bare repo' '
+	test_expect_code 0 git --git-dir=bare.git archive -v HEAD \
+		":(attr:files_named_a)" >/dev/null 2>actual &&
+	cat >expect <<-\EOF &&
+	a/
+	a/a
+	EOF
+	test_cmp expect actual
+'
+
 # Pull the size and date of each entry in a tarfile using the system tar.
 #
 # We'll pull out only the year from the date; that avoids any question of
--
2.46.0
Previous: Ronan PigottNext: René Scharfe
Message 3 of 4 in “Archive from bare repo?”
  1. Ronan PigottSep 20, 2024
  2. Ronan PigottSep 20, 2024
  3. archive: load index before pathspec checksRené Scharfe, Sep 21, 2024
  4. René ScharfeSep 21, 2024

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.