Commit a1773f9d89887d299248d15b43953d3fa494a025

yorah 2012-07-23T18:16:09

Add flag to turn off pathspec testing for diff and status

diff --git a/include/git2/diff.h b/include/git2/diff.h
index edec995..85727d9 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -46,6 +46,7 @@ enum {
 	GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8),
 	GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9),
 	GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10),
+	GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11),
 };
 
 /**
diff --git a/include/git2/status.h b/include/git2/status.h
index 69b6e47..9e7b5de 100644
--- a/include/git2/status.h
+++ b/include/git2/status.h
@@ -96,6 +96,8 @@ typedef enum {
  *   the top-level directory will be included (with a trailing
  *   slash on the entry name).  Given this flag, the directory
  *   itself will not be included, but all the files in it will.
+ * - GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH indicates that the given
+ *   path will be treated as a literal path, and not as a pathspec.
  */
 
 enum {
@@ -104,6 +106,7 @@ enum {
 	GIT_STATUS_OPT_INCLUDE_UNMODIFIED = (1 << 2),
 	GIT_STATUS_OPT_EXCLUDE_SUBMODULES = (1 << 3),
 	GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = (1 << 4),
+	GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH = (1 << 5),
 };
 
 /**
diff --git a/src/diff.c b/src/diff.c
index f08688e..2b1529d 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -61,9 +61,10 @@ static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path)
 		return true;
 
 	git_vector_foreach(&diff->pathspec, i, match) {
-		int result = strcmp(match->pattern, path);
+		int result = strcmp(match->pattern, path) ? FNM_NOMATCH : 0;
 		
-		if (result != 0)
+		if (((diff->opts.flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH) == 0) && 
+			result == FNM_NOMATCH)
 			result = p_fnmatch(match->pattern, path, 0);
 
 		/* if we didn't match, look for exact dirname prefix match */
diff --git a/src/status.c b/src/status.c
index 633082c..d782376 100644
--- a/src/status.c
+++ b/src/status.c
@@ -99,6 +99,8 @@ int git_status_foreach_ext(
 		diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED;
 	if ((opts->flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0)
 		diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
+	if ((opts->flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0)
+		diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
 	/* TODO: support EXCLUDE_SUBMODULES flag */
 
 	if (show != GIT_STATUS_SHOW_WORKDIR_ONLY &&
diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c
index 1bdd816..bd57cf2 100644
--- a/tests-clar/status/worktree.c
+++ b/tests-clar/status/worktree.c
@@ -726,3 +726,49 @@ void test_status_worktree__filemode_changes(void)
 
 	git_config_free(cfg);
 }
+
+int cb_status__expected_path(const char *p, unsigned int s, void *payload)
+{
+	const char *expected_path = (const char *)payload;
+
+	GIT_UNUSED(s);
+
+	if (payload == NULL)
+		cl_fail("Unexpected path");
+
+	cl_assert_equal_s(expected_path, p);
+
+	return 0;
+}
+
+void test_status_worktree__disable_pathspec_match(void)
+{
+	git_repository *repo;
+	git_status_options opts;
+	char *file_with_bracket = "LICENSE[1].md", 
+		*imaginary_file_with_bracket = "LICENSE[1-2].md";
+
+	cl_git_pass(git_repository_init(&repo, "pathspec", 0));
+	cl_git_mkfile("pathspec/LICENSE[1].md", "screaming bracket\n");
+	cl_git_mkfile("pathspec/LICENSE1.md", "no bracket\n");
+
+	memset(&opts, 0, sizeof(opts));
+	opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | 
+		GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH;
+	opts.pathspec.count = 1;
+	opts.pathspec.strings = &file_with_bracket;
+
+	cl_git_pass(
+		git_status_foreach_ext(repo, &opts, cb_status__expected_path, 
+		file_with_bracket)
+	);
+
+	/* Test passing a pathspec matching files in the workdir. */
+	/* Must not match because pathspecs are disabled. */ 
+	opts.pathspec.strings = &imaginary_file_with_bracket;
+	cl_git_pass(
+		git_status_foreach_ext(repo, &opts, cb_status__expected_path, NULL)
+	);
+	
+	git_repository_free(repo);
+}