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.
This commit is contained in:
Russell Belfer 2013-01-10 15:15:37 -08:00
parent 404880b1ba
commit 40342bd2b6
3 changed files with 93 additions and 2 deletions

View File

@ -131,6 +131,9 @@ typedef enum {
/** Don't refresh index/config/etc before doing checkout */
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
*/
@ -222,7 +225,8 @@ typedef struct git_checkout_opts {
void *progress_payload;
/** 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;

View File

@ -222,7 +222,9 @@ static int checkout_action_wd_only(
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
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;
/* check if item is tracked in the index but not in the checkout diff */
@ -1209,6 +1211,8 @@ int git_checkout_iterator(
GIT_DIFF_INCLUDE_TYPECHANGE |
GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
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)
diff_opts.pathspec = data.opts.paths;

View File

@ -273,3 +273,86 @@ void test_checkout_tree__can_update_only(void)
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"));
}