Commit 40342bd2 by Russell Belfer

Add GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH

This adds an option to checkout a la the diff option to turn off
fnmatch evaluation for pathspec entries.  This can be useful to
make sure your "pattern" in really interpretted as an exact file
match only.
parent 404880b1
...@@ -131,6 +131,9 @@ typedef enum { ...@@ -131,6 +131,9 @@ typedef enum {
/** Don't refresh index/config/etc before doing checkout */ /** Don't refresh index/config/etc before doing checkout */
GIT_CHECKOUT_NO_REFRESH = (1u << 9), GIT_CHECKOUT_NO_REFRESH = (1u << 9),
/** Treat pathspec as simple list of exact match file paths */
GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13),
/** /**
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
*/ */
...@@ -222,7 +225,8 @@ typedef struct git_checkout_opts { ...@@ -222,7 +225,8 @@ typedef struct git_checkout_opts {
void *progress_payload; void *progress_payload;
/** When not zeroed out, array of fnmatch patterns specifying which /** When not zeroed out, array of fnmatch patterns specifying which
* paths should be taken into account, otherwise all files. * paths should be taken into account, otherwise all files. Use
* GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as simple list.
*/ */
git_strarray paths; git_strarray paths;
......
...@@ -222,7 +222,9 @@ static int checkout_action_wd_only( ...@@ -222,7 +222,9 @@ static int checkout_action_wd_only(
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE; git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
if (!git_pathspec_match_path( if (!git_pathspec_match_path(
pathspec, wd->path, false, workdir->ignore_case)) pathspec, wd->path,
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
workdir->ignore_case))
return 0; return 0;
/* check if item is tracked in the index but not in the checkout diff */ /* check if item is tracked in the index but not in the checkout diff */
...@@ -1209,6 +1211,8 @@ int git_checkout_iterator( ...@@ -1209,6 +1211,8 @@ int git_checkout_iterator(
GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_INCLUDE_TYPECHANGE |
GIT_DIFF_INCLUDE_TYPECHANGE_TREES | GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
GIT_DIFF_SKIP_BINARY_CHECK; GIT_DIFF_SKIP_BINARY_CHECK;
if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)
diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
if (data.opts.paths.count > 0) if (data.opts.paths.count > 0)
diff_opts.pathspec = data.opts.paths; diff_opts.pathspec = data.opts.paths;
......
...@@ -273,3 +273,86 @@ void test_checkout_tree__can_update_only(void) ...@@ -273,3 +273,86 @@ void test_checkout_tree__can_update_only(void)
git_object_free(obj); git_object_free(obj);
} }
void test_checkout_tree__can_checkout_with_pattern(void)
{
char *entries[] = { "[l-z]*.txt" };
/* 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_assert(git_path_exists("testrepo/README"));
cl_assert(!git_path_exists("testrepo/branch_file.txt"));
cl_assert(!git_path_exists("testrepo/link_to_new.txt"));
cl_assert(!git_path_exists("testrepo/new.txt"));
/* now to a narrow patterned checkout */
g_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
g_opts.paths.strings = entries;
g_opts.paths.count = 1;
cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master"));
cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
cl_assert(git_path_exists("testrepo/README"));
cl_assert(!git_path_exists("testrepo/branch_file.txt"));
cl_assert(git_path_exists("testrepo/link_to_new.txt"));
cl_assert(git_path_exists("testrepo/new.txt"));
}
void test_checkout_tree__can_disable_pattern_match(void)
{
char *entries[] = { "b*.txt" };
/* 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_assert(!git_path_isfile("testrepo/branch_file.txt"));
/* now to a narrow patterned checkout, but disable pattern */
g_opts.checkout_strategy =
GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH;
g_opts.paths.strings = entries;
g_opts.paths.count = 1;
cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master"));
cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
cl_assert(!git_path_isfile("testrepo/branch_file.txt"));
/* let's try that again, but allow the pattern match */
g_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
cl_assert(git_path_isfile("testrepo/branch_file.txt"));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment