From: Edward Thomson Date: Tue, 31 Mar 2015 20:28:13 +0000 (-0400) Subject: checkout: remove blocking dir when FORCEd X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=05f690122e9927eece61afb17c1595a136d119b2;p=libgit2.git checkout: remove blocking dir when FORCEd --- diff --git a/src/checkout.c b/src/checkout.c index b70ea1892..dd10732b5 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -409,6 +409,14 @@ static bool submodule_is_config_only( return rval; } +static bool checkout_is_empty_dir(checkout_data *data, const char *path) +{ + git_buf_truncate(&data->path, data->workdir_len); + if (git_buf_puts(&data->path, path) < 0) + return false; + return git_path_is_empty_dir(data->path.ptr); +} + static int checkout_action_with_wd( int *action, checkout_data *data, @@ -526,6 +534,7 @@ static int checkout_action_with_wd_dir( checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL)); GITERR_CHECK_ERROR( checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE); break; case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */ case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */ @@ -550,8 +559,6 @@ static int checkout_action_with_wd_dir( * dir and it will succeed if no children are left. */ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); - if (*action != CHECKOUT_ACTION__NONE) - *action |= CHECKOUT_ACTION__DEFER_REMOVE; } else if (delta->new_file.mode != GIT_FILEMODE_TREE) /* For typechange to dir, dir is already created so no action */ @@ -564,6 +571,20 @@ static int checkout_action_with_wd_dir( return checkout_action_common(action, data, delta, wd); } +static int checkout_action_with_wd_dir_empty( + int *action, + checkout_data *data, + const git_diff_delta *delta) +{ + int error = checkout_action_no_wd(action, data, delta); + + /* We can always safely remove an empty directory. */ + if (error == 0 && *action != CHECKOUT_ACTION__NONE) + *action |= CHECKOUT_ACTION__REMOVE; + + return error; +} + static int checkout_action( int *action, checkout_data *data, @@ -653,7 +674,9 @@ static int checkout_action( } } - return checkout_action_with_wd_dir(action, data, delta, workdir, wd); + return checkout_is_empty_dir(data, wd->path) ? + checkout_action_with_wd_dir_empty(action, data, delta) : + checkout_action_with_wd_dir(action, data, delta, workdir, wd); } /* case 6 - wd is after delta */ diff --git a/tests/checkout/icase.c b/tests/checkout/icase.c index 211738070..ae1a63b90 100644 --- a/tests/checkout/icase.c +++ b/tests/checkout/icase.c @@ -21,7 +21,7 @@ void test_checkout_icase__initialize(void) cl_git_pass(git_object_lookup(&obj, repo, &id, GIT_OBJ_ANY)); git_checkout_init_options(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION); - checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE; } void test_checkout_icase__cleanup(void) @@ -79,8 +79,21 @@ static void assert_name_is(const char *expected) free(actual); } -void test_checkout_icase__overwrites_files_for_files(void) +void test_checkout_icase__refuses_to_overwrite_files_for_files(void) +{ + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + + cl_git_write2file("testrepo/BRANCH_FILE.txt", "neue file\n", 10, \ + O_WRONLY | O_CREAT | O_TRUNC, 0644); + + cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); + assert_name_is("testrepo/BRANCH_FILE.txt"); +} + +void test_checkout_icase__overwrites_files_for_files_when_forced(void) { + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_write2file("testrepo/NEW.txt", "neue file\n", 10, \ O_WRONLY | O_CREAT | O_TRUNC, 0644); @@ -88,8 +101,22 @@ void test_checkout_icase__overwrites_files_for_files(void) assert_name_is("testrepo/new.txt"); } -void test_checkout_icase__overwrites_links_for_files(void) +void test_checkout_icase__refuses_to_overwrite_links_for_files(void) { + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + + cl_must_pass(p_symlink("../tmp", "testrepo/BRANCH_FILE.txt")); + + cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); + + cl_assert(!git_path_exists("tmp")); + assert_name_is("testrepo/BRANCH_FILE.txt"); +} + +void test_checkout_icase__overwrites_links_for_files_when_forced(void) +{ + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_must_pass(p_symlink("../tmp", "testrepo/NEW.txt")); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); @@ -98,9 +125,39 @@ void test_checkout_icase__overwrites_links_for_files(void) assert_name_is("testrepo/new.txt"); } -void test_checkout_icase__overwites_folders_for_files(void) +void test_checkout_icase__overwrites_empty_folders_for_files(void) +{ + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + + cl_must_pass(p_mkdir("testrepo/NEW.txt", 0777)); + + cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); + + assert_name_is("testrepo/new.txt"); + cl_assert(!git_path_isdir("testrepo/new.txt")); +} + +void test_checkout_icase__refuses_to_overwrite_populated_folders_for_files(void) +{ + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + + cl_must_pass(p_mkdir("testrepo/BRANCH_FILE.txt", 0777)); + cl_git_write2file("testrepo/BRANCH_FILE.txt/foobar", "neue file\n", 10, \ + O_WRONLY | O_CREAT | O_TRUNC, 0644); + + cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); + + assert_name_is("testrepo/BRANCH_FILE.txt"); + cl_assert(git_path_isdir("testrepo/BRANCH_FILE.txt")); +} + +void test_checkout_icase__overwrites_folders_for_files_when_forced(void) { + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_must_pass(p_mkdir("testrepo/NEW.txt", 0777)); + cl_git_write2file("testrepo/NEW.txt/foobar", "neue file\n", 10, \ + O_WRONLY | O_CREAT | O_TRUNC, 0644); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); @@ -108,8 +165,22 @@ void test_checkout_icase__overwites_folders_for_files(void) cl_assert(!git_path_isdir("testrepo/new.txt")); } -void test_checkout_icase__overwrites_files_for_folders(void) +void test_checkout_icase__refuses_to_overwrite_files_for_folders(void) { + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + + cl_git_write2file("testrepo/A", "neue file\n", 10, \ + O_WRONLY | O_CREAT | O_TRUNC, 0644); + + cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); + assert_name_is("testrepo/A"); + cl_assert(!git_path_isdir("testrepo/A")); +} + +void test_checkout_icase__overwrites_files_for_folders_when_forced(void) +{ + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_write2file("testrepo/A", "neue file\n", 10, \ O_WRONLY | O_CREAT | O_TRUNC, 0644); @@ -118,8 +189,22 @@ void test_checkout_icase__overwrites_files_for_folders(void) cl_assert(git_path_isdir("testrepo/a")); } -void test_checkout_icase__overwrites_links_for_folders(void) +void test_checkout_icase__refuses_to_overwrite_links_for_folders(void) +{ + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING; + + cl_must_pass(p_symlink("..", "testrepo/A")); + + cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts)); + + cl_assert(!git_path_exists("b.txt")); + assert_name_is("testrepo/A"); +} + +void test_checkout_icase__overwrites_links_for_folders_when_forced(void) { + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_must_pass(p_symlink("..", "testrepo/A")); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); @@ -127,4 +212,3 @@ void test_checkout_icase__overwrites_links_for_folders(void) cl_assert(!git_path_exists("b.txt")); assert_name_is("testrepo/a"); } -