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
This commit is contained in:
commit
1966babf6e
@ -443,6 +443,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (pathspec) {
|
||||
int i;
|
||||
struct path_exclude_check check;
|
||||
|
||||
path_exclude_check_init(&check, &dir);
|
||||
if (!seen)
|
||||
seen = find_used_pathspec(pathspec);
|
||||
for (i = 0; pathspec[i]; i++) {
|
||||
@ -450,7 +453,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
&& !file_exists(pathspec[i])) {
|
||||
if (ignore_missing) {
|
||||
int dtype = DT_UNKNOWN;
|
||||
if (excluded(&dir, pathspec[i], &dtype))
|
||||
if (path_excluded(&check, pathspec[i], -1, &dtype))
|
||||
dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
|
||||
} else
|
||||
die(_("pathspec '%s' did not match any files"),
|
||||
@ -458,6 +461,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
free(seen);
|
||||
path_exclude_check_clear(&check);
|
||||
}
|
||||
|
||||
plug_bulk_checkin();
|
||||
|
@ -200,9 +200,19 @@ static void show_ru_info(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce)
|
||||
{
|
||||
int dtype = ce_to_dtype(ce);
|
||||
return path_excluded(check, ce->name, ce_namelen(ce), &dtype);
|
||||
}
|
||||
|
||||
static void show_files(struct dir_struct *dir)
|
||||
{
|
||||
int i;
|
||||
struct path_exclude_check check;
|
||||
|
||||
if ((dir->flags & DIR_SHOW_IGNORED))
|
||||
path_exclude_check_init(&check, dir);
|
||||
|
||||
/* For cached/deleted files we don't need to even do the readdir */
|
||||
if (show_others || show_killed) {
|
||||
@ -215,9 +225,8 @@ static void show_files(struct dir_struct *dir)
|
||||
if (show_cached | show_stage) {
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (dir->flags & DIR_SHOW_IGNORED &&
|
||||
!excluded(dir, ce->name, &dtype))
|
||||
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
||||
!ce_excluded(&check, ce))
|
||||
continue;
|
||||
if (show_unmerged && !ce_stage(ce))
|
||||
continue;
|
||||
@ -232,9 +241,8 @@ static void show_files(struct dir_struct *dir)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
struct stat st;
|
||||
int err;
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (dir->flags & DIR_SHOW_IGNORED &&
|
||||
!excluded(dir, ce->name, &dtype))
|
||||
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
||||
!ce_excluded(&check, ce))
|
||||
continue;
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
@ -247,6 +255,9 @@ static void show_files(struct dir_struct *dir)
|
||||
show_ce_entry(tag_modified, ce);
|
||||
}
|
||||
}
|
||||
|
||||
if ((dir->flags & DIR_SHOW_IGNORED))
|
||||
path_exclude_check_clear(&check);
|
||||
}
|
||||
|
||||
/*
|
||||
|
60
dir.c
60
dir.c
@ -553,7 +553,7 @@ int excluded_from_list(const char *pathname,
|
||||
return -1; /* undecided */
|
||||
}
|
||||
|
||||
int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
|
||||
static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
|
||||
{
|
||||
int pathlen = strlen(pathname);
|
||||
int st;
|
||||
@ -573,6 +573,64 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void path_exclude_check_init(struct path_exclude_check *check,
|
||||
struct dir_struct *dir)
|
||||
{
|
||||
check->dir = dir;
|
||||
strbuf_init(&check->path, 256);
|
||||
}
|
||||
|
||||
void path_exclude_check_clear(struct path_exclude_check *check)
|
||||
{
|
||||
strbuf_release(&check->path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this name excluded? This is for a caller like show_files() that
|
||||
* do not honor directory hierarchy and iterate through paths that are
|
||||
* possibly in an ignored directory.
|
||||
*
|
||||
* A path to a directory known to be excluded is left in check->path to
|
||||
* optimize for repeated checks for files in the same excluded directory.
|
||||
*/
|
||||
int path_excluded(struct path_exclude_check *check,
|
||||
const char *name, int namelen, int *dtype)
|
||||
{
|
||||
int i;
|
||||
struct strbuf *path = &check->path;
|
||||
|
||||
/*
|
||||
* we allow the caller to pass namelen as an optimization; it
|
||||
* must match the length of the name, as we eventually call
|
||||
* excluded() on the whole name string.
|
||||
*/
|
||||
if (namelen < 0)
|
||||
namelen = strlen(name);
|
||||
|
||||
if (path->len &&
|
||||
path->len <= namelen &&
|
||||
!memcmp(name, path->buf, path->len) &&
|
||||
(!name[path->len] || name[path->len] == '/'))
|
||||
return 1;
|
||||
|
||||
strbuf_setlen(path, 0);
|
||||
for (i = 0; name[i]; i++) {
|
||||
int ch = name[i];
|
||||
|
||||
if (ch == '/') {
|
||||
int dt = DT_DIR;
|
||||
if (excluded(check->dir, path->buf, &dt))
|
||||
return 1;
|
||||
}
|
||||
strbuf_addch(path, ch);
|
||||
}
|
||||
|
||||
/* An entry in the index; cannot be a directory with subentries */
|
||||
strbuf_setlen(path, 0);
|
||||
|
||||
return excluded(check->dir, name, dtype);
|
||||
}
|
||||
|
||||
static struct dir_entry *dir_entry_new(const char *pathname, int len)
|
||||
{
|
||||
struct dir_entry *ent;
|
||||
|
18
dir.h
18
dir.h
@ -1,6 +1,8 @@
|
||||
#ifndef DIR_H
|
||||
#define DIR_H
|
||||
|
||||
#include "strbuf.h"
|
||||
|
||||
struct dir_entry {
|
||||
unsigned int len;
|
||||
char name[FLEX_ARRAY]; /* more */
|
||||
@ -76,8 +78,22 @@ extern int read_directory(struct dir_struct *, const char *path, int len, const
|
||||
|
||||
extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,
|
||||
int *dtype, struct exclude_list *el);
|
||||
extern int excluded(struct dir_struct *, const char *, int *);
|
||||
struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
|
||||
|
||||
/*
|
||||
* The excluded() API is meant for callers that check each level of leading
|
||||
* directory hierarchies with excluded() to avoid recursing into excluded
|
||||
* directories. Callers that do not do so should use this API instead.
|
||||
*/
|
||||
struct path_exclude_check {
|
||||
struct dir_struct *dir;
|
||||
struct strbuf path;
|
||||
};
|
||||
extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *);
|
||||
extern void path_exclude_check_clear(struct path_exclude_check *);
|
||||
extern int path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
|
||||
|
||||
|
||||
extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
|
||||
char **buf_p, struct exclude_list *which, int check_index);
|
||||
extern void add_excludes_from_file(struct dir_struct *, const char *fname);
|
||||
|
@ -1023,6 +1023,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
||||
o->el = ⪙
|
||||
}
|
||||
|
||||
if (o->dir) {
|
||||
o->path_exclude_check = xmalloc(sizeof(struct path_exclude_check));
|
||||
path_exclude_check_init(o->path_exclude_check, o->dir);
|
||||
}
|
||||
memset(&o->result, 0, sizeof(o->result));
|
||||
o->result.initialized = 1;
|
||||
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
|
||||
|
||||
done:
|
||||
free_excludes(&el);
|
||||
if (o->path_exclude_check) {
|
||||
path_exclude_check_clear(o->path_exclude_check);
|
||||
free(o->path_exclude_check);
|
||||
}
|
||||
return ret;
|
||||
|
||||
return_failed:
|
||||
@ -1363,7 +1371,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
|
||||
if (ignore_case && icase_exists(o, name, len, st))
|
||||
return 0;
|
||||
|
||||
if (o->dir && excluded(o->dir, name, &dtype))
|
||||
if (o->dir &&
|
||||
path_excluded(o->path_exclude_check, name, -1, &dtype))
|
||||
/*
|
||||
* ce->name is explicitly excluded, so it is Ok to
|
||||
* overwrite it.
|
||||
|
@ -52,6 +52,7 @@ struct unpack_trees_options {
|
||||
const char *prefix;
|
||||
int cache_bottom;
|
||||
struct dir_struct *dir;
|
||||
struct path_exclude_check *path_exclude_check;
|
||||
struct pathspec *pathspec;
|
||||
merge_fn_t fn;
|
||||
const char *msgs[NB_UNPACK_TREES_ERROR_TYPES];
|
||||
|
Loading…
Reference in New Issue
Block a user