Skip to content

Commit eb41775

Browse files
committed
ls-files -i: pay attention to exclusion of leading paths
"git ls-files --exclude=t/ -i" does not show paths in directory t/ that have been added to the index, but it should. The excluded() API was designed for callers who walk the tree from the top, checking each level of the directory hierarchy as it descends if it is excluded, and not even bothering to recurse into an excluded directory. This would allow us optimize for a common case by not having to check if the exclude pattern "foo/" matches when looking at "foo/bar", because the caller should have noticed that "foo" is excluded and did not even bother to read "foo/bar" out of opendir()/readdir() to call it. The code for "ls-files -i" however walks the index linearly, feeding paths without checking if the leading directory is already excluded. Introduce a helper function path_excluded() to let this caller properly call excluded() check for higher hierarchies as necessary. Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent d9f5ef7 commit eb41775

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

builtin/ls-files.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ static void show_ru_info(void)
203203
static void show_files(struct dir_struct *dir)
204204
{
205205
int i;
206+
struct path_exclude_check check;
207+
208+
if ((dir->flags & DIR_SHOW_IGNORED))
209+
path_exclude_check_init(&check, dir);
206210

207211
/* For cached/deleted files we don't need to even do the readdir */
208212
if (show_others || show_killed) {
@@ -215,9 +219,8 @@ static void show_files(struct dir_struct *dir)
215219
if (show_cached | show_stage) {
216220
for (i = 0; i < active_nr; i++) {
217221
struct cache_entry *ce = active_cache[i];
218-
int dtype = ce_to_dtype(ce);
219-
if (dir->flags & DIR_SHOW_IGNORED &&
220-
!excluded(dir, ce->name, &dtype))
222+
if ((dir->flags & DIR_SHOW_IGNORED) &&
223+
!path_excluded(&check, ce))
221224
continue;
222225
if (show_unmerged && !ce_stage(ce))
223226
continue;
@@ -232,9 +235,8 @@ static void show_files(struct dir_struct *dir)
232235
struct cache_entry *ce = active_cache[i];
233236
struct stat st;
234237
int err;
235-
int dtype = ce_to_dtype(ce);
236-
if (dir->flags & DIR_SHOW_IGNORED &&
237-
!excluded(dir, ce->name, &dtype))
238+
if ((dir->flags & DIR_SHOW_IGNORED) &&
239+
!path_excluded(&check, ce))
238240
continue;
239241
if (ce->ce_flags & CE_UPDATE)
240242
continue;
@@ -247,6 +249,9 @@ static void show_files(struct dir_struct *dir)
247249
show_ce_entry(tag_modified, ce);
248250
}
249251
}
252+
253+
if ((dir->flags & DIR_SHOW_IGNORED))
254+
path_exclude_check_clear(&check);
250255
}
251256

252257
/*

dir.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,38 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
580580
return 0;
581581
}
582582

583+
void path_exclude_check_init(struct path_exclude_check *check,
584+
struct dir_struct *dir)
585+
{
586+
check->dir = dir;
587+
strbuf_init(&check->path, 256);
588+
}
589+
590+
void path_exclude_check_clear(struct path_exclude_check *check)
591+
{
592+
strbuf_release(&check->path);
593+
}
594+
595+
int path_excluded(struct path_exclude_check *check, struct cache_entry *ce)
596+
{
597+
int i, dtype;
598+
struct strbuf *path = &check->path;
599+
600+
strbuf_setlen(path, 0);
601+
for (i = 0; ce->name[i]; i++) {
602+
int ch = ce->name[i];
603+
604+
if (ch == '/') {
605+
dtype = DT_DIR;
606+
if (excluded(check->dir, path->buf, &dtype))
607+
return 1;
608+
}
609+
strbuf_addch(path, ch);
610+
}
611+
dtype = ce_to_dtype(ce);
612+
return excluded(check->dir, ce->name, &dtype);
613+
}
614+
583615
static struct dir_entry *dir_entry_new(const char *pathname, int len)
584616
{
585617
struct dir_entry *ent;

dir.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef DIR_H
22
#define DIR_H
33

4+
#include "strbuf.h"
5+
46
struct dir_entry {
57
unsigned int len;
68
char name[FLEX_ARRAY]; /* more */
@@ -78,6 +80,20 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas
7880
int *dtype, struct exclude_list *el);
7981
extern int excluded(struct dir_struct *, const char *, int *);
8082
struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
83+
84+
/*
85+
* The excluded() API is meant for callers that check each level of leading
86+
* directory hierarchies with excluded() to avoid recursing into excluded
87+
* directories. Callers that do not do so should use this API instead.
88+
*/
89+
struct path_exclude_check {
90+
struct dir_struct *dir;
91+
struct strbuf path;
92+
};
93+
extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *);
94+
extern void path_exclude_check_clear(struct path_exclude_check *);
95+
extern int path_excluded(struct path_exclude_check *, struct cache_entry *);
96+
8197
extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
8298
char **buf_p, struct exclude_list *which, int check_index);
8399
extern void add_excludes_from_file(struct dir_struct *, const char *fname);

0 commit comments

Comments
 (0)