summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/diff.h8
-rw-r--r--include/git2/pathspec.h41
-rw-r--r--src/array.h2
-rw-r--r--src/diff.c10
-rw-r--r--src/diff.h2
-rw-r--r--src/pathspec.c314
-rw-r--r--src/pathspec.h12
-rw-r--r--tests-clar/diff/pathspec.c92
8 files changed, 404 insertions, 77 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 43029c49c..121c9df5c 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -798,6 +798,14 @@ GIT_EXTERN(size_t) git_diff_num_deltas_of_type(
git_delta_t type);
/**
+ * Check if deltas are sorted case sensitively or insensitively.
+ *
+ * @param diff Diff list to check
+ * @return 0 if case sensitive, 1 if case is ignored
+ */
+GIT_EXTERN(int) git_diff_is_sorted_icase(const git_diff_list *diff);
+
+/**
* Return the diff delta and patch for an entry in the diff list.
*
* The `git_diff_patch` is a newly created object contains the text diffs
diff --git a/include/git2/pathspec.h b/include/git2/pathspec.h
index 6d97bb326..a835f8e52 100644
--- a/include/git2/pathspec.h
+++ b/include/git2/pathspec.h
@@ -10,6 +10,7 @@
#include "common.h"
#include "types.h"
#include "strarray.h"
+#include "diff.h"
/**
* Compiled pathspec
@@ -167,6 +168,30 @@ GIT_EXTERN(int) git_pathspec_match_tree(
git_pathspec *ps);
/**
+ * Match a pathspec against files in a diff list.
+ *
+ * This matches the pathspec against the files in the given diff list.
+ *
+ * If `out` is not NULL, this returns a `git_patchspec_match_list`. That
+ * contains the list of all matched filenames (unless you pass the
+ * `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
+ * pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
+ * flag). You must call `git_pathspec_match_list_free()` on this object.
+ *
+ * @param out Output list of matches; pass NULL to just get return value
+ * @param diff A generated diff list
+ * @param flags Combination of git_pathspec_flag_t options to control match
+ * @param ps Pathspec to be matched
+ * @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
+ * the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
+ */
+GIT_EXTERN(int) git_pathspec_match_diff(
+ git_pathspec_match_list **out,
+ git_diff_list *diff,
+ uint32_t flags,
+ git_pathspec *ps);
+
+/**
* Free memory associates with a git_pathspec_match_list
*
* @param m The git_pathspec_match_list to be freed
@@ -185,6 +210,9 @@ GIT_EXTERN(size_t) git_pathspec_match_list_entrycount(
/**
* Get a matching filename by position.
*
+ * This routine cannot be used if the match list was generated by
+ * `git_pathspec_match_diff`. If so, it will always return NULL.
+ *
* @param m The git_pathspec_match_list object
* @param pos The index into the list
* @return The filename of the match
@@ -193,6 +221,19 @@ GIT_EXTERN(const char *) git_pathspec_match_list_entry(
const git_pathspec_match_list *m, size_t pos);
/**
+ * Get a matching diff delta by position.
+ *
+ * This routine can only be used if the match list was generated by
+ * `git_pathspec_match_diff`. Otherwise it will always return NULL.
+ *
+ * @param m The git_pathspec_match_list object
+ * @param pos The index into the list
+ * @return The filename of the match
+ */
+GIT_EXTERN(const git_diff_delta *) git_pathspec_match_list_diff_entry(
+ const git_pathspec_match_list *m, size_t pos);
+
+/**
* Get the number of pathspec items that did not match.
*
* This will be zero unless you passed GIT_PATHSPEC_FIND_FAILURES when
diff --git a/src/array.h b/src/array.h
index 707570624..248010425 100644
--- a/src/array.h
+++ b/src/array.h
@@ -66,4 +66,6 @@ GIT_INLINE(void *) git_array_grow(git_array_generic_t *a, size_t item_size)
#define git_array_size(a) (a).size
+#define git_array_valid_index(a, i) ((i) < (a).size)
+
#endif
diff --git a/src/diff.c b/src/diff.c
index 56232ebf4..cc7be451f 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -247,6 +247,11 @@ GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta)
return str;
}
+const char *git_diff_delta__path(const git_diff_delta *delta)
+{
+ return diff_delta__path(delta);
+}
+
int git_diff_delta__cmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
@@ -1235,6 +1240,11 @@ size_t git_diff_num_deltas_of_type(git_diff_list *diff, git_delta_t type)
return count;
}
+int git_diff_is_sorted_icase(const git_diff_list *diff)
+{
+ return (diff->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0;
+}
+
int git_diff__paired_foreach(
git_diff_list *head2idx,
git_diff_list *idx2wd,
diff --git a/src/diff.h b/src/diff.h
index 6ef03ee7c..d09a130bc 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -76,6 +76,8 @@ extern void git_diff_list_addref(git_diff_list *diff);
extern int git_diff_delta__cmp(const void *a, const void *b);
extern int git_diff_delta__casecmp(const void *a, const void *b);
+extern const char *git_diff_delta__path(const git_diff_delta *delta);
+
extern bool git_diff_delta__should_skip(
const git_diff_options *opts, const git_diff_delta *delta);
diff --git a/src/pathspec.c b/src/pathspec.c
index 021f38f1c..625726e0b 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -6,12 +6,15 @@
*/
#include "git2/pathspec.h"
+#include "git2/diff.h"
#include "pathspec.h"
#include "buf_text.h"
#include "attr_file.h"
#include "iterator.h"
#include "repository.h"
#include "index.h"
+#include "bitvec.h"
+#include "diff.h"
/* what is the common non-wildcard prefix for all items in the pathspec */
char *git_pathspec_prefix(const git_strarray *pathspec)
@@ -162,6 +165,28 @@ static int pathspec_match_one(
return -1;
}
+static int git_pathspec__match_at(
+ size_t *matched_at,
+ const git_vector *vspec,
+ struct pathspec_match_context *ctxt,
+ const char *path0,
+ const char *path1)
+{
+ int result = GIT_ENOTFOUND;
+ size_t i = 0;
+ const git_attr_fnmatch *match;
+
+ git_vector_foreach(vspec, i, match) {
+ if (path0 && (result = pathspec_match_one(match, ctxt, path0)) >= 0)
+ break;
+ if (path1 && (result = pathspec_match_one(match, ctxt, path1)) >= 0)
+ break;
+ }
+
+ *matched_at = i;
+ return result;
+}
+
/* match a path against the vectorized pathspec */
bool git_pathspec__match(
const git_vector *vspec,
@@ -171,8 +196,8 @@ bool git_pathspec__match(
const char **matched_pathspec,
size_t *matched_at)
{
- size_t i;
- const git_attr_fnmatch *match;
+ int result;
+ size_t pos;
struct pathspec_match_context ctxt;
if (matched_pathspec)
@@ -185,20 +210,18 @@ bool git_pathspec__match(
pathspec_match_context_init(&ctxt, disable_fnmatch, casefold);
- git_vector_foreach(vspec, i, match) {
- int result = pathspec_match_one(match, &ctxt, path);
-
- if (result >= 0) {
- if (matched_pathspec)
- *matched_pathspec = match->pattern;
- if (matched_at)
- *matched_at = i;
-
- return (result != 0);
+ result = git_pathspec__match_at(&pos, vspec, &ctxt, path, NULL);
+ if (result >= 0) {
+ if (matched_pathspec) {
+ const git_attr_fnmatch *match = git_vector_get(vspec, pos);
+ *matched_pathspec = match->pattern;
}
+
+ if (matched_at)
+ *matched_at = pos;
}
- return false;
+ return (result > 0);
}
@@ -277,7 +300,8 @@ static void pathspec_match_free(git_pathspec_match_list *m)
git__free(m);
}
-static git_pathspec_match_list *pathspec_match_alloc(git_pathspec *ps)
+static git_pathspec_match_list *pathspec_match_alloc(
+ git_pathspec *ps, int datatype)
{
git_pathspec_match_list *m = git__calloc(1, sizeof(git_pathspec_match_list));
@@ -292,16 +316,73 @@ static git_pathspec_match_list *pathspec_match_alloc(git_pathspec *ps)
*/
GIT_REFCOUNT_INC(ps);
m->pathspec = ps;
+ m->datatype = datatype;
return m;
}
-GIT_INLINE(void) pathspec_mark_pattern(uint8_t *used, size_t pos, size_t *ct)
+GIT_INLINE(size_t) pathspec_mark_pattern(git_bitvec *used, size_t pos)
+{
+ if (!git_bitvec_get(used, pos)) {
+ git_bitvec_set(used, pos, true);
+ return 1;
+ }
+
+ return 0;
+}
+
+static size_t pathspec_mark_remaining(
+ git_bitvec *used,
+ git_vector *patterns,
+ struct pathspec_match_context *ctxt,
+ size_t start,
+ const char *path0,
+ const char *path1)
+{
+ size_t count = 0;
+
+ if (path1 == path0)
+ path1 = NULL;
+
+ for (; start < patterns->length; ++start) {
+ const git_attr_fnmatch *pat = git_vector_get(patterns, start);
+
+ if (git_bitvec_get(used, start))
+ continue;
+
+ if (path0 && pathspec_match_one(pat, ctxt, path0) > 0)
+ count += pathspec_mark_pattern(used, start);
+ else if (path1 && pathspec_match_one(pat, ctxt, path1) > 0)
+ count += pathspec_mark_pattern(used, start);
+ }
+
+ return count;
+}
+
+static int pathspec_build_failure_array(
+ git_pathspec_string_array_t *failures,
+ git_vector *patterns,
+ git_bitvec *used,
+ git_pool *pool)
{
- if (!used[pos]) {
- used[pos] = 1;
- (*ct)++;
+ size_t pos;
+ char **failed;
+ const git_attr_fnmatch *pat;
+
+ for (pos = 0; pos < patterns->length; ++pos) {
+ if (git_bitvec_get(used, pos))
+ continue;
+
+ if ((failed = git_array_alloc(*failures)) == NULL)
+ return -1;
+
+ pat = git_vector_get(patterns, pos);
+
+ if ((*failed = git_pool_strdup(pool, pat->pattern)) == NULL)
+ return -1;
}
+
+ return 0;
}
static int pathspec_match_from_iterator(
@@ -315,47 +396,37 @@ static int pathspec_match_from_iterator(
const git_index_entry *entry = NULL;
struct pathspec_match_context ctxt;
git_vector *patterns = &ps->pathspec;
- bool find_failures = (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
- bool failures_only = (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
+ bool find_failures = out && (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
+ bool failures_only = !out || (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
size_t pos, used_ct = 0, found_files = 0;
git_index *index = NULL;
- uint8_t *used_patterns = NULL;
+ git_bitvec used_patterns;
char **file;
+ if (git_bitvec_init(&used_patterns, patterns->length) < 0)
+ return -1;
+
if (out) {
- *out = m = pathspec_match_alloc(ps);
+ *out = m = pathspec_match_alloc(ps, PATHSPEC_DATATYPE_STRINGS);
GITERR_CHECK_ALLOC(m);
- } else {
- failures_only = true;
- find_failures = false;
}
if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0)
goto done;
- if (patterns->length > 0) {
- used_patterns = git__calloc(patterns->length, sizeof(uint8_t));
- GITERR_CHECK_ALLOC(used_patterns);
- }
-
if (git_iterator_type(iter) == GIT_ITERATOR_TYPE_WORKDIR &&
(error = git_repository_index__weakptr(
&index, git_iterator_owner(iter))) < 0)
goto done;
- pathspec_match_context_init(&ctxt,
- (flags & GIT_PATHSPEC_NO_GLOB) != 0, git_iterator_ignore_case(iter));
+ pathspec_match_context_init(
+ &ctxt, (flags & GIT_PATHSPEC_NO_GLOB) != 0,
+ git_iterator_ignore_case(iter));
while (!(error = git_iterator_advance(&entry, iter))) {
- int result = -1;
-
- for (pos = 0; pos < patterns->length; ++pos) {
- const git_attr_fnmatch *pat = git_vector_get(patterns, pos);
-
- result = pathspec_match_one(pat, &ctxt, entry->path);
- if (result >= 0)
- break;
- }
+ /* search for match with entry->path */
+ int result = git_pathspec__match_at(
+ &pos, patterns, &ctxt, entry->path, NULL);
/* no matches for this path */
if (result < 0)
@@ -363,31 +434,24 @@ static int pathspec_match_from_iterator(
/* if result was a negative pattern match, then don't list file */
if (!result) {
- pathspec_mark_pattern(used_patterns, pos, &used_ct);
+ used_ct += pathspec_mark_pattern(&used_patterns, pos);
continue;
}
- /* check if path is untracked and ignored */
+ /* check if path is ignored and untracked */
if (index != NULL &&
git_iterator_current_is_ignored(iter) &&
git_index__find(NULL, index, entry->path, GIT_INDEX_STAGE_ANY) < 0)
continue;
/* mark the matched pattern as used */
- pathspec_mark_pattern(used_patterns, pos, &used_ct);
+ used_ct += pathspec_mark_pattern(&used_patterns, pos);
++found_files;
/* if find_failures is on, check if any later patterns also match */
- if (find_failures && used_ct < patterns->length) {
- for (++pos; pos < patterns->length; ++pos) {
- const git_attr_fnmatch *pat = git_vector_get(patterns, pos);
- if (used_patterns[pos])
- continue;
-
- if (pathspec_match_one(pat, &ctxt, entry->path) > 0)
- pathspec_mark_pattern(used_patterns, pos, &used_ct);
- }
- }
+ if (find_failures && used_ct < patterns->length)
+ used_ct += pathspec_mark_remaining(
+ &used_patterns, patterns, &ctxt, pos + 1, entry->path, NULL);
/* if only looking at failures, exit early or just continue */
if (failures_only || !out) {
@@ -397,7 +461,7 @@ static int pathspec_match_from_iterator(
}
/* insert matched path into matches array */
- if ((file = git_array_alloc(m->matches)) == NULL ||
+ if ((file = (char **)git_array_alloc(m->matches)) == NULL ||
(*file = git_pool_strdup(&m->pool, entry->path)) == NULL) {
error = -1;
goto done;
@@ -409,19 +473,10 @@ static int pathspec_match_from_iterator(
error = 0;
/* insert patterns that had no matches into failures array */
- if (find_failures && used_ct < patterns->length) {
- for (pos = 0; pos < patterns->length; ++pos) {
- const git_attr_fnmatch *pat = git_vector_get(patterns, pos);
- if (used_patterns[pos])
- continue;
-
- if ((file = git_array_alloc(m->failures)) == NULL ||
- (*file = git_pool_strdup(&m->pool, pat->pattern)) == NULL) {
- error = -1;
- goto done;
- }
- }
- }
+ if (find_failures && used_ct < patterns->length &&
+ (error = pathspec_build_failure_array(
+ &m->failures, patterns, &used_patterns, &m->pool)) < 0)
+ goto done;
/* if every pattern failed to match, then we have failed */
if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_files) {
@@ -430,7 +485,7 @@ static int pathspec_match_from_iterator(
}
done:
- git__free(used_patterns);
+ git_bitvec_free(&used_patterns);
if (error < 0) {
pathspec_match_free(m);
@@ -518,33 +573,142 @@ int git_pathspec_match_tree(
return error;
}
+int git_pathspec_match_diff(
+ git_pathspec_match_list **out,
+ git_diff_list *diff,
+ uint32_t flags,
+ git_pathspec *ps)
+{
+ int error = 0;
+ git_pathspec_match_list *m = NULL;
+ struct pathspec_match_context ctxt;
+ git_vector *patterns = &ps->pathspec;
+ bool find_failures = out && (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
+ bool failures_only = !out || (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
+ size_t i, pos, used_ct = 0, found_deltas = 0;
+ const git_diff_delta *delta, **match;
+ git_bitvec used_patterns;
+
+ assert(diff);
+
+ if (git_bitvec_init(&used_patterns, patterns->length) < 0)
+ return -1;
+
+ if (out) {
+ *out = m = pathspec_match_alloc(ps, PATHSPEC_DATATYPE_DIFF);
+ GITERR_CHECK_ALLOC(m);
+ }
+
+ pathspec_match_context_init(
+ &ctxt, (flags & GIT_PATHSPEC_NO_GLOB) != 0,
+ git_diff_is_sorted_icase(diff));
+
+ git_vector_foreach(&diff->deltas, i, delta) {
+ /* search for match with delta */
+ int result = git_pathspec__match_at(
+ &pos, patterns, &ctxt, delta->old_file.path, delta->new_file.path);
+
+ /* no matches for this path */
+ if (result < 0)
+ continue;
+
+ /* mark the matched pattern as used */
+ used_ct += pathspec_mark_pattern(&used_patterns, pos);
+
+ /* if result was a negative pattern match, then don't list file */
+ if (!result)
+ continue;
+
+ ++found_deltas;
+
+ /* if find_failures is on, check if any later patterns also match */
+ if (find_failures && used_ct < patterns->length)
+ used_ct += pathspec_mark_remaining(
+ &used_patterns, patterns, &ctxt, pos + 1,
+ delta->old_file.path, delta->new_file.path);
+
+ /* if only looking at failures, exit early or just continue */
+ if (failures_only || !out) {
+ if (used_ct == patterns->length)
+ break;
+ continue;
+ }
+
+ /* insert matched delta into matches array */
+ if (!(match = (const git_diff_delta **)git_array_alloc(m->matches))) {
+ error = -1;
+ goto done;
+ } else {
+ *match = delta;
+ }
+ }
+
+ /* insert patterns that had no matches into failures array */
+ if (find_failures && used_ct < patterns->length &&
+ (error = pathspec_build_failure_array(
+ &m->failures, patterns, &used_patterns, &m->pool)) < 0)
+ goto done;
+
+ /* if every pattern failed to match, then we have failed */
+ if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_deltas) {
+ giterr_set(GITERR_INVALID, "No matching deltas were found");
+ error = GIT_ENOTFOUND;
+ }
+
+done:
+ git_bitvec_free(&used_patterns);
+
+ if (error < 0) {
+ pathspec_match_free(m);
+ if (out) *out = NULL;
+ }
+
+ return error;
+}
+
void git_pathspec_match_list_free(git_pathspec_match_list *m)
{
- pathspec_match_free(m);
+ if (m)
+ pathspec_match_free(m);
}
size_t git_pathspec_match_list_entrycount(
const git_pathspec_match_list *m)
{
- return git_array_size(m->matches);
+ return m ? git_array_size(m->matches) : 0;
}
const char *git_pathspec_match_list_entry(
const git_pathspec_match_list *m, size_t pos)
{
- char **entry = git_array_get(m->matches, pos);
- return entry ? *entry : NULL;
+ if (!m || m->datatype != PATHSPEC_DATATYPE_STRINGS ||
+ !git_array_valid_index(m->matches, pos))
+ return NULL;
+
+ return *((const char **)git_array_get(m->matches, pos));
+}
+
+const git_diff_delta *git_pathspec_match_list_diff_entry(
+ const git_pathspec_match_list *m, size_t pos)
+{
+ if (!m || m->datatype != PATHSPEC_DATATYPE_DIFF ||
+ !git_array_valid_index(m->matches, pos))
+ return NULL;
+
+ return *((const git_diff_delta **)git_array_get(m->matches, pos));
}
size_t git_pathspec_match_list_failed_entrycount(
const git_pathspec_match_list *m)
{
- return git_array_size(m->failures);
+ return m ? git_array_size(m->failures) : 0;
}
const char * git_pathspec_match_list_failed_entry(
const git_pathspec_match_list *m, size_t pos)
{
- char **entry = git_array_get(m->failures, pos);
+ char **entry = m ? git_array_get(m->failures, pos) : NULL;
+
return entry ? *entry : NULL;
}
+
diff --git a/src/pathspec.h b/src/pathspec.h
index e7edfea38..40cd21c3f 100644
--- a/src/pathspec.h
+++ b/src/pathspec.h
@@ -22,12 +22,20 @@ struct git_pathspec {
git_pool pool;
};
+enum {
+ PATHSPEC_DATATYPE_STRINGS = 0,
+ PATHSPEC_DATATYPE_DIFF = 1,
+};
+
+typedef git_array_t(char *) git_pathspec_string_array_t;
+
/* public interface to pathspec matching */
struct git_pathspec_match_list {
git_pathspec *pathspec;
- git_array_t(char *) matches;
- git_array_t(char *) failures;
+ git_array_t(void *) matches;
+ git_pathspec_string_array_t failures;
git_pool pool;
+ int datatype;
};
/* what is the common non-wildcard prefix for all items in the pathspec */
diff --git a/tests-clar/diff/pathspec.c b/tests-clar/diff/pathspec.c
new file mode 100644
index 000000000..332b513b3
--- /dev/null
+++ b/tests-clar/diff/pathspec.c
@@ -0,0 +1,92 @@
+#include "clar_libgit2.h"
+#include "diff_helpers.h"
+
+static git_repository *g_repo = NULL;
+
+void test_diff_pathspec__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("status");
+}
+
+void test_diff_pathspec__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_diff_pathspec__0(void)
+{
+ const char *a_commit = "26a125ee"; /* the current HEAD */
+ const char *b_commit = "0017bd4a"; /* the start */
+ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit);
+ git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit);
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff_list *diff = NULL;
+ git_strarray paths = { NULL, 1 };
+ char *path;
+ git_pathspec *ps;
+ git_pathspec_match_list *matches;
+
+ cl_assert(a);
+ cl_assert(b);
+
+ path = "*_file";
+ paths.strings = &path;
+ cl_git_pass(git_pathspec_new(&ps, &paths));
+
+ cl_git_pass(git_pathspec_match_tree(&matches, a, GIT_PATHSPEC_DEFAULT, ps));
+ cl_assert_equal_i(7, git_pathspec_match_list_entrycount(matches));
+ cl_assert_equal_s("current_file", git_pathspec_match_list_entry(matches,0));
+ cl_assert(git_pathspec_match_list_diff_entry(matches,0) == NULL);
+ git_pathspec_match_list_free(matches);
+
+ cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, NULL, a, &opts));
+
+ cl_git_pass(git_pathspec_match_diff(
+ &matches, diff, GIT_PATHSPEC_DEFAULT, ps));
+ cl_assert_equal_i(7, git_pathspec_match_list_entrycount(matches));
+ cl_assert(git_pathspec_match_list_diff_entry(matches, 0) != NULL);
+ cl_assert(git_pathspec_match_list_entry(matches, 0) == NULL);
+ cl_assert_equal_s("current_file",
+ git_pathspec_match_list_diff_entry(matches,0)->new_file.path);
+ cl_assert_equal_i(GIT_DELTA_ADDED,
+ git_pathspec_match_list_diff_entry(matches,0)->status);
+ git_pathspec_match_list_free(matches);
+
+ git_diff_list_free(diff);
+ diff = NULL;
+
+ cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
+
+ cl_git_pass(git_pathspec_match_diff(
+ &matches, diff, GIT_PATHSPEC_DEFAULT, ps));
+ cl_assert_equal_i(3, git_pathspec_match_list_entrycount(matches));
+ cl_assert(git_pathspec_match_list_diff_entry(matches, 0) != NULL);
+ cl_assert(git_pathspec_match_list_entry(matches, 0) == NULL);
+ cl_assert_equal_s("subdir/current_file",
+ git_pathspec_match_list_diff_entry(matches,0)->new_file.path);
+ cl_assert_equal_i(GIT_DELTA_DELETED,
+ git_pathspec_match_list_diff_entry(matches,0)->status);
+ git_pathspec_match_list_free(matches);
+
+ git_diff_list_free(diff);
+ diff = NULL;
+
+ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts));
+
+ cl_git_pass(git_pathspec_match_diff(
+ &matches, diff, GIT_PATHSPEC_DEFAULT, ps));
+ cl_assert_equal_i(4, git_pathspec_match_list_entrycount(matches));
+ cl_assert(git_pathspec_match_list_diff_entry(matches, 0) != NULL);
+ cl_assert(git_pathspec_match_list_entry(matches, 0) == NULL);
+ cl_assert_equal_s("modified_file",
+ git_pathspec_match_list_diff_entry(matches,0)->new_file.path);
+ cl_assert_equal_i(GIT_DELTA_MODIFIED,
+ git_pathspec_match_list_diff_entry(matches,0)->status);
+ git_pathspec_match_list_free(matches);
+
+ git_diff_list_free(diff);
+ diff = NULL;
+
+ git_tree_free(a);
+ git_tree_free(b);
+}