mirror of
https://github.com/git/git.git
synced 2024-11-28 04:23:30 +08:00
ls-files: fix overeager pathspec optimization
Given pathspecs that share a common prefix, ls-files optimized its call into recursive directory reader by starting at the common prefix directory. If you have a directory "t" with an untracked file "t/junk" in it, but the top-level .gitignore file told us to ignore "t/", this resulted in: $ git ls-files -o --exclude-standard $ git ls-files -o --exclude-standard t/ t/junk $ git ls-files -o --exclude-standard t/junk t/junk $ cd t && git ls-files -o --exclude-standard junk We could argue that you are overriding the ignore file by giving a patchspec that matches or being in that directory, but it is somewhat unexpected. Worse yet, these behave differently: $ git ls-files -o --exclude-standard t/ . $ git ls-files -o --exclude-standard t/ t/junk This patch changes the optimization so that it notices when the common prefix directory that it starts reading from is an ignored one. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
16e2cfa909
commit
48ffef966c
38
dir.c
38
dir.c
@ -813,6 +813,41 @@ static void free_simplify(struct path_simplify *simplify)
|
||||
free(simplify);
|
||||
}
|
||||
|
||||
static int treat_leading_path(struct dir_struct *dir,
|
||||
const char *path, int len,
|
||||
const struct path_simplify *simplify)
|
||||
{
|
||||
char pathbuf[PATH_MAX];
|
||||
int baselen, blen;
|
||||
const char *cp;
|
||||
|
||||
while (len && path[len - 1] == '/')
|
||||
len--;
|
||||
if (!len)
|
||||
return 1;
|
||||
baselen = 0;
|
||||
while (1) {
|
||||
cp = path + baselen + !!baselen;
|
||||
cp = memchr(cp, '/', path + len - cp);
|
||||
if (!cp)
|
||||
baselen = len;
|
||||
else
|
||||
baselen = cp - path;
|
||||
memcpy(pathbuf, path, baselen);
|
||||
pathbuf[baselen] = '\0';
|
||||
if (!is_directory(pathbuf))
|
||||
return 0;
|
||||
if (simplify_away(pathbuf, baselen, simplify))
|
||||
return 0;
|
||||
blen = baselen;
|
||||
if (treat_one_path(dir, pathbuf, &blen, simplify,
|
||||
DT_DIR, NULL) == path_ignored)
|
||||
return 0; /* do not recurse into it */
|
||||
if (len <= baselen)
|
||||
return 1; /* finished checking */
|
||||
}
|
||||
}
|
||||
|
||||
int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
|
||||
{
|
||||
struct path_simplify *simplify;
|
||||
@ -821,7 +856,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const char
|
||||
return dir->nr;
|
||||
|
||||
simplify = create_simplify(pathspec);
|
||||
read_directory_recursive(dir, path, len, 0, simplify);
|
||||
if (!len || treat_leading_path(dir, path, len, simplify))
|
||||
read_directory_recursive(dir, path, len, 0, simplify);
|
||||
free_simplify(simplify);
|
||||
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
|
||||
qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
|
||||
|
@ -183,7 +183,7 @@ test_expect_success 'subdirectory ignore (l1/l2)' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_failure 'subdirectory ignore (l1)' '
|
||||
test_expect_success 'subdirectory ignore (l1)' '
|
||||
(
|
||||
cd top/l1 &&
|
||||
git ls-files -o --exclude-standard
|
||||
|
Loading…
Reference in New Issue
Block a user