Skip to content

Commit c28b3d6

Browse files
pcloudsgitster
authored andcommitted
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>
1 parent b5041c5 commit c28b3d6

File tree

6 files changed

+95
-22
lines changed

6 files changed

+95
-22
lines changed

Documentation/technical/api-directory-listing.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
5858
Calling sequence
5959
----------------
6060

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+
6164
* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
6265
sizeof(dir))`.
6366

builtin-clean.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
7171

7272
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
7373

74+
if (read_cache() < 0)
75+
die("index file corrupt");
76+
7477
if (!ignored)
7578
setup_standard_excludes(&dir);
7679

7780
pathspec = get_pathspec(prefix, argv);
78-
read_cache();
7981

8082
fill_directory(&dir, pathspec);
8183

builtin-ls-files.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
485485
prefix_offset = strlen(prefix);
486486
git_config(git_default_config, NULL);
487487

488+
if (read_cache() < 0)
489+
die("index file corrupt");
490+
488491
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
489492
ls_files_usage, 0);
490493
if (show_tag || show_valid_bit) {
@@ -513,7 +516,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
513516
pathspec = get_pathspec(prefix, argv);
514517

515518
/* be nice with submodule paths ending in a slash */
516-
read_cache();
517519
if (pathspec)
518520
strip_trailing_slash_from_submodules();
519521

dir.c

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -200,32 +200,62 @@ void add_exclude(const char *string, const char *base,
200200
which->excludes[which->nr++] = x;
201201
}
202202

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+
203226
static int add_excludes_from_file_1(const char *fname,
204227
const char *base,
205228
int baselen,
206229
char **buf_p,
207-
struct exclude_list *which)
230+
struct exclude_list *which,
231+
int check_index)
208232
{
209233
struct stat st;
210234
int fd, i;
211235
size_t size;
212236
char *buf, *entry;
213237

214238
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;
221245
}
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);
227258
}
228-
close(fd);
229259

230260
if (buf_p)
231261
*buf_p = buf;
@@ -240,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname,
240270
}
241271
}
242272
return 0;
243-
244-
err:
245-
if (0 <= fd)
246-
close(fd);
247-
return -1;
248273
}
249274

250275
void add_excludes_from_file(struct dir_struct *dir, const char *fname)
251276
{
252277
if (add_excludes_from_file_1(fname, "", 0, NULL,
253-
&dir->exclude_list[EXC_FILE]) < 0)
278+
&dir->exclude_list[EXC_FILE], 0) < 0)
254279
die("cannot use %s as an exclude file", fname);
255280
}
256281

@@ -301,7 +326,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
301326
strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
302327
add_excludes_from_file_1(dir->basebuf,
303328
dir->basebuf, stk->baselen,
304-
&stk->filebuf, el);
329+
&stk->filebuf, el, 1);
305330
dir->exclude_stack = stk;
306331
current = stk->baselen;
307332
}

t/t3001-ls-files-others-exclude.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ two/*.4
6464
echo '!*.2
6565
!*.8' >one/two/.gitignore
6666

67+
allignores='.gitignore one/.gitignore one/two/.gitignore'
68+
6769
test_expect_success \
6870
'git ls-files --others with various exclude options.' \
6971
'git ls-files --others \
@@ -85,6 +87,26 @@ test_expect_success \
8587
>output &&
8688
test_cmp expect output'
8789

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+
88110
cat > excludes-file <<\EOF
89111
*.[1-8]
90112
e*

t/t7300-clean.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ test_expect_success 'setup' '
2222
2323
'
2424

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+
2544
test_expect_success 'git clean' '
2645
2746
mkdir -p build docs &&

0 commit comments

Comments
 (0)