Skip to content

Commit 1966bab

Browse files
committed
Merge branch 'jc/ls-files-i-dir'
"git ls-files --exclude=t -i" did not consider anything under t/ as excluded, as it did not pay attention to exclusion of leading paths while walking the index. Other two users of excluded() are also updated. * jc/ls-files-i-dir: dir.c: make excluded() file scope static unpack-trees.c: use path_excluded() in check_ok_to_remove() builtin/add.c: use path_excluded() path_excluded(): update API to less cache-entry centric ls-files -i: micro-optimize path_excluded() ls-files -i: pay attention to exclusion of leading paths
2 parents 9d8d51d + 0d316f0 commit 1966bab

File tree

6 files changed

+109
-10
lines changed

6 files changed

+109
-10
lines changed

builtin/add.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,21 +443,25 @@ int cmd_add(int argc, const char **argv, const char *prefix)
443443

444444
if (pathspec) {
445445
int i;
446+
struct path_exclude_check check;
447+
448+
path_exclude_check_init(&check, &dir);
446449
if (!seen)
447450
seen = find_used_pathspec(pathspec);
448451
for (i = 0; pathspec[i]; i++) {
449452
if (!seen[i] && pathspec[i][0]
450453
&& !file_exists(pathspec[i])) {
451454
if (ignore_missing) {
452455
int dtype = DT_UNKNOWN;
453-
if (excluded(&dir, pathspec[i], &dtype))
456+
if (path_excluded(&check, pathspec[i], -1, &dtype))
454457
dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
455458
} else
456459
die(_("pathspec '%s' did not match any files"),
457460
pathspec[i]);
458461
}
459462
}
460463
free(seen);
464+
path_exclude_check_clear(&check);
461465
}
462466

463467
plug_bulk_checkin();

builtin/ls-files.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,19 @@ static void show_ru_info(void)
200200
}
201201
}
202202

203+
static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce)
204+
{
205+
int dtype = ce_to_dtype(ce);
206+
return path_excluded(check, ce->name, ce_namelen(ce), &dtype);
207+
}
208+
203209
static void show_files(struct dir_struct *dir)
204210
{
205211
int i;
212+
struct path_exclude_check check;
213+
214+
if ((dir->flags & DIR_SHOW_IGNORED))
215+
path_exclude_check_init(&check, dir);
206216

207217
/* For cached/deleted files we don't need to even do the readdir */
208218
if (show_others || show_killed) {
@@ -215,9 +225,8 @@ static void show_files(struct dir_struct *dir)
215225
if (show_cached | show_stage) {
216226
for (i = 0; i < active_nr; i++) {
217227
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))
228+
if ((dir->flags & DIR_SHOW_IGNORED) &&
229+
!ce_excluded(&check, ce))
221230
continue;
222231
if (show_unmerged && !ce_stage(ce))
223232
continue;
@@ -232,9 +241,8 @@ static void show_files(struct dir_struct *dir)
232241
struct cache_entry *ce = active_cache[i];
233242
struct stat st;
234243
int err;
235-
int dtype = ce_to_dtype(ce);
236-
if (dir->flags & DIR_SHOW_IGNORED &&
237-
!excluded(dir, ce->name, &dtype))
244+
if ((dir->flags & DIR_SHOW_IGNORED) &&
245+
!ce_excluded(&check, ce))
238246
continue;
239247
if (ce->ce_flags & CE_UPDATE)
240248
continue;
@@ -247,6 +255,9 @@ static void show_files(struct dir_struct *dir)
247255
show_ce_entry(tag_modified, ce);
248256
}
249257
}
258+
259+
if ((dir->flags & DIR_SHOW_IGNORED))
260+
path_exclude_check_clear(&check);
250261
}
251262

252263
/*

dir.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ int excluded_from_list(const char *pathname,
553553
return -1; /* undecided */
554554
}
555555

556-
int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
556+
static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
557557
{
558558
int pathlen = strlen(pathname);
559559
int st;
@@ -573,6 +573,64 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
573573
return 0;
574574
}
575575

576+
void path_exclude_check_init(struct path_exclude_check *check,
577+
struct dir_struct *dir)
578+
{
579+
check->dir = dir;
580+
strbuf_init(&check->path, 256);
581+
}
582+
583+
void path_exclude_check_clear(struct path_exclude_check *check)
584+
{
585+
strbuf_release(&check->path);
586+
}
587+
588+
/*
589+
* Is this name excluded? This is for a caller like show_files() that
590+
* do not honor directory hierarchy and iterate through paths that are
591+
* possibly in an ignored directory.
592+
*
593+
* A path to a directory known to be excluded is left in check->path to
594+
* optimize for repeated checks for files in the same excluded directory.
595+
*/
596+
int path_excluded(struct path_exclude_check *check,
597+
const char *name, int namelen, int *dtype)
598+
{
599+
int i;
600+
struct strbuf *path = &check->path;
601+
602+
/*
603+
* we allow the caller to pass namelen as an optimization; it
604+
* must match the length of the name, as we eventually call
605+
* excluded() on the whole name string.
606+
*/
607+
if (namelen < 0)
608+
namelen = strlen(name);
609+
610+
if (path->len &&
611+
path->len <= namelen &&
612+
!memcmp(name, path->buf, path->len) &&
613+
(!name[path->len] || name[path->len] == '/'))
614+
return 1;
615+
616+
strbuf_setlen(path, 0);
617+
for (i = 0; name[i]; i++) {
618+
int ch = name[i];
619+
620+
if (ch == '/') {
621+
int dt = DT_DIR;
622+
if (excluded(check->dir, path->buf, &dt))
623+
return 1;
624+
}
625+
strbuf_addch(path, ch);
626+
}
627+
628+
/* An entry in the index; cannot be a directory with subentries */
629+
strbuf_setlen(path, 0);
630+
631+
return excluded(check->dir, name, dtype);
632+
}
633+
576634
static struct dir_entry *dir_entry_new(const char *pathname, int len)
577635
{
578636
struct dir_entry *ent;

dir.h

Lines changed: 17 additions & 1 deletion
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 */
@@ -76,8 +78,22 @@ extern int read_directory(struct dir_struct *, const char *path, int len, const
7678

7779
extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,
7880
int *dtype, struct exclude_list *el);
79-
extern int excluded(struct dir_struct *, const char *, int *);
8081
struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
82+
83+
/*
84+
* The excluded() API is meant for callers that check each level of leading
85+
* directory hierarchies with excluded() to avoid recursing into excluded
86+
* directories. Callers that do not do so should use this API instead.
87+
*/
88+
struct path_exclude_check {
89+
struct dir_struct *dir;
90+
struct strbuf path;
91+
};
92+
extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *);
93+
extern void path_exclude_check_clear(struct path_exclude_check *);
94+
extern int path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
95+
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);

unpack-trees.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
10231023
o->el = &el;
10241024
}
10251025

1026+
if (o->dir) {
1027+
o->path_exclude_check = xmalloc(sizeof(struct path_exclude_check));
1028+
path_exclude_check_init(o->path_exclude_check, o->dir);
1029+
}
10261030
memset(&o->result, 0, sizeof(o->result));
10271031
o->result.initialized = 1;
10281032
o->result.timestamp.sec = o->src_index->timestamp.sec;
@@ -1148,6 +1152,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
11481152

11491153
done:
11501154
free_excludes(&el);
1155+
if (o->path_exclude_check) {
1156+
path_exclude_check_clear(o->path_exclude_check);
1157+
free(o->path_exclude_check);
1158+
}
11511159
return ret;
11521160

11531161
return_failed:
@@ -1363,7 +1371,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
13631371
if (ignore_case && icase_exists(o, name, len, st))
13641372
return 0;
13651373

1366-
if (o->dir && excluded(o->dir, name, &dtype))
1374+
if (o->dir &&
1375+
path_excluded(o->path_exclude_check, name, -1, &dtype))
13671376
/*
13681377
* ce->name is explicitly excluded, so it is Ok to
13691378
* overwrite it.

unpack-trees.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct unpack_trees_options {
5252
const char *prefix;
5353
int cache_bottom;
5454
struct dir_struct *dir;
55+
struct path_exclude_check *path_exclude_check;
5556
struct pathspec *pathspec;
5657
merge_fn_t fn;
5758
const char *msgs[NB_UNPACK_TREES_ERROR_TYPES];

0 commit comments

Comments
 (0)