Add flag to turn off pathspec testing for diff and status
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
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);
+}