Merge pull request #5378 from libgit2/ethomson/checkout_pathspecs Honor GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH for all checkout types
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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
diff --git a/src/checkout.c b/src/checkout.c
index 5cfa728..f0dd736 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2544,6 +2544,17 @@ cleanup:
#define CHECKOUT_INDEX_DONT_WRITE_MASK \
(GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
+GIT_INLINE(void) setup_pathspecs(
+ git_iterator_options *iter_opts,
+ const git_checkout_options *checkout_opts)
+{
+ if (checkout_opts &&
+ (checkout_opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
+ iter_opts->pathlist.count = checkout_opts->paths.count;
+ iter_opts->pathlist.strings = checkout_opts->paths.strings;
+ }
+}
+
int git_checkout_iterator(
git_iterator *target,
git_index *index,
@@ -2586,6 +2597,8 @@ int git_checkout_iterator(
workdir_opts.start = data.pfx;
workdir_opts.end = data.pfx;
+ setup_pathspecs(&workdir_opts, opts);
+
if ((error = git_iterator_reset_range(target, data.pfx, data.pfx)) < 0 ||
(error = git_iterator_for_workdir_ext(
&workdir, data.repo, data.opts.target_directory, index, NULL,
@@ -2596,10 +2609,8 @@ int git_checkout_iterator(
GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
baseline_opts.start = data.pfx;
baseline_opts.end = data.pfx;
- if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
- baseline_opts.pathlist.count = opts->paths.count;
- baseline_opts.pathlist.strings = opts->paths.strings;
- }
+
+ setup_pathspecs(&baseline_opts, opts);
if (data.opts.baseline_index) {
if ((error = git_iterator_for_index(
@@ -2689,6 +2700,7 @@ int git_checkout_index(
git_index *index,
const git_checkout_options *opts)
{
+ git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
int error, owned = 0;
git_iterator *index_i;
@@ -2716,7 +2728,9 @@ int git_checkout_index(
return error;
GIT_REFCOUNT_INC(index);
- if (!(error = git_iterator_for_index(&index_i, repo, index, NULL)))
+ setup_pathspecs(&iter_opts, opts);
+
+ if (!(error = git_iterator_for_index(&index_i, repo, index, &iter_opts)))
error = git_checkout_iterator(index_i, index, opts);
if (owned)
@@ -2773,10 +2787,7 @@ int git_checkout_tree(
if ((error = git_repository_index(&index, repo)) < 0)
return error;
- if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
- iter_opts.pathlist.count = opts->paths.count;
- iter_opts.pathlist.strings = opts->paths.strings;
- }
+ setup_pathspecs(&iter_opts, opts);
if (!(error = git_iterator_for_tree(&tree_i, tree, &iter_opts)))
error = git_checkout_iterator(tree_i, index, opts);
diff --git a/tests/checkout/index.c b/tests/checkout/index.c
index a76c471..8134673 100644
--- a/tests/checkout/index.c
+++ b/tests/checkout/index.c
@@ -89,6 +89,65 @@ void test_checkout_index__can_remove_untracked_files(void)
cl_assert_equal_i(false, git_path_isdir("./testrepo/dir"));
}
+void test_checkout_index__can_disable_pathspec_match(void)
+{
+ static git_index *index;
+ git_oid commit_id;
+ git_checkout_options g_opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_object *g_object;
+
+ char *files_to_checkout[] = { "test10.txt", "test11.txt"};
+ size_t files_to_checkout_size = 2;
+
+ /* reset to beginning of history (i.e. just a README file) */
+ g_opts.checkout_strategy =
+ GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
+
+ cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479"));
+ cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
+ cl_git_pass(
+ git_repository_set_head_detached(g_repo, git_object_id(g_object)));
+ git_object_free(g_object);
+ g_object = NULL;
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* We create 4 files and commit them */
+ cl_git_mkfile("testrepo/test9.txt", "original\n");
+ cl_git_mkfile("testrepo/test10.txt", "original\n");
+ cl_git_mkfile("testrepo/test11.txt", "original\n");
+ cl_git_mkfile("testrepo/test12.txt", "original\n");
+
+ cl_git_pass(git_index_add_bypath(index, "test9.txt"));
+ cl_git_pass(git_index_add_bypath(index, "test10.txt"));
+ cl_git_pass(git_index_add_bypath(index, "test11.txt"));
+ cl_git_pass(git_index_add_bypath(index, "test12.txt"));
+ cl_git_pass(git_index_write(index));
+
+ cl_repo_commit_from_index(&commit_id, g_repo, NULL, 0, "commit our test files");
+
+ /* We modify the content of all 4 of our files */
+ cl_git_rewritefile("testrepo/test9.txt", "modified\n");
+ cl_git_rewritefile("testrepo/test10.txt", "modified\n");
+ cl_git_rewritefile("testrepo/test11.txt", "modified\n");
+ cl_git_rewritefile("testrepo/test12.txt", "modified\n");
+
+ /* We checkout only test10.txt and test11.txt */
+ g_opts.checkout_strategy =
+ GIT_CHECKOUT_FORCE |
+ GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH;
+ g_opts.paths.strings = files_to_checkout;
+ g_opts.paths.count = files_to_checkout_size;
+ cl_git_pass(git_checkout_index(g_repo, NULL, &g_opts));
+
+ /* The only files that have been reverted to their original content
+ should be test10.txt and test11.txt */
+ check_file_contents("testrepo/test9.txt", "modified\n");
+ check_file_contents("testrepo/test10.txt", "original\n");
+ check_file_contents("testrepo/test11.txt", "original\n");
+ check_file_contents("testrepo/test12.txt", "modified\n");
+}
+
void test_checkout_index__honor_the_specified_pathspecs(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;