Commit 03fcef18 by Vicent Marti

Merge pull request #2328 from libgit2/rb/how-broken-can-ignores-be

Improve checks for ignore containment
parents bcf9792f f554611a
...@@ -281,7 +281,7 @@ uint32_t git_attr_file__name_hash(const char *name) ...@@ -281,7 +281,7 @@ uint32_t git_attr_file__name_hash(const char *name)
int git_attr_file__lookup_one( int git_attr_file__lookup_one(
git_attr_file *file, git_attr_file *file,
const git_attr_path *path, git_attr_path *path,
const char *attr, const char *attr,
const char **value) const char **value)
{ {
...@@ -342,14 +342,11 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path) ...@@ -342,14 +342,11 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path)
bool git_attr_fnmatch__match( bool git_attr_fnmatch__match(
git_attr_fnmatch *match, git_attr_fnmatch *match,
const git_attr_path *path) git_attr_path *path)
{ {
const char *filename; const char *filename;
int flags = 0; int flags = 0;
if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir)
return false;
if (match->flags & GIT_ATTR_FNMATCH_ICASE) if (match->flags & GIT_ATTR_FNMATCH_ICASE)
flags |= FNM_CASEFOLD; flags |= FNM_CASEFOLD;
if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR) if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
...@@ -365,12 +362,28 @@ bool git_attr_fnmatch__match( ...@@ -365,12 +362,28 @@ bool git_attr_fnmatch__match(
flags |= FNM_LEADING_DIR; flags |= FNM_LEADING_DIR;
} }
if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) {
int matchval;
/* for attribute checks or root ignore checks, fail match */
if (!(match->flags & GIT_ATTR_FNMATCH_IGNORE) ||
path->basename == path->path)
return false;
/* for ignore checks, use container of current item for check */
path->basename[-1] = '\0';
flags |= FNM_LEADING_DIR;
matchval = p_fnmatch(match->pattern, path->path, flags);
path->basename[-1] = '/';
return (matchval != FNM_NOMATCH);
}
return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH); return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH);
} }
bool git_attr_rule__match( bool git_attr_rule__match(
git_attr_rule *rule, git_attr_rule *rule,
const git_attr_path *path) git_attr_path *path)
{ {
bool matched = git_attr_fnmatch__match(&rule->match, path); bool matched = git_attr_fnmatch__match(&rule->match, path);
......
...@@ -138,7 +138,7 @@ int git_attr_file__clear_rules( ...@@ -138,7 +138,7 @@ int git_attr_file__clear_rules(
int git_attr_file__lookup_one( int git_attr_file__lookup_one(
git_attr_file *file, git_attr_file *file,
const git_attr_path *path, git_attr_path *path,
const char *attr, const char *attr,
const char **value); const char **value);
...@@ -162,13 +162,13 @@ extern int git_attr_fnmatch__parse( ...@@ -162,13 +162,13 @@ extern int git_attr_fnmatch__parse(
extern bool git_attr_fnmatch__match( extern bool git_attr_fnmatch__match(
git_attr_fnmatch *rule, git_attr_fnmatch *rule,
const git_attr_path *path); git_attr_path *path);
extern void git_attr_rule__free(git_attr_rule *rule); extern void git_attr_rule__free(git_attr_rule *rule);
extern bool git_attr_rule__match( extern bool git_attr_rule__match(
git_attr_rule *rule, git_attr_rule *rule,
const git_attr_path *path); git_attr_path *path);
extern git_attr_assignment *git_attr_rule__lookup_assignment( extern git_attr_assignment *git_attr_rule__lookup_assignment(
git_attr_rule *rule, const char *name); git_attr_rule *rule, const char *name);
......
...@@ -633,7 +633,6 @@ typedef struct { ...@@ -633,7 +633,6 @@ typedef struct {
git_iterator *new_iter; git_iterator *new_iter;
const git_index_entry *oitem; const git_index_entry *oitem;
const git_index_entry *nitem; const git_index_entry *nitem;
git_buf ignore_prefix;
} diff_in_progress; } diff_in_progress;
#define MODE_BITS_MASK 0000777 #define MODE_BITS_MASK 0000777
...@@ -844,24 +843,13 @@ static int handle_unmatched_new_item( ...@@ -844,24 +843,13 @@ static int handle_unmatched_new_item(
/* check if this is a prefix of the other side */ /* check if this is a prefix of the other side */
contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); contains_oitem = entry_is_prefixed(diff, info->oitem, nitem);
/* check if this is contained in an ignored parent directory */ /* update delta_type if this item is ignored */
if (git_buf_len(&info->ignore_prefix)) { if (git_iterator_current_is_ignored(info->new_iter))
if (diff->pfxcomp(nitem->path, git_buf_cstr(&info->ignore_prefix)) == 0)
delta_type = GIT_DELTA_IGNORED; delta_type = GIT_DELTA_IGNORED;
else
git_buf_clear(&info->ignore_prefix);
}
if (nitem->mode == GIT_FILEMODE_TREE) { if (nitem->mode == GIT_FILEMODE_TREE) {
bool recurse_into_dir = contains_oitem; bool recurse_into_dir = contains_oitem;
/* if not already inside an ignored dir, check if this is ignored */
if (delta_type != GIT_DELTA_IGNORED &&
git_iterator_current_is_ignored(info->new_iter)) {
delta_type = GIT_DELTA_IGNORED;
git_buf_sets(&info->ignore_prefix, nitem->path);
}
/* check if user requests recursion into this type of dir */ /* check if user requests recursion into this type of dir */
recurse_into_dir = contains_oitem || recurse_into_dir = contains_oitem ||
(delta_type == GIT_DELTA_UNTRACKED && (delta_type == GIT_DELTA_UNTRACKED &&
...@@ -938,27 +926,12 @@ static int handle_unmatched_new_item( ...@@ -938,27 +926,12 @@ static int handle_unmatched_new_item(
} }
} }
/* In core git, the next two checks are effectively reversed --
* i.e. when an file contained in an ignored directory is explicitly
* ignored, it shows up as an ignored file in the diff list, even though
* other untracked files in the same directory are skipped completely.
*
* To me, this seems odd. If the directory is ignored and the file is
* untracked, we should skip it consistently, regardless of whether it
* happens to match a pattern in the ignore file.
*
* To match the core git behavior, reverse the following two if checks
* so that individual file ignores are checked before container
* directory exclusions are used to skip the file.
*/
else if (delta_type == GIT_DELTA_IGNORED && else if (delta_type == GIT_DELTA_IGNORED &&
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS) &&
git_iterator_current_tree_is_ignored(info->new_iter))
/* item contained in ignored directory, so skip over it */ /* item contained in ignored directory, so skip over it */
return git_iterator_advance(&info->nitem, info->new_iter); return git_iterator_advance(&info->nitem, info->new_iter);
else if (git_iterator_current_is_ignored(info->new_iter))
delta_type = GIT_DELTA_IGNORED;
else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR)
delta_type = GIT_DELTA_ADDED; delta_type = GIT_DELTA_ADDED;
...@@ -1068,7 +1041,6 @@ int git_diff__from_iterators( ...@@ -1068,7 +1041,6 @@ int git_diff__from_iterators(
info.repo = repo; info.repo = repo;
info.old_iter = old_iter; info.old_iter = old_iter;
info.new_iter = new_iter; info.new_iter = new_iter;
git_buf_init(&info.ignore_prefix, 0);
/* make iterators have matching icase behavior */ /* make iterators have matching icase behavior */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE)) { if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE)) {
...@@ -1123,8 +1095,6 @@ cleanup: ...@@ -1123,8 +1095,6 @@ cleanup:
else else
git_diff_free(diff); git_diff_free(diff);
git_buf_free(&info.ignore_prefix);
return error; return error;
} }
......
...@@ -248,14 +248,15 @@ void git_ignore__free(git_ignores *ignores) ...@@ -248,14 +248,15 @@ void git_ignore__free(git_ignores *ignores)
} }
static bool ignore_lookup_in_rules( static bool ignore_lookup_in_rules(
git_attr_file *file, git_attr_path *path, int *ignored) int *ignored, git_attr_file *file, git_attr_path *path)
{ {
size_t j; size_t j;
git_attr_fnmatch *match; git_attr_fnmatch *match;
git_vector_rforeach(&file->rules, j, match) { git_vector_rforeach(&file->rules, j, match) {
if (git_attr_fnmatch__match(match, path)) { if (git_attr_fnmatch__match(match, path)) {
*ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0); *ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0) ?
GIT_IGNORE_TRUE : GIT_IGNORE_FALSE;
return true; return true;
} }
} }
...@@ -264,34 +265,34 @@ static bool ignore_lookup_in_rules( ...@@ -264,34 +265,34 @@ static bool ignore_lookup_in_rules(
} }
int git_ignore__lookup( int git_ignore__lookup(
git_ignores *ignores, const char *pathname, int *ignored) int *out, git_ignores *ignores, const char *pathname)
{ {
unsigned int i; unsigned int i;
git_attr_file *file; git_attr_file *file;
git_attr_path path; git_attr_path path;
*out = GIT_IGNORE_NOTFOUND;
if (git_attr_path__init( if (git_attr_path__init(
&path, pathname, git_repository_workdir(ignores->repo)) < 0) &path, pathname, git_repository_workdir(ignores->repo)) < 0)
return -1; return -1;
/* first process builtins - success means path was found */ /* first process builtins - success means path was found */
if (ignore_lookup_in_rules(ignores->ign_internal, &path, ignored)) if (ignore_lookup_in_rules(out, ignores->ign_internal, &path))
goto cleanup; goto cleanup;
/* next process files in the path */ /* next process files in the path */
git_vector_foreach(&ignores->ign_path, i, file) { git_vector_foreach(&ignores->ign_path, i, file) {
if (ignore_lookup_in_rules(file, &path, ignored)) if (ignore_lookup_in_rules(out, file, &path))
goto cleanup; goto cleanup;
} }
/* last process global ignores */ /* last process global ignores */
git_vector_foreach(&ignores->ign_global, i, file) { git_vector_foreach(&ignores->ign_global, i, file) {
if (ignore_lookup_in_rules(file, &path, ignored)) if (ignore_lookup_in_rules(out, file, &path))
goto cleanup; goto cleanup;
} }
*ignored = 0;
cleanup: cleanup:
git_attr_path__free(&path); git_attr_path__free(&path);
return 0; return 0;
...@@ -335,8 +336,6 @@ int git_ignore_path_is_ignored( ...@@ -335,8 +336,6 @@ int git_ignore_path_is_ignored(
int error; int error;
const char *workdir; const char *workdir;
git_attr_path path; git_attr_path path;
char *tail, *end;
bool full_is_dir;
git_ignores ignores; git_ignores ignores;
unsigned int i; unsigned int i;
git_attr_file *file; git_attr_file *file;
...@@ -345,55 +344,42 @@ int git_ignore_path_is_ignored( ...@@ -345,55 +344,42 @@ int git_ignore_path_is_ignored(
workdir = repo ? git_repository_workdir(repo) : NULL; workdir = repo ? git_repository_workdir(repo) : NULL;
if ((error = git_attr_path__init(&path, pathname, workdir)) < 0) memset(&path, 0, sizeof(path));
return error; memset(&ignores, 0, sizeof(ignores));
tail = path.path;
end = &path.full.ptr[path.full.size];
full_is_dir = path.is_dir;
while (1) {
/* advance to next component of path */
path.basename = tail;
while (tail < end && *tail != '/') tail++;
*tail = '\0';
path.full.size = (tail - path.full.ptr); if ((error = git_attr_path__init(&path, pathname, workdir)) < 0 ||
path.is_dir = (tail == end) ? full_is_dir : true;
/* initialize ignores the first time through */
if (path.basename == path.path &&
(error = git_ignore__for_path(repo, path.path, &ignores)) < 0) (error = git_ignore__for_path(repo, path.path, &ignores)) < 0)
break; goto cleanup;
while (1) {
/* first process builtins - success means path was found */ /* first process builtins - success means path was found */
if (ignore_lookup_in_rules(ignores.ign_internal, &path, ignored)) if (ignore_lookup_in_rules(ignored, ignores.ign_internal, &path))
goto cleanup; goto cleanup;
/* next process files in the path */ /* next process files in the path */
git_vector_foreach(&ignores.ign_path, i, file) { git_vector_foreach(&ignores.ign_path, i, file) {
if (ignore_lookup_in_rules(file, &path, ignored)) if (ignore_lookup_in_rules(ignored, file, &path))
goto cleanup; goto cleanup;
} }
/* last process global ignores */ /* last process global ignores */
git_vector_foreach(&ignores.ign_global, i, file) { git_vector_foreach(&ignores.ign_global, i, file) {
if (ignore_lookup_in_rules(file, &path, ignored)) if (ignore_lookup_in_rules(ignored, file, &path))
goto cleanup; goto cleanup;
} }
/* if we found no rules before reaching the end, we're done */ /* move up one directory */
if (tail == end) if (path.basename == path.path)
break; break;
path.basename[-1] = '\0';
/* now add this directory to list of ignores */ while (path.basename > path.path && *path.basename != '/')
if ((error = git_ignore__push_dir(&ignores, path.path)) < 0) path.basename--;
if (path.basename > path.path)
path.basename++;
path.is_dir = 1;
if ((error = git_ignore__pop_dir(&ignores)) < 0)
break; break;
/* reinstate divider in path */
*tail = '/';
while (*tail == '/') tail++;
} }
*ignored = 0; *ignored = 0;
...@@ -404,7 +390,6 @@ cleanup: ...@@ -404,7 +390,6 @@ cleanup:
return error; return error;
} }
int git_ignore__check_pathspec_for_exact_ignores( int git_ignore__check_pathspec_for_exact_ignores(
git_repository *repo, git_repository *repo,
git_vector *vspec, git_vector *vspec,
......
...@@ -42,7 +42,14 @@ extern int git_ignore__pop_dir(git_ignores *ign); ...@@ -42,7 +42,14 @@ extern int git_ignore__pop_dir(git_ignores *ign);
extern void git_ignore__free(git_ignores *ign); extern void git_ignore__free(git_ignores *ign);
extern int git_ignore__lookup(git_ignores *ign, const char *path, int *ignored); enum {
GIT_IGNORE_UNCHECKED = -2,
GIT_IGNORE_NOTFOUND = -1,
GIT_IGNORE_FALSE = 0,
GIT_IGNORE_TRUE = 1,
};
extern int git_ignore__lookup(int *out, git_ignores *ign, const char *path);
/* command line Git sometimes generates an error message if given a /* command line Git sometimes generates an error message if given a
* pathspec that contains an exact match to an ignored file (provided * pathspec that contains an exact match to an ignored file (provided
......
...@@ -897,6 +897,7 @@ struct fs_iterator_frame { ...@@ -897,6 +897,7 @@ struct fs_iterator_frame {
fs_iterator_frame *next; fs_iterator_frame *next;
git_vector entries; git_vector entries;
size_t index; size_t index;
int is_ignored;
}; };
typedef struct fs_iterator fs_iterator; typedef struct fs_iterator fs_iterator;
...@@ -1290,16 +1291,28 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) ...@@ -1290,16 +1291,28 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path)
static int workdir_iterator__enter_dir(fs_iterator *fi) static int workdir_iterator__enter_dir(fs_iterator *fi)
{ {
workdir_iterator *wi = (workdir_iterator *)fi;
fs_iterator_frame *ff = fi->stack; fs_iterator_frame *ff = fi->stack;
size_t pos; size_t pos;
git_path_with_stat *entry; git_path_with_stat *entry;
bool found_submodules = false; bool found_submodules = false;
/* only push new ignores if this is not top level directory */ /* check if this directory is ignored */
if (git_ignore__lookup(
&ff->is_ignored, &wi->ignores, fi->path.ptr + fi->root_len) < 0) {
giterr_clear();
ff->is_ignored = GIT_IGNORE_NOTFOUND;
}
/* if this is not the top level directory... */
if (ff->next != NULL) { if (ff->next != NULL) {
workdir_iterator *wi = (workdir_iterator *)fi;
ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/');
/* inherit ignored from parent if no rule specified */
if (ff->is_ignored <= GIT_IGNORE_NOTFOUND)
ff->is_ignored = ff->next->is_ignored;
/* push new ignores for files in this directory */
(void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]);
} }
...@@ -1342,7 +1355,7 @@ static int workdir_iterator__update_entry(fs_iterator *fi) ...@@ -1342,7 +1355,7 @@ static int workdir_iterator__update_entry(fs_iterator *fi)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
/* reset is_ignored since we haven't checked yet */ /* reset is_ignored since we haven't checked yet */
wi->is_ignored = -1; wi->is_ignored = GIT_IGNORE_UNCHECKED;
return 0; return 0;
} }
...@@ -1487,6 +1500,19 @@ int git_iterator_current_parent_tree( ...@@ -1487,6 +1500,19 @@ int git_iterator_current_parent_tree(
return 0; return 0;
} }
static void workdir_iterator_update_is_ignored(workdir_iterator *wi)
{
if (git_ignore__lookup(
&wi->is_ignored, &wi->ignores, wi->fi.entry.path) < 0) {
giterr_clear();
wi->is_ignored = GIT_IGNORE_NOTFOUND;
}
/* use ignore from containing frame stack */
if (wi->is_ignored <= GIT_IGNORE_NOTFOUND)
wi->is_ignored = wi->fi.stack->is_ignored;
}
bool git_iterator_current_is_ignored(git_iterator *iter) bool git_iterator_current_is_ignored(git_iterator *iter)
{ {
workdir_iterator *wi = (workdir_iterator *)iter; workdir_iterator *wi = (workdir_iterator *)iter;
...@@ -1494,14 +1520,22 @@ bool git_iterator_current_is_ignored(git_iterator *iter) ...@@ -1494,14 +1520,22 @@ bool git_iterator_current_is_ignored(git_iterator *iter)
if (iter->type != GIT_ITERATOR_TYPE_WORKDIR) if (iter->type != GIT_ITERATOR_TYPE_WORKDIR)
return false; return false;
if (wi->is_ignored != -1) if (wi->is_ignored != GIT_IGNORE_UNCHECKED)
return (bool)(wi->is_ignored != 0); return (bool)(wi->is_ignored == GIT_IGNORE_TRUE);
if (git_ignore__lookup( workdir_iterator_update_is_ignored(wi);
&wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0)
wi->is_ignored = true;
return (bool)wi->is_ignored; return (bool)(wi->is_ignored == GIT_IGNORE_TRUE);
}
bool git_iterator_current_tree_is_ignored(git_iterator *iter)
{
workdir_iterator *wi = (workdir_iterator *)iter;
if (iter->type != GIT_ITERATOR_TYPE_WORKDIR)
return false;
return (bool)(wi->fi.stack->is_ignored == GIT_IGNORE_TRUE);
} }
int git_iterator_cmp(git_iterator *iter, const char *path_prefix) int git_iterator_cmp(git_iterator *iter, const char *path_prefix)
...@@ -1549,10 +1583,8 @@ int git_iterator_advance_over_with_status( ...@@ -1549,10 +1583,8 @@ int git_iterator_advance_over_with_status(
return error; return error;
if (!S_ISDIR(entry->mode)) { if (!S_ISDIR(entry->mode)) {
if (git_ignore__lookup( workdir_iterator_update_is_ignored(wi);
&wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) if (wi->is_ignored == GIT_IGNORE_TRUE)
wi->is_ignored = true;
if (wi->is_ignored)
*status = GIT_ITERATOR_STATUS_IGNORED; *status = GIT_ITERATOR_STATUS_IGNORED;
return git_iterator_advance(entryptr, iter); return git_iterator_advance(entryptr, iter);
} }
...@@ -1564,14 +1596,12 @@ int git_iterator_advance_over_with_status( ...@@ -1564,14 +1596,12 @@ int git_iterator_advance_over_with_status(
/* scan inside directory looking for a non-ignored item */ /* scan inside directory looking for a non-ignored item */
while (entry && !iter->prefixcomp(entry->path, base)) { while (entry && !iter->prefixcomp(entry->path, base)) {
if (git_ignore__lookup( workdir_iterator_update_is_ignored(wi);
&wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0)
wi->is_ignored = true;
/* if we found an explicitly ignored item, then update from /* if we found an explicitly ignored item, then update from
* EMPTY to IGNORED * EMPTY to IGNORED
*/ */
if (wi->is_ignored) if (wi->is_ignored == GIT_IGNORE_TRUE)
*status = GIT_ITERATOR_STATUS_IGNORED; *status = GIT_ITERATOR_STATUS_IGNORED;
else if (S_ISDIR(entry->mode)) { else if (S_ISDIR(entry->mode)) {
error = git_iterator_advance_into(&entry, iter); error = git_iterator_advance_into(&entry, iter);
...@@ -1580,7 +1610,7 @@ int git_iterator_advance_over_with_status( ...@@ -1580,7 +1610,7 @@ int git_iterator_advance_over_with_status(
continue; continue;
else if (error == GIT_ENOTFOUND) { else if (error == GIT_ENOTFOUND) {
error = 0; error = 0;
wi->is_ignored = true; /* mark empty directories as ignored */ wi->is_ignored = GIT_IGNORE_TRUE; /* mark empty dirs ignored */
} else } else
break; /* real error, stop here */ break; /* real error, stop here */
} else { } else {
......
...@@ -245,6 +245,8 @@ extern int git_iterator_current_parent_tree( ...@@ -245,6 +245,8 @@ extern int git_iterator_current_parent_tree(
extern bool git_iterator_current_is_ignored(git_iterator *iter); extern bool git_iterator_current_is_ignored(git_iterator *iter);
extern bool git_iterator_current_tree_is_ignored(git_iterator *iter);
extern int git_iterator_cmp( extern int git_iterator_cmp(
git_iterator *iter, const char *path_prefix); git_iterator *iter, const char *path_prefix);
......
...@@ -647,7 +647,7 @@ static void workdir_iterator_test( ...@@ -647,7 +647,7 @@ static void workdir_iterator_test(
void test_diff_iterator__workdir_0(void) void test_diff_iterator__workdir_0(void)
{ {
workdir_iterator_test("attr", NULL, NULL, 27, 1, NULL, "ign"); workdir_iterator_test("attr", NULL, NULL, 23, 5, NULL, "ign");
} }
static const char *status_paths[] = { static const char *status_paths[] = {
......
...@@ -681,3 +681,110 @@ void test_status_ignore__issue_1766_negated_ignores(void) ...@@ -681,3 +681,110 @@ void test_status_ignore__issue_1766_negated_ignores(void)
} }
} }
static void add_one_to_index(const char *file)
{
git_index *index;
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_bypath(index, file));
git_index_free(index);
}
/* Some further broken scenarios that have been reported */
void test_status_ignore__more_breakage(void)
{
static const char *test_files[] = {
"empty_standard_repo/d1/pfx-d2/d3/d4/d5/tracked",
"empty_standard_repo/d1/pfx-d2/d3/d4/d5/untracked",
"empty_standard_repo/d1/pfx-d2/d3/d4/untracked",
NULL
};
make_test_data("empty_standard_repo", test_files);
cl_git_mkfile(
"empty_standard_repo/.gitignore",
"/d1/pfx-*\n"
"!/d1/pfx-d2/\n"
"/d1/pfx-d2/*\n"
"!/d1/pfx-d2/d3/\n"
"/d1/pfx-d2/d3/*\n"
"!/d1/pfx-d2/d3/d4/\n");
add_one_to_index("d1/pfx-d2/d3/d4/d5/tracked");
{
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
status_entry_counts counts;
static const char *files[] = {
".gitignore",
"d1/pfx-d2/d3/d4/d5/tracked",
"d1/pfx-d2/d3/d4/d5/untracked",
"d1/pfx-d2/d3/d4/untracked",
};
static const unsigned int statuses[] = {
GIT_STATUS_WT_NEW,
GIT_STATUS_INDEX_NEW,
GIT_STATUS_WT_NEW,
GIT_STATUS_WT_NEW,
};
memset(&counts, 0x0, sizeof(status_entry_counts));
counts.expected_entry_count = 4;
counts.expected_paths = files;
counts.expected_statuses = statuses;
opts.flags = GIT_STATUS_OPT_DEFAULTS |
GIT_STATUS_OPT_INCLUDE_IGNORED |
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
cl_git_pass(git_status_foreach_ext(
g_repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
}
refute_is_ignored("d1/pfx-d2/d3/d4/d5/tracked");
refute_is_ignored("d1/pfx-d2/d3/d4/d5/untracked");
refute_is_ignored("d1/pfx-d2/d3/d4/untracked");
}
void test_status_ignore__negative_ignores_inside_ignores(void)
{
static const char *test_files[] = {
"empty_standard_repo/top/mid/btm/tracked",
"empty_standard_repo/top/mid/btm/untracked",
NULL
};
make_test_data("empty_standard_repo", test_files);
cl_git_mkfile(
"empty_standard_repo/.gitignore",
"top\n!top/mid/btm\n");
add_one_to_index("top/mid/btm/tracked");
{
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
status_entry_counts counts;
static const char *files[] = {
".gitignore", "top/mid/btm/tracked", "top/mid/btm/untracked",
};
static const unsigned int statuses[] = {
GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_NEW,
};
memset(&counts, 0x0, sizeof(status_entry_counts));
counts.expected_entry_count = 3;
counts.expected_paths = files;
counts.expected_statuses = statuses;
opts.flags = GIT_STATUS_OPT_DEFAULTS |
GIT_STATUS_OPT_INCLUDE_IGNORED |
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
cl_git_pass(git_status_foreach_ext(
g_repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
}
refute_is_ignored("top/mid/btm/tracked");
refute_is_ignored("top/mid/btm/untracked");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment