| #include "clar_libgit2.h" |
| #include "checkout_helpers.h" |
| |
| #include "git2/checkout.h" |
| #include "fileops.h" |
| #include "repository.h" |
| #include "remote.h" |
| |
| static git_repository *g_repo; |
| |
| void test_checkout_index__initialize(void) |
| { |
| git_tree *tree; |
| |
| g_repo = cl_git_sandbox_init("testrepo"); |
| |
| cl_git_pass(git_repository_head_tree(&tree, g_repo)); |
| |
| reset_index_to_treeish((git_object *)tree); |
| git_tree_free(tree); |
| |
| cl_git_rewritefile( |
| "./testrepo/.gitattributes", |
| "* text eol=lf\n"); |
| } |
| |
| void test_checkout_index__cleanup(void) |
| { |
| cl_git_sandbox_cleanup(); |
| |
| /* try to remove alternative dir */ |
| if (git_path_isdir("alternative")) |
| git_futils_rmdir_r("alternative", NULL, GIT_RMDIR_REMOVE_FILES); |
| } |
| |
| void test_checkout_index__cannot_checkout_a_bare_repository(void) |
| { |
| test_checkout_index__cleanup(); |
| |
| g_repo = cl_git_sandbox_init("testrepo.git"); |
| |
| cl_git_fail(git_checkout_index(g_repo, NULL, NULL)); |
| } |
| |
| void test_checkout_index__can_create_missing_files(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/README", "hey there\n"); |
| check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n"); |
| check_file_contents("./testrepo/new.txt", "my new file\n"); |
| } |
| |
| void test_checkout_index__can_remove_untracked_files(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| git_futils_mkdir("./testrepo/dir/subdir/subsubdir", 0755, GIT_MKDIR_PATH); |
| cl_git_mkfile("./testrepo/dir/one", "one\n"); |
| cl_git_mkfile("./testrepo/dir/subdir/two", "two\n"); |
| |
| cl_assert_equal_i(true, git_path_isdir("./testrepo/dir/subdir/subsubdir")); |
| |
| opts.checkout_strategy = |
| GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING | |
| GIT_CHECKOUT_REMOVE_UNTRACKED; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_assert_equal_i(false, git_path_isdir("./testrepo/dir")); |
| } |
| |
| void test_checkout_index__honor_the_specified_pathspecs(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| char *entries[] = { "*.txt" }; |
| |
| opts.paths.strings = entries; |
| opts.paths.count = 1; |
| |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); |
| check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n"); |
| check_file_contents("./testrepo/new.txt", "my new file\n"); |
| } |
| |
| void test_checkout_index__honor_the_gitattributes_directives(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| const char *attributes = |
| "branch_file.txt text eol=crlf\n" |
| "new.txt text eol=lf\n"; |
| |
| cl_git_mkfile("./testrepo/.gitattributes", attributes); |
| cl_repo_set_bool(g_repo, "core.autocrlf", false); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/README", "hey there\n"); |
| check_file_contents("./testrepo/new.txt", "my new file\n"); |
| check_file_contents("./testrepo/branch_file.txt", "hi\r\nbye!\r\n"); |
| } |
| |
| void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void) |
| { |
| #ifdef GIT_WIN32 |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| const char *expected_readme_text = "hey there\r\n"; |
| |
| cl_git_pass(p_unlink("./testrepo/.gitattributes")); |
| cl_repo_set_bool(g_repo, "core.autocrlf", true); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/README", expected_readme_text); |
| #endif |
| } |
| |
| void test_checkout_index__honor_coresymlinks_default(void) |
| { |
| git_repository *repo; |
| git_remote *origin; |
| git_object *target; |
| char cwd[GIT_PATH_MAX]; |
| |
| const char *url = git_repository_path(g_repo); |
| |
| cl_assert(getcwd(cwd, sizeof(cwd)) != NULL); |
| cl_assert_equal_i(0, p_mkdir("readonly", 0555)); // Read-only directory |
| cl_assert_equal_i(0, chdir("readonly")); |
| cl_git_pass(git_repository_init(&repo, "../symlink.git", true)); |
| cl_assert_equal_i(0, chdir(cwd)); |
| cl_assert_equal_i(0, p_mkdir("symlink", 0777)); |
| cl_git_pass(git_repository_set_workdir(repo, "symlink", 1)); |
| |
| cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); |
| cl_git_pass(git_remote_fetch(origin, NULL, NULL, NULL)); |
| git_remote_free(origin); |
| |
| cl_git_pass(git_revparse_single(&target, repo, "remotes/origin/master")); |
| cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); |
| git_object_free(target); |
| git_repository_free(repo); |
| |
| #ifdef GIT_WIN32 |
| check_file_contents("./symlink/link_to_new.txt", "new.txt"); |
| #else |
| { |
| char link_data[1024]; |
| size_t link_size = 1024; |
| |
| link_size = p_readlink("./symlink/link_to_new.txt", link_data, link_size); |
| link_data[link_size] = '\0'; |
| cl_assert_equal_i(link_size, strlen("new.txt")); |
| cl_assert_equal_s(link_data, "new.txt"); |
| check_file_contents("./symlink/link_to_new.txt", "my new file\n"); |
| } |
| #endif |
| |
| cl_fixture_cleanup("symlink"); |
| } |
| |
| void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_repo_set_bool(g_repo, "core.symlinks", true); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| #ifdef GIT_WIN32 |
| check_file_contents("./testrepo/link_to_new.txt", "new.txt"); |
| #else |
| { |
| char link_data[1024]; |
| size_t link_size = 1024; |
| |
| link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size); |
| link_data[link_size] = '\0'; |
| cl_assert_equal_i(link_size, strlen("new.txt")); |
| cl_assert_equal_s(link_data, "new.txt"); |
| check_file_contents("./testrepo/link_to_new.txt", "my new file\n"); |
| } |
| #endif |
| } |
| |
| void test_checkout_index__honor_coresymlinks_setting_set_to_false(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_repo_set_bool(g_repo, "core.symlinks", false); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/link_to_new.txt", "new.txt"); |
| } |
| |
| void test_checkout_index__donot_overwrite_modified_file_by_default(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); |
| |
| /* set this up to not return an error code on conflicts, but it |
| * still will not have permission to overwrite anything... |
| */ |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/new.txt", "This isn't what's stored!"); |
| } |
| |
| void test_checkout_index__can_overwrite_modified_file(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_FORCE; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/new.txt", "my new file\n"); |
| } |
| |
| void test_checkout_index__options_disable_filters(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_git_mkfile("./testrepo/.gitattributes", "*.txt text eol=crlf\n"); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| opts.disable_filters = false; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/new.txt", "my new file\r\n"); |
| |
| p_unlink("./testrepo/new.txt"); |
| |
| opts.disable_filters = true; |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/new.txt", "my new file\n"); |
| } |
| |
| void test_checkout_index__options_dir_modes(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| struct stat st; |
| git_oid oid; |
| git_commit *commit; |
| mode_t um; |
| |
| if (!cl_is_chmod_supported()) |
| return; |
| |
| cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); |
| cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); |
| |
| reset_index_to_treeish((git_object *)commit); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| opts.dir_mode = 0701; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| /* umask will influence actual directory creation mode */ |
| (void)p_umask(um = p_umask(022)); |
| |
| cl_git_pass(p_stat("./testrepo/a", &st)); |
| /* Haiku & Hurd use other mode bits, so we must mask them out */ |
| cl_assert_equal_i_fmt(st.st_mode & (S_IFMT | 07777), (GIT_FILEMODE_TREE | 0701) & ~um, "%07o"); |
| |
| /* File-mode test, since we're on the 'dir' branch */ |
| cl_git_pass(p_stat("./testrepo/a/b.txt", &st)); |
| cl_assert_equal_i_fmt(st.st_mode & (S_IFMT | 07777), GIT_FILEMODE_BLOB_EXECUTABLE & ~um, "%07o"); |
| |
| git_commit_free(commit); |
| } |
| |
| void test_checkout_index__options_override_file_modes(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| struct stat st; |
| |
| if (!cl_is_chmod_supported()) |
| return; |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| opts.file_mode = 0700; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_git_pass(p_stat("./testrepo/new.txt", &st)); |
| cl_assert_equal_i_fmt(st.st_mode & GIT_MODE_PERMS_MASK, 0700, "%07o"); |
| } |
| |
| void test_checkout_index__options_open_flags(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_git_mkfile("./testrepo/new.txt", "hi\n"); |
| |
| opts.checkout_strategy = |
| GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DONT_REMOVE_EXISTING; |
| opts.file_open_flags = O_CREAT | O_RDWR | O_APPEND; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./testrepo/new.txt", "hi\nmy new file\n"); |
| } |
| |
| struct notify_data { |
| const char *file; |
| const char *sha; |
| }; |
| |
| static int test_checkout_notify_cb( |
| git_checkout_notify_t why, |
| const char *path, |
| const git_diff_file *baseline, |
| const git_diff_file *target, |
| const git_diff_file *workdir, |
| void *payload) |
| { |
| struct notify_data *expectations = (struct notify_data *)payload; |
| |
| GIT_UNUSED(workdir); |
| |
| cl_assert_equal_i(GIT_CHECKOUT_NOTIFY_CONFLICT, why); |
| cl_assert_equal_s(expectations->file, path); |
| cl_assert_equal_i(0, git_oid_streq(&baseline->id, expectations->sha)); |
| cl_assert_equal_i(0, git_oid_streq(&target->id, expectations->sha)); |
| |
| return 0; |
| } |
| |
| void test_checkout_index__can_notify_of_skipped_files(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| struct notify_data data; |
| |
| cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); |
| |
| /* |
| * $ git ls-tree HEAD |
| * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README |
| * 100644 blob 3697d64be941a53d4ae8f6a271e4e3fa56b022cc branch_file.txt |
| * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt |
| */ |
| data.file = "new.txt"; |
| data.sha = "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"; |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING | |
| GIT_CHECKOUT_ALLOW_CONFLICTS; |
| opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; |
| opts.notify_cb = test_checkout_notify_cb; |
| opts.notify_payload = &data; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| } |
| |
| static int dont_notify_cb( |
| git_checkout_notify_t why, |
| const char *path, |
| const git_diff_file *baseline, |
| const git_diff_file *target, |
| const git_diff_file *workdir, |
| void *payload) |
| { |
| GIT_UNUSED(why); |
| GIT_UNUSED(path); |
| GIT_UNUSED(baseline); |
| GIT_UNUSED(target); |
| GIT_UNUSED(workdir); |
| GIT_UNUSED(payload); |
| |
| cl_assert(false); |
| |
| return 0; |
| } |
| |
| void test_checkout_index__wont_notify_of_expected_line_ending_changes(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_git_pass(p_unlink("./testrepo/.gitattributes")); |
| cl_repo_set_bool(g_repo, "core.autocrlf", true); |
| |
| cl_git_mkfile("./testrepo/new.txt", "my new file\r\n"); |
| |
| opts.checkout_strategy = |
| GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING | |
| GIT_CHECKOUT_ALLOW_CONFLICTS; |
| opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; |
| opts.notify_cb = dont_notify_cb; |
| opts.notify_payload = NULL; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| } |
| |
| static void checkout_progress_counter( |
| const char *path, size_t cur, size_t tot, void *payload) |
| { |
| GIT_UNUSED(path); GIT_UNUSED(cur); GIT_UNUSED(tot); |
| (*(int *)payload)++; |
| } |
| |
| void test_checkout_index__calls_progress_callback(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| int calls = 0; |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| opts.progress_cb = checkout_progress_counter; |
| opts.progress_payload = &calls; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| cl_assert(calls > 0); |
| } |
| |
| void test_checkout_index__can_overcome_name_clashes(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| git_index *index; |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| git_index_clear(index); |
| |
| cl_git_mkfile("./testrepo/path0", "content\r\n"); |
| cl_git_pass(p_mkdir("./testrepo/path1", 0777)); |
| cl_git_mkfile("./testrepo/path1/file1", "content\r\n"); |
| |
| cl_git_pass(git_index_add_bypath(index, "path0")); |
| cl_git_pass(git_index_add_bypath(index, "path1/file1")); |
| |
| cl_git_pass(p_unlink("./testrepo/path0")); |
| cl_git_pass(git_futils_rmdir_r( |
| "./testrepo/path1", NULL, GIT_RMDIR_REMOVE_FILES)); |
| |
| cl_git_mkfile("./testrepo/path1", "content\r\n"); |
| cl_git_pass(p_mkdir("./testrepo/path0", 0777)); |
| cl_git_mkfile("./testrepo/path0/file0", "content\r\n"); |
| |
| cl_assert(git_path_isfile("./testrepo/path1")); |
| cl_assert(git_path_isfile("./testrepo/path0/file0")); |
| |
| opts.checkout_strategy = |
| GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING | |
| GIT_CHECKOUT_ALLOW_CONFLICTS; |
| cl_git_pass(git_checkout_index(g_repo, index, &opts)); |
| |
| cl_assert(git_path_isfile("./testrepo/path1")); |
| cl_assert(git_path_isfile("./testrepo/path0/file0")); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_FORCE; |
| cl_git_pass(git_checkout_index(g_repo, index, &opts)); |
| |
| cl_assert(git_path_isfile("./testrepo/path0")); |
| cl_assert(git_path_isfile("./testrepo/path1/file1")); |
| |
| git_index_free(index); |
| } |
| |
| void test_checkout_index__validates_struct_version(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| const git_error *err; |
| |
| opts.version = 1024; |
| cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); |
| |
| err = giterr_last(); |
| cl_assert_equal_i(err->klass, GITERR_INVALID); |
| |
| opts.version = 0; |
| giterr_clear(); |
| cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); |
| |
| err = giterr_last(); |
| cl_assert_equal_i(err->klass, GITERR_INVALID); |
| } |
| |
| void test_checkout_index__can_update_prefixed_files(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); |
| |
| cl_git_mkfile("./testrepo/READ", "content\n"); |
| cl_git_mkfile("./testrepo/README.after", "content\n"); |
| cl_git_pass(p_mkdir("./testrepo/branch_file", 0777)); |
| cl_git_pass(p_mkdir("./testrepo/branch_file/contained_dir", 0777)); |
| cl_git_mkfile("./testrepo/branch_file/contained_file", "content\n"); |
| cl_git_pass(p_mkdir("./testrepo/branch_file.txt.after", 0777)); |
| |
| opts.checkout_strategy = |
| GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING | |
| GIT_CHECKOUT_REMOVE_UNTRACKED; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| /* remove untracked will remove the .gitattributes file before the blobs |
| * were created, so they will have had crlf filtering applied on Windows |
| */ |
| check_file_contents_nocr("./testrepo/README", "hey there\n"); |
| check_file_contents_nocr("./testrepo/branch_file.txt", "hi\nbye!\n"); |
| check_file_contents_nocr("./testrepo/new.txt", "my new file\n"); |
| |
| cl_assert(!git_path_exists("testrepo/READ")); |
| cl_assert(!git_path_exists("testrepo/README.after")); |
| cl_assert(!git_path_exists("testrepo/branch_file")); |
| cl_assert(!git_path_exists("testrepo/branch_file.txt.after")); |
| } |
| |
| void test_checkout_index__can_checkout_a_newly_initialized_repository(void) |
| { |
| test_checkout_index__cleanup(); |
| |
| g_repo = cl_git_sandbox_init("empty_standard_repo"); |
| cl_git_remove_placeholders(git_repository_path(g_repo), "dummy-marker.txt"); |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, NULL)); |
| } |
| |
| void test_checkout_index__issue_1397(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| test_checkout_index__cleanup(); |
| |
| g_repo = cl_git_sandbox_init("issue_1397"); |
| |
| cl_repo_set_bool(g_repo, "core.autocrlf", true); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_FORCE; |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| check_file_contents("./issue_1397/crlf_file.txt", "first line\r\nsecond line\r\nboth with crlf"); |
| } |
| |
| void test_checkout_index__target_directory(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| checkout_counts cts; |
| memset(&cts, 0, sizeof(cts)); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING; |
| opts.target_directory = "alternative"; |
| cl_assert(!git_path_isdir("alternative")); |
| |
| opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; |
| opts.notify_cb = checkout_count_callback; |
| opts.notify_payload = &cts; |
| |
| /* create some files that *would* conflict if we were using the wd */ |
| cl_git_mkfile("testrepo/README", "I'm in the way!\n"); |
| cl_git_mkfile("testrepo/new.txt", "my new file\n"); |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_assert_equal_i(0, cts.n_untracked); |
| cl_assert_equal_i(0, cts.n_ignored); |
| cl_assert_equal_i(4, cts.n_updates); |
| |
| check_file_contents("./alternative/README", "hey there\n"); |
| check_file_contents("./alternative/branch_file.txt", "hi\nbye!\n"); |
| check_file_contents("./alternative/new.txt", "my new file\n"); |
| |
| cl_git_pass(git_futils_rmdir_r( |
| "alternative", NULL, GIT_RMDIR_REMOVE_FILES)); |
| } |
| |
| void test_checkout_index__target_directory_from_bare(void) |
| { |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| git_index *index; |
| git_object *head = NULL; |
| checkout_counts cts; |
| memset(&cts, 0, sizeof(cts)); |
| |
| test_checkout_index__cleanup(); |
| |
| g_repo = cl_git_sandbox_init("testrepo.git"); |
| cl_assert(git_repository_is_bare(g_repo)); |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| cl_git_pass(git_revparse_single(&head, g_repo, "HEAD^{tree}")); |
| cl_git_pass(git_index_read_tree(index, (const git_tree *)head)); |
| cl_git_pass(git_index_write(index)); |
| git_index_free(index); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | |
| GIT_CHECKOUT_RECREATE_MISSING; |
| |
| opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; |
| opts.notify_cb = checkout_count_callback; |
| opts.notify_payload = &cts; |
| |
| /* fail to checkout a bare repo */ |
| cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); |
| |
| opts.target_directory = "alternative"; |
| cl_assert(!git_path_isdir("alternative")); |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_assert_equal_i(0, cts.n_untracked); |
| cl_assert_equal_i(0, cts.n_ignored); |
| cl_assert_equal_i(3, cts.n_updates); |
| |
| /* files will have been filtered if needed, so strip CR */ |
| check_file_contents_nocr("./alternative/README", "hey there\n"); |
| check_file_contents_nocr("./alternative/branch_file.txt", "hi\nbye!\n"); |
| check_file_contents_nocr("./alternative/new.txt", "my new file\n"); |
| |
| cl_git_pass(git_futils_rmdir_r( |
| "alternative", NULL, GIT_RMDIR_REMOVE_FILES)); |
| |
| git_object_free(head); |
| } |
| |
| void test_checkout_index__can_get_repo_from_index(void) |
| { |
| git_index *index; |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); |
| cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); |
| |
| opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| |
| cl_git_pass(git_checkout_index(NULL, index, &opts)); |
| |
| check_file_contents("./testrepo/README", "hey there\n"); |
| check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n"); |
| check_file_contents("./testrepo/new.txt", "my new file\n"); |
| |
| git_index_free(index); |
| } |
| |
| static void add_conflict(git_index *index, const char *path) |
| { |
| git_index_entry entry; |
| |
| memset(&entry, 0, sizeof(git_index_entry)); |
| |
| entry.mode = 0100644; |
| entry.path = path; |
| |
| git_oid_fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46"); |
| GIT_IDXENTRY_STAGE_SET(&entry, 1); |
| cl_git_pass(git_index_add(index, &entry)); |
| |
| git_oid_fromstr(&entry.id, "4e886e602529caa9ab11d71f86634bd1b6e0de10"); |
| GIT_IDXENTRY_STAGE_SET(&entry, 2); |
| cl_git_pass(git_index_add(index, &entry)); |
| |
| git_oid_fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863"); |
| GIT_IDXENTRY_STAGE_SET(&entry, 3); |
| cl_git_pass(git_index_add(index, &entry)); |
| } |
| |
| void test_checkout_index__writes_conflict_file(void) |
| { |
| git_index *index; |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| git_buf conflicting_buf = GIT_BUF_INIT; |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| |
| add_conflict(index, "conflicting.txt"); |
| cl_git_pass(git_index_write(index)); |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt")); |
| cl_assert(strcmp(conflicting_buf.ptr, |
| "<<<<<<< ours\n" |
| "this file is changed in master and branch\n" |
| "=======\n" |
| "this file is changed in branch and master\n" |
| ">>>>>>> theirs\n") == 0); |
| git_buf_free(&conflicting_buf); |
| |
| git_index_free(index); |
| } |
| |
| void test_checkout_index__adding_conflict_removes_stage_0(void) |
| { |
| git_index *new_index, *index; |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| |
| cl_git_pass(git_index_new(&new_index)); |
| |
| add_conflict(new_index, "new.txt"); |
| cl_git_pass(git_checkout_index(g_repo, new_index, &opts)); |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| |
| cl_assert(git_index_get_bypath(index, "new.txt", 0) == NULL); |
| cl_assert(git_index_get_bypath(index, "new.txt", 1) != NULL); |
| cl_assert(git_index_get_bypath(index, "new.txt", 2) != NULL); |
| cl_assert(git_index_get_bypath(index, "new.txt", 3) != NULL); |
| |
| git_index_free(index); |
| git_index_free(new_index); |
| } |
| |
| void test_checkout_index__conflicts_honor_coreautocrlf(void) |
| { |
| #ifdef GIT_WIN32 |
| git_index *index; |
| git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; |
| git_buf conflicting_buf = GIT_BUF_INIT; |
| |
| cl_git_pass(p_unlink("./testrepo/.gitattributes")); |
| cl_repo_set_bool(g_repo, "core.autocrlf", true); |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| |
| add_conflict(index, "conflicting.txt"); |
| cl_git_pass(git_index_write(index)); |
| |
| cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); |
| |
| cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt")); |
| cl_assert(strcmp(conflicting_buf.ptr, |
| "<<<<<<< ours\r\n" |
| "this file is changed in master and branch\r\n" |
| "=======\r\n" |
| "this file is changed in branch and master\r\n" |
| ">>>>>>> theirs\r\n") == 0); |
| git_buf_free(&conflicting_buf); |
| |
| git_index_free(index); |
| #endif |
| } |