From 92f7d32b59642c82c17027bc85a39100869280a7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 12 Sep 2015 13:46:22 -0400 Subject: [PATCH 1/2] diff::workdir: ensure ignored files are not returned Ensure that a diff with the workdir is not erroneously returning directories. --- tests/diff/workdir.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c index e87769170..89f9483a6 100644 --- a/tests/diff/workdir.c +++ b/tests/diff/workdir.c @@ -2054,3 +2054,46 @@ void test_diff_workdir__only_writes_index_when_necessary(void) git_index_free(index); } +void test_diff_workdir__to_index_pathlist(void) +{ + git_index *index; + git_diff *diff; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_vector pathlist = GIT_VECTOR_INIT; + + git_vector_insert(&pathlist, "foobar/asdf"); + git_vector_insert(&pathlist, "subdir/asdf"); + git_vector_insert(&pathlist, "ignored/asdf"); + + g_repo = cl_git_sandbox_init("status"); + + cl_git_mkfile("status/.gitignore", ".gitignore\n" "ignored/\n"); + + cl_must_pass(p_mkdir("status/foobar", 0777)); + cl_git_mkfile("status/foobar/one", "one\n"); + + cl_must_pass(p_mkdir("status/ignored", 0777)); + cl_git_mkfile("status/ignored/one", "one\n"); + cl_git_mkfile("status/ignored/two", "two\n"); + cl_git_mkfile("status/ignored/three", "three\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + + opts.flags = GIT_DIFF_INCLUDE_IGNORED; + opts.pathspec.strings = pathlist.contents; + opts.pathspec.count = pathlist.length; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, &opts)); + cl_assert_equal_i(0, git_diff_num_deltas(diff)); + git_diff_free(diff); + + opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, &opts)); + cl_assert_equal_i(0, git_diff_num_deltas(diff)); + git_diff_free(diff); + + git_index_free(index); + git_vector_free(&pathlist); +} + From 8ab4d0e1e16bf42e4617a40a13d67385fc8fa40c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 12 Sep 2015 15:32:18 -0400 Subject: [PATCH 2/2] diff: check pathspec on non-files When we're not doing pathspec matching, we let the iterator handle file matching for us. However, we can only trust the iterator to return *files* that match the pattern, because the iterator must return directories that are not strictly in the pathlist, but that are the parents of files that match the pattern, so that diff can later recurse into them. Thus, diff must examine non-files explicitly before including them in the delta list. --- src/diff.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/diff.c b/src/diff.c index 32c1d4aa5..d97dcd9d2 100644 --- a/src/diff.c +++ b/src/diff.c @@ -75,18 +75,27 @@ static int diff_insert_delta( } static bool diff_pathspec_match( - const char **matched_pathspec, git_diff *diff, const char *path) + const char **matched_pathspec, + git_diff *diff, + const git_index_entry *entry) { - /* The iterator has filtered out paths for us, so the fact that we're - * seeing this patch means that it must match the given path list. + bool disable_pathspec_match = + DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH); + + /* If we're disabling fnmatch, then the iterator has already applied + * the filters to the files for us and we don't have to do anything. + * However, this only applies to *files* - the iterator will include + * directories that we need to recurse into when not autoexpanding, + * so we still need to apply the pathspec match to directories. */ - if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH)) { - *matched_pathspec = path; + if ((S_ISLNK(entry->mode) || S_ISREG(entry->mode)) && + disable_pathspec_match) { + *matched_pathspec = entry->path; return true; } return git_pathspec__match( - &diff->pathspec, path, false, + &diff->pathspec, entry->path, disable_pathspec_match, DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE), matched_pathspec, NULL); } @@ -127,7 +136,7 @@ static int diff_delta__from_one( DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNREADABLE)) return 0; - if (!diff_pathspec_match(&matched_pathspec, diff, entry->path)) + if (!diff_pathspec_match(&matched_pathspec, diff, entry)) return 0; delta = diff_delta__alloc(diff, status, entry->path); @@ -768,7 +777,7 @@ static int maybe_modified( const char *matched_pathspec; int error = 0; - if (!diff_pathspec_match(&matched_pathspec, diff, oitem->path)) + if (!diff_pathspec_match(&matched_pathspec, diff, oitem)) return 0; memset(&noid, 0, sizeof(noid));