From d62e44cb8218840a0291fb5fbb7c5106e1e35a12 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Mon, 3 Jun 2019 18:35:08 +0300 Subject: [PATCH] checkout: Fix removing untracked files by path in subdirectories The checkout code didn't iterate into a subdir if it didn't match the pathspec, but since the pathspec might match files in the subdir we should recurse into it (In contrast to gitignore handling). Fixes #5089 --- src/checkout.c | 9 +++++++-- tests/checkout/head.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index f0dd736dc..59ff873dd 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -371,8 +371,13 @@ static int checkout_action_wd_only( if (!git_pathspec__match( pathspec, wd->path, (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0, - git_iterator_ignore_case(workdir), NULL, NULL)) - return git_iterator_advance(wditem, workdir); + git_iterator_ignore_case(workdir), NULL, NULL)) { + + if (wd->mode == GIT_FILEMODE_TREE) + return git_iterator_advance_into(wditem, workdir); + else + return git_iterator_advance(wditem, workdir); + } /* check if item is tracked in the index but not in the checkout diff */ if (data->index != NULL) { diff --git a/tests/checkout/head.c b/tests/checkout/head.c index 799123086..5b3a034e7 100644 --- a/tests/checkout/head.c +++ b/tests/checkout/head.c @@ -109,6 +109,32 @@ void test_checkout_head__do_not_remove_untracked_file_in_subdir(void) cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked")); } +void test_checkout_head__do_remove_untracked_paths(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + char *paths[] = {"tracked/untracked"}; + + cl_git_pass(p_mkdir("testrepo/tracked", 0755)); + cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755)); + cl_git_mkfile("testrepo/tracked/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/untracked", "untracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "tracked/tracked")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; + opts.paths.strings = paths; + opts.paths.count = 1; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(git_path_isfile("testrepo/tracked/tracked")); + cl_assert(!git_path_isfile("testrepo/tracked/untracked")); +} + void test_checkout_head__do_remove_tracked_subdir(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; -- 2.27.0