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

[PATCH 11/23] Read .gitignore from index if it is skip-worktree

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Dec 14, 2009, 10:30 UTC
Message-ID
<1260786666-8405-12-git-send-email-pclouds@gmail.com>
In-Reply-To
<1260786666-8405-1-git-send-email-pclouds@gmail.com>

This adds index as a prerequisite for directory listing (with exclude). At the moment directory listing is used by "git clean", "git add", "git ls-files" and "git status"/"git commit" and unpack_trees()-related commands. These commands have been checked/modified to populate index before doing directory listing.

add_excludes_from_file() does not enable this feature, because it is used to read .git/info/exclude and some explicit files specified by "git ls-files".

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/technical/api-directory-listing.txt |    3 +
 builtin-clean.c                                   |    4 +-
 builtin-ls-files.c                                |    4 +-
 dir.c                                             |   65 ++++++++++++++------
 t/t3001-ls-files-others-exclude.sh                |   22 +++++++
 t/t7300-clean.sh                                  |   19 ++++++
 6 files changed, 95 insertions(+), 22 deletions(-)
diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 5bbd18f..add6f43 100644
--- a/Documentation/technical/api-directory-listing.txt
+++ b/Documentation/technical/api-directory-listing.txt
@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
 Calling sequence
 ----------------
 
+Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE
+marked. If you to exclude files, make sure you have loaded index first.
+
 * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
   sizeof(dir))`.
 
diff --git a/builtin-clean.c b/builtin-clean.c
index 2d8c735..e424b77 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -71,11 +71,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 
 	dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
 
+	if (read_cache() < 0)
+		die("index file corrupt");
+
 	if (!ignored)
 		setup_standard_excludes(&dir);
 
 	pathspec = get_pathspec(prefix, argv);
-	read_cache();
 
 	fill_directory(&dir, pathspec);
 
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index ad7e447..2e47242 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -485,6 +485,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 		prefix_offset = strlen(prefix);
 	git_config(git_default_config, NULL);
 
+	if (read_cache() < 0)
+		die("index file corrupt");
+
 	argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
 			ls_files_usage, 0);
 	if (show_tag || show_valid_bit) {
@@ -513,7 +516,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 	pathspec = get_pathspec(prefix, argv);
 
 	/* be nice with submodule paths ending in a slash */
-	read_cache();
 	if (pathspec)
 		strip_trailing_slash_from_submodules();
 
diff --git a/dir.c b/dir.c
index 1170d64..e8e5b79 100644
--- a/dir.c
+++ b/dir.c
@@ -200,11 +200,35 @@ void add_exclude(const char *string, const char *base,
 	which->excludes[which->nr++] = x;
 }
 
+static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
+{
+	int pos, len;
+	unsigned long sz;
+	enum object_type type;
+	void *data;
+	struct index_state *istate = &the_index;
+
+	len = strlen(path);
+	pos = index_name_pos(istate, path, len);
+	if (pos < 0)
+		return NULL;
+	if (!ce_skip_worktree(istate->cache[pos]))
+		return NULL;
+	data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+	if (!data || type != OBJ_BLOB) {
+		free(data);
+		return NULL;
+	}
+	*size = xsize_t(sz);
+	return data;
+}
+
 static int add_excludes_from_file_1(const char *fname,
 				    const char *base,
 				    int baselen,
 				    char **buf_p,
-				    struct exclude_list *which)
+				    struct exclude_list *which,
+				    int check_index)
 {
 	struct stat st;
 	int fd, i;
@@ -212,20 +236,26 @@ static int add_excludes_from_file_1(const char *fname,
 	char *buf, *entry;
 
 	fd = open(fname, O_RDONLY);
-	if (fd < 0 || fstat(fd, &st) < 0)
-		goto err;
-	size = xsize_t(st.st_size);
-	if (size == 0) {
-		close(fd);
-		return 0;
+	if (fd < 0 || fstat(fd, &st) < 0) {
+		if (0 <= fd)
+			close(fd);
+		if (!check_index ||
+		    (buf = read_skip_worktree_file_from_index(fname, &size)) == NULL)
+			return -1;
 	}
-	buf = xmalloc(size+1);
-	if (read_in_full(fd, buf, size) != size)
-	{
-		free(buf);
-		goto err;
+	else {
+		size = xsize_t(st.st_size);
+		if (size == 0) {
+			close(fd);
+			return 0;
+		}
+		buf = xmalloc(size);
+		if (read_in_full(fd, buf, size) != size) {
+			close(fd);
+			return -1;
+		}
+		close(fd);
 	}
-	close(fd);
 
 	if (buf_p)
 		*buf_p = buf;
@@ -240,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname,
 		}
 	}
 	return 0;
-
- err:
-	if (0 <= fd)
-		close(fd);
-	return -1;
 }
 
 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
 {
 	if (add_excludes_from_file_1(fname, "", 0, NULL,
-				     &dir->exclude_list[EXC_FILE]) < 0)
+				     &dir->exclude_list[EXC_FILE], 0) < 0)
 		die("cannot use %s as an exclude file", fname);
 }
 
@@ -301,7 +326,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 		strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
 		add_excludes_from_file_1(dir->basebuf,
 					 dir->basebuf, stk->baselen,
-					 &stk->filebuf, el);
+					 &stk->filebuf, el, 1);
 		dir->exclude_stack = stk;
 		current = stk->baselen;
 	}
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index c65bca8..132c476 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -64,6 +64,8 @@ two/*.4
 echo '!*.2
 !*.8' >one/two/.gitignore
 
+allignores='.gitignore one/.gitignore one/two/.gitignore'
+
 test_expect_success \
     'git ls-files --others with various exclude options.' \
     'git ls-files --others \
@@ -85,6 +87,26 @@ test_expect_success \
        >output &&
      test_cmp expect output'
 
+test_expect_success 'setup skip-worktree gitignore' '
+	git add $allignores &&
+	git update-index --skip-worktree $allignores &&
+	rm $allignores
+'
+
+test_expect_success \
+    'git ls-files --others with various exclude options.' \
+    'git ls-files --others \
+       --exclude=\*.6 \
+       --exclude-per-directory=.gitignore \
+       --exclude-from=.git/ignore \
+       >output &&
+     test_cmp expect output'
+
+test_expect_success 'restore gitignore' '
+	git checkout $allignores &&
+	rm .git/index
+'
+
 cat > excludes-file <<\EOF
 *.[1-8]
 e*
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 929d5d4..8073d02 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -22,6 +22,25 @@ test_expect_success 'setup' '
 
 '
 
+test_expect_success 'git clean with skip-worktree .gitignore' '
+	git update-index --skip-worktree .gitignore &&
+	rm .gitignore &&
+	mkdir -p build docs &&
+	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
+	git clean &&
+	test -f Makefile &&
+	test -f README &&
+	test -f src/part1.c &&
+	test -f src/part2.c &&
+	test ! -f a.out &&
+	test ! -f src/part3.c &&
+	test -f docs/manual.txt &&
+	test -f obj.o &&
+	test -f build/lib.so &&
+	git update-index --no-skip-worktree .gitignore &&
+	git checkout .gitignore
+'
+
 test_expect_success 'git clean' '
 
 	mkdir -p build docs &&
-- 
1.6.5.2.216.g9c1ec
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 16 of 30 in “nd/sparse reroll”
  1. 00/23 nd/sparse rerollNguyễn Thái Ngọc Duy, Dec 14, 2009
  2. 01/23 update-index: refactor mark_valid() in preparation for new optionsNguyễn Thái Ngọc Duy, Dec 14, 2009
  3. 02/23 Add test-index-versionNguyễn Thái Ngọc Duy, Dec 14, 2009
  4. 03/23 Introduce "skip-worktree" bit in index, teach Git to get/set this bitNguyễn Thái Ngọc Duy, Dec 14, 2009
  5. Greg PriceDec 14, 2009
  6. Nguyen Thai Ngoc DuyDec 15, 2009
  7. Johannes SixtDec 15, 2009
  8. Nguyen Thai Ngoc DuyDec 15, 2009
  9. 04/23 update-index: ignore update request if it's skip-worktreeNguyễn Thái Ngọc Duy, Dec 14, 2009
  10. 05/23 Teach ls-files and update-index to respect skip-worktree bitNguyễn Thái Ngọc Duy, Dec 14, 2009
  11. 06/23 Teach diff machinery to respect skip-worktree bitNguyễn Thái Ngọc Duy, Dec 14, 2009
  12. 07/23 Teach grep to respect skip-worktree bitNguyễn Thái Ngọc Duy, Dec 14, 2009
  13. 08/23 Teach commit to respect skip-worktree bitNguyễn Thái Ngọc Duy, Dec 14, 2009
  14. 09/23 Teach Git to respect skip-worktree bit (writing part)Nguyễn Thái Ngọc Duy, Dec 14, 2009
  15. 10/23 Avoid writing to buffer in add_excludes_from_file_1()Nguyễn Thái Ngọc Duy, Dec 14, 2009
  16. 11/23 Read .gitignore from index if it is skip-worktreeNguyễn Thái Ngọc Duy, Dec 14, 2009
  17. 12/23 unpack-trees(): carry skip-worktree bit over in merged_entry()Nguyễn Thái Ngọc Duy, Dec 14, 2009
  18. 13/23 excluded_1(): support exclude files in indexNguyễn Thái Ngọc Duy, Dec 14, 2009
  19. 14/23 dir.c: export excluded_1() and add_excludes_from_file_1()Nguyễn Thái Ngọc Duy, Dec 14, 2009
  20. 15/23 Introduce "sparse checkout"Nguyễn Thái Ngọc Duy, Dec 14, 2009
  21. 16/23 unpack-trees(): add CE_WT_REMOVE to remove on worktree aloneNguyễn Thái Ngọc Duy, Dec 14, 2009
  22. 17/23 unpack-trees.c: generalize verify_* functionsNguyễn Thái Ngọc Duy, Dec 14, 2009
  23. 18/23 unpack-trees(): "enable" sparse checkout and load $GIT_DIR/info/sparse-checkoutNguyễn Thái Ngọc Duy, Dec 14, 2009
  24. 19/23 unpack_trees(): apply $GIT_DIR/info/sparse-checkout to the final indexNguyễn Thái Ngọc Duy, Dec 14, 2009
  25. 20/23 unpack-trees(): ignore worktree check outside checkout areaNguyễn Thái Ngọc Duy, Dec 14, 2009
  26. 21/23 read-tree: add --no-sparse-checkout to disable sparse checkout supportNguyễn Thái Ngọc Duy, Dec 14, 2009
  27. 22/23 Add tests for sparse checkoutNguyễn Thái Ngọc Duy, Dec 14, 2009
  28. 23/23 sparse checkout: inhibit empty worktreeNguyễn Thái Ngọc Duy, Dec 14, 2009
  29. Johannes SixtDec 14, 2009
  30. Nguyen Thai Ngoc DuyDec 14, 2009

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.