]> git.proxmox.com Git - libgit2.git/commitdiff
checkout: remove blocking dir when FORCEd
authorEdward Thomson <ethomson@microsoft.com>
Tue, 31 Mar 2015 20:28:13 +0000 (16:28 -0400)
committerEdward Thomson <ethomson@edwardthomson.com>
Mon, 4 May 2015 12:18:27 +0000 (07:18 -0500)
src/checkout.c
tests/checkout/icase.c

index b70ea1892a37393e7a6147ff4c6b14df9df8bbef..dd10732b5a168ff437f5df75a05fe0e206f56139 100644 (file)
@@ -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 */
index 211738070042e9742a6689b6edec8d6b728707ae..ae1a63b9045cbf29ec8d5432f10810a3c6c05de1 100644 (file)
@@ -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");
 }
-