this allows to use .gitignore in sparse mode, where .gitignore may or may not be checked out (CE_VALID) --- dir.c | 70 ++++++++++++++++++++++++------------ t/t3001-ls-files-others-exclude.sh | 20 ++++++++++ 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/dir.c b/dir.c index e05b850..86bc90c 100644 --- a/dir.c +++ b/dir.c @@ -200,11 +200,36 @@ void add_exclude(const char *string, const char *base, which->excludes[which->nr++] = x; } +static void *read_index_data(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; + /* only applies to no-checkout items */ + if (!(istate->cache[pos]->ce_flags & CE_VALID)) + 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, const char *base, int baselen, char **buf_p, - struct exclude_list *which) + struct exclude_list *which, + int check_index) { struct stat st; int fd, i; @@ -212,27 +237,31 @@ static int add_excludes_from_file_1(const char *fname, char *buf, *entry; fd = open(fname, O_RDONLY); - if (fd < 0 || fstat(fd, &st) < 0) - goto err; - size = xsize_t(st.st_size); - if (size == 0) { - close(fd); - return 0; + if (fd < 0 || fstat(fd, &st) < 0) { + if (0 <= fd) + close(fd); + if (!check_index || (buf = read_index_data(fname, &size)) == NULL) + return -1; } - buf = xmalloc(size+1); - if (read_in_full(fd, buf, size) != size) - { - free(buf); - goto err; + 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); if (buf_p) *buf_p = buf; - buf[size++] = '\n'; entry = buf; - for (i = 0; i < size; i++) { - if (buf[i] == '\n') { + for (i = 0; i <= size; i++) { + if (i == size || buf[i] == '\n') { if (entry != buf + i && entry[0] != '#') { buf[i - (i && buf[i-1] == '\r')] = 0; add_exclude(entry, base, baselen, which); @@ -241,17 +270,12 @@ static int add_excludes_from_file_1(const char *fname, } } return 0; - - err: - if (0 <= fd) - close(fd); - return -1; } void add_excludes_from_file(struct dir_struct *dir, const char *fname) { 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); } @@ -302,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); add_excludes_from_file_1(dir->basebuf, dir->basebuf, stk->baselen, - &stk->filebuf, el); + &stk->filebuf, el, 1); dir->exclude_stack = stk; current = stk->baselen; } diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index c65bca8..e8b25d3 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -85,6 +85,26 @@ test_expect_success \ >output && test_cmp expect output' +test_expect_success 'setup sparse gitignore' ' + git add .gitignore one/.gitignore one/two/.gitignore && + git update-index --no-checkout .gitignore one/.gitignore one/two/.gitignore && + rm .gitignore one/.gitignore one/two/.gitignore +' + +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 .gitignore one/.gitignore one/two/.gitignore && + rm .git/index +' + cat > excludes-file <<\EOF *.[1-8] e* -- 1.6.3.2.448.gdf8b6 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html