@matheusbsbs / matheus-bagliano / commits / c28b3d6e7b
Fork 0

Read .gitignore from index if it is skip-worktree

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>

Nguyễn Thái Ngọc Duy committed Aug 20, 2009 at 20:47 UTC c28b3d6e7b0471a02f81324a90b26effae0f4bde
6 files changed +95 -22
Documentation/technical/api-directory-listing.txt
+3
@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
58 Calling sequence
59 ----------------
60
61 +Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE
62 +marked. If you to exclude files, make sure you have loaded index first.
63 +
64 * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
65 sizeof(dir))`.
66
builtin-clean.c
+3 -1
@@ -71,11 +71,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
71
72 dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
73
74 + if (read_cache() < 0)
75 + die("index file corrupt");
76 +
77 if (!ignored)
78 setup_standard_excludes(&dir);
79
80 pathspec = get_pathspec(prefix, argv);
78 - read_cache();
81
82 fill_directory(&dir, pathspec);
83
builtin-ls-files.c
+3 -1
@@ -485,6 +485,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
485 prefix_offset = strlen(prefix);
486 git_config(git_default_config, NULL);
487
488 + if (read_cache() < 0)
489 + die("index file corrupt");
490 +
491 argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
492 ls_files_usage, 0);
493 if (show_tag || show_valid_bit) {
@@ -513,7 +516,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
516 pathspec = get_pathspec(prefix, argv);
517
518 /* be nice with submodule paths ending in a slash */
516 - read_cache();
519 if (pathspec)
520 strip_trailing_slash_from_submodules();
521
dir.c
+45 -20
@@ -200,11 +200,35 @@ void add_exclude(const char *string, const char *base,
200 which->excludes[which->nr++] = x;
201 }
202
203 +static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
204 +{
205 + int pos, len;
206 + unsigned long sz;
207 + enum object_type type;
208 + void *data;
209 + struct index_state *istate = &the_index;
210 +
211 + len = strlen(path);
212 + pos = index_name_pos(istate, path, len);
213 + if (pos < 0)
214 + return NULL;
215 + if (!ce_skip_worktree(istate->cache[pos]))
216 + return NULL;
217 + data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
218 + if (!data || type != OBJ_BLOB) {
219 + free(data);
220 + return NULL;
221 + }
222 + *size = xsize_t(sz);
223 + return data;
224 +}
225 +
226 static int add_excludes_from_file_1(const char *fname,
227 const char *base,
228 int baselen,
229 char **buf_p,
207 - struct exclude_list *which)
230 + struct exclude_list *which,
231 + int check_index)
232 {
233 struct stat st;
234 int fd, i;
@@ -212,20 +236,26 @@ static int add_excludes_from_file_1(const char *fname,
236 char *buf, *entry;
237
238 fd = open(fname, O_RDONLY);
215 - if (fd < 0 || fstat(fd, &st) < 0)
216 - goto err;
217 - size = xsize_t(st.st_size);
218 - if (size == 0) {
219 - close(fd);
220 - return 0;
239 + if (fd < 0 || fstat(fd, &st) < 0) {
240 + if (0 <= fd)
241 + close(fd);
242 + if (!check_index ||
243 + (buf = read_skip_worktree_file_from_index(fname, &size)) == NULL)
244 + return -1;
245 }
222 - buf = xmalloc(size+1);
223 - if (read_in_full(fd, buf, size) != size)
224 - {
225 - free(buf);
226 - goto err;
246 + else {
247 + size = xsize_t(st.st_size);
248 + if (size == 0) {
249 + close(fd);
250 + return 0;
251 + }
252 + buf = xmalloc(size);
253 + if (read_in_full(fd, buf, size) != size) {
254 + close(fd);
255 + return -1;
256 + }
257 + close(fd);
258 }
228 - close(fd);
259
260 if (buf_p)
261 *buf_p = buf;
@@ -240,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname,
270 }
271 }
272 return 0;
243 -
244 - err:
245 - if (0 <= fd)
246 - close(fd);
247 - return -1;
273 }
274
275 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
276 {
277 if (add_excludes_from_file_1(fname, "", 0, NULL,
253 - &dir->exclude_list[EXC_FILE]) < 0)
278 + &dir->exclude_list[EXC_FILE], 0) < 0)
279 die("cannot use %s as an exclude file", fname);
280 }
281
@@ -301,7 +326,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
326 strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
327 add_excludes_from_file_1(dir->basebuf,
328 dir->basebuf, stk->baselen,
304 - &stk->filebuf, el);
329 + &stk->filebuf, el, 1);
330 dir->exclude_stack = stk;
331 current = stk->baselen;
332 }
t/t3001-ls-files-others-exclude.sh
+22
@@ -64,6 +64,8 @@ two/*.4
64 echo '!*.2
65 !*.8' >one/two/.gitignore
66
67 +allignores='.gitignore one/.gitignore one/two/.gitignore'
68 +
69 test_expect_success \
70 'git ls-files --others with various exclude options.' \
71 'git ls-files --others \
@@ -85,6 +87,26 @@ test_expect_success \
87 >output &&
88 test_cmp expect output'
89
90 +test_expect_success 'setup skip-worktree gitignore' '
91 + git add $allignores &&
92 + git update-index --skip-worktree $allignores &&
93 + rm $allignores
94 +'
95 +
96 +test_expect_success \
97 + 'git ls-files --others with various exclude options.' \
98 + 'git ls-files --others \
99 + --exclude=\*.6 \
100 + --exclude-per-directory=.gitignore \
101 + --exclude-from=.git/ignore \
102 + >output &&
103 + test_cmp expect output'
104 +
105 +test_expect_success 'restore gitignore' '
106 + git checkout $allignores &&
107 + rm .git/index
108 +'
109 +
110 cat > excludes-file <<\EOF
111 *.[1-8]
112 e*
t/t7300-clean.sh
+19
@@ -22,6 +22,25 @@ test_expect_success 'setup' '
22
23 '
24
25 +test_expect_success 'git clean with skip-worktree .gitignore' '
26 + git update-index --skip-worktree .gitignore &&
27 + rm .gitignore &&
28 + mkdir -p build docs &&
29 + touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
30 + git clean &&
31 + test -f Makefile &&
32 + test -f README &&
33 + test -f src/part1.c &&
34 + test -f src/part2.c &&
35 + test ! -f a.out &&
36 + test ! -f src/part3.c &&
37 + test -f docs/manual.txt &&
38 + test -f obj.o &&
39 + test -f build/lib.so &&
40 + git update-index --no-skip-worktree .gitignore &&
41 + git checkout .gitignore
42 +'
43 +
44 test_expect_success 'git clean' '
45
46 mkdir -p build docs &&