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 &&