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>
This commit is contained in:

committed by
Junio C Hamano

parent
b5041c5f3b
commit
c28b3d6e7b
@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
|
|||||||
Calling sequence
|
Calling sequence
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE
|
||||||
|
marked. If you to exclude files, make sure you have loaded index first.
|
||||||
|
|
||||||
* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
|
* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
|
||||||
sizeof(dir))`.
|
sizeof(dir))`.
|
||||||
|
|
||||||
|
@ -71,11 +71,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
|
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
|
||||||
|
|
||||||
|
if (read_cache() < 0)
|
||||||
|
die("index file corrupt");
|
||||||
|
|
||||||
if (!ignored)
|
if (!ignored)
|
||||||
setup_standard_excludes(&dir);
|
setup_standard_excludes(&dir);
|
||||||
|
|
||||||
pathspec = get_pathspec(prefix, argv);
|
pathspec = get_pathspec(prefix, argv);
|
||||||
read_cache();
|
|
||||||
|
|
||||||
fill_directory(&dir, pathspec);
|
fill_directory(&dir, pathspec);
|
||||||
|
|
||||||
|
@ -485,6 +485,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||||||
prefix_offset = strlen(prefix);
|
prefix_offset = strlen(prefix);
|
||||||
git_config(git_default_config, NULL);
|
git_config(git_default_config, NULL);
|
||||||
|
|
||||||
|
if (read_cache() < 0)
|
||||||
|
die("index file corrupt");
|
||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
|
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
|
||||||
ls_files_usage, 0);
|
ls_files_usage, 0);
|
||||||
if (show_tag || show_valid_bit) {
|
if (show_tag || show_valid_bit) {
|
||||||
@ -513,7 +516,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||||||
pathspec = get_pathspec(prefix, argv);
|
pathspec = get_pathspec(prefix, argv);
|
||||||
|
|
||||||
/* be nice with submodule paths ending in a slash */
|
/* be nice with submodule paths ending in a slash */
|
||||||
read_cache();
|
|
||||||
if (pathspec)
|
if (pathspec)
|
||||||
strip_trailing_slash_from_submodules();
|
strip_trailing_slash_from_submodules();
|
||||||
|
|
||||||
|
65
dir.c
65
dir.c
@ -200,11 +200,35 @@ void add_exclude(const char *string, const char *base,
|
|||||||
which->excludes[which->nr++] = x;
|
which->excludes[which->nr++] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
|
||||||
|
{
|
||||||
|
int pos, len;
|
||||||
|
unsigned long sz;
|
||||||
|
enum object_type type;
|
||||||
|
void *data;
|
||||||
|
struct index_state *istate = &the_index;
|
||||||
|
|
||||||
|
len = strlen(path);
|
||||||
|
pos = index_name_pos(istate, path, len);
|
||||||
|
if (pos < 0)
|
||||||
|
return NULL;
|
||||||
|
if (!ce_skip_worktree(istate->cache[pos]))
|
||||||
|
return NULL;
|
||||||
|
data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
|
||||||
|
if (!data || type != OBJ_BLOB) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*size = xsize_t(sz);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static int add_excludes_from_file_1(const char *fname,
|
static int add_excludes_from_file_1(const char *fname,
|
||||||
const char *base,
|
const char *base,
|
||||||
int baselen,
|
int baselen,
|
||||||
char **buf_p,
|
char **buf_p,
|
||||||
struct exclude_list *which)
|
struct exclude_list *which,
|
||||||
|
int check_index)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int fd, i;
|
int fd, i;
|
||||||
@ -212,20 +236,26 @@ static int add_excludes_from_file_1(const char *fname,
|
|||||||
char *buf, *entry;
|
char *buf, *entry;
|
||||||
|
|
||||||
fd = open(fname, O_RDONLY);
|
fd = open(fname, O_RDONLY);
|
||||||
if (fd < 0 || fstat(fd, &st) < 0)
|
if (fd < 0 || fstat(fd, &st) < 0) {
|
||||||
goto err;
|
if (0 <= fd)
|
||||||
size = xsize_t(st.st_size);
|
close(fd);
|
||||||
if (size == 0) {
|
if (!check_index ||
|
||||||
|
(buf = read_skip_worktree_file_from_index(fname, &size)) == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size = xsize_t(st.st_size);
|
||||||
|
if (size == 0) {
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buf = xmalloc(size);
|
||||||
|
if (read_in_full(fd, buf, size) != size) {
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
buf = xmalloc(size+1);
|
|
||||||
if (read_in_full(fd, buf, size) != size)
|
|
||||||
{
|
|
||||||
free(buf);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (buf_p)
|
if (buf_p)
|
||||||
*buf_p = buf;
|
*buf_p = buf;
|
||||||
@ -240,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
|
||||||
if (0 <= fd)
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_excludes_from_file(struct dir_struct *dir, const char *fname)
|
void add_excludes_from_file(struct dir_struct *dir, const char *fname)
|
||||||
{
|
{
|
||||||
if (add_excludes_from_file_1(fname, "", 0, NULL,
|
if (add_excludes_from_file_1(fname, "", 0, NULL,
|
||||||
&dir->exclude_list[EXC_FILE]) < 0)
|
&dir->exclude_list[EXC_FILE], 0) < 0)
|
||||||
die("cannot use %s as an exclude file", fname);
|
die("cannot use %s as an exclude file", fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +326,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
|
|||||||
strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
|
strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
|
||||||
add_excludes_from_file_1(dir->basebuf,
|
add_excludes_from_file_1(dir->basebuf,
|
||||||
dir->basebuf, stk->baselen,
|
dir->basebuf, stk->baselen,
|
||||||
&stk->filebuf, el);
|
&stk->filebuf, el, 1);
|
||||||
dir->exclude_stack = stk;
|
dir->exclude_stack = stk;
|
||||||
current = stk->baselen;
|
current = stk->baselen;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,8 @@ two/*.4
|
|||||||
echo '!*.2
|
echo '!*.2
|
||||||
!*.8' >one/two/.gitignore
|
!*.8' >one/two/.gitignore
|
||||||
|
|
||||||
|
allignores='.gitignore one/.gitignore one/two/.gitignore'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'git ls-files --others with various exclude options.' \
|
'git ls-files --others with various exclude options.' \
|
||||||
'git ls-files --others \
|
'git ls-files --others \
|
||||||
@ -85,6 +87,26 @@ test_expect_success \
|
|||||||
>output &&
|
>output &&
|
||||||
test_cmp expect output'
|
test_cmp expect output'
|
||||||
|
|
||||||
|
test_expect_success 'setup skip-worktree gitignore' '
|
||||||
|
git add $allignores &&
|
||||||
|
git update-index --skip-worktree $allignores &&
|
||||||
|
rm $allignores
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'git ls-files --others with various exclude options.' \
|
||||||
|
'git ls-files --others \
|
||||||
|
--exclude=\*.6 \
|
||||||
|
--exclude-per-directory=.gitignore \
|
||||||
|
--exclude-from=.git/ignore \
|
||||||
|
>output &&
|
||||||
|
test_cmp expect output'
|
||||||
|
|
||||||
|
test_expect_success 'restore gitignore' '
|
||||||
|
git checkout $allignores &&
|
||||||
|
rm .git/index
|
||||||
|
'
|
||||||
|
|
||||||
cat > excludes-file <<\EOF
|
cat > excludes-file <<\EOF
|
||||||
*.[1-8]
|
*.[1-8]
|
||||||
e*
|
e*
|
||||||
|
@ -22,6 +22,25 @@ test_expect_success 'setup' '
|
|||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git clean with skip-worktree .gitignore' '
|
||||||
|
git update-index --skip-worktree .gitignore &&
|
||||||
|
rm .gitignore &&
|
||||||
|
mkdir -p build docs &&
|
||||||
|
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||||
|
git clean &&
|
||||||
|
test -f Makefile &&
|
||||||
|
test -f README &&
|
||||||
|
test -f src/part1.c &&
|
||||||
|
test -f src/part2.c &&
|
||||||
|
test ! -f a.out &&
|
||||||
|
test ! -f src/part3.c &&
|
||||||
|
test -f docs/manual.txt &&
|
||||||
|
test -f obj.o &&
|
||||||
|
test -f build/lib.so &&
|
||||||
|
git update-index --no-skip-worktree .gitignore &&
|
||||||
|
git checkout .gitignore
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'git clean' '
|
test_expect_success 'git clean' '
|
||||||
|
|
||||||
mkdir -p build docs &&
|
mkdir -p build docs &&
|
||||||
|
Reference in New Issue
Block a user