1 #include "clar_libgit2.h"
2 #include "checkout_helpers.h"
4 #include "git2/checkout.h"
6 #include "repository.h"
8 #include "repo/repo_helpers.h"
10 static git_repository
*g_repo
;
11 static git_str g_global_path
= GIT_STR_INIT
;
13 void test_checkout_index__initialize(void)
17 g_repo
= cl_git_sandbox_init("testrepo");
19 cl_git_pass(git_repository_head_tree(&tree
, g_repo
));
21 reset_index_to_treeish((git_object
*)tree
);
25 "./testrepo/.gitattributes",
28 git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH
, GIT_CONFIG_LEVEL_GLOBAL
,
32 void test_checkout_index__cleanup(void)
34 git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH
, GIT_CONFIG_LEVEL_GLOBAL
,
36 git_str_dispose(&g_global_path
);
38 cl_git_sandbox_cleanup();
40 /* try to remove directories created by tests */
41 cl_fixture_cleanup("alternative");
42 cl_fixture_cleanup("symlink");
43 cl_fixture_cleanup("symlink.git");
44 cl_fixture_cleanup("tmp_global_path");
47 void test_checkout_index__cannot_checkout_a_bare_repository(void)
49 cl_git_sandbox_cleanup();
50 g_repo
= cl_git_sandbox_init("testrepo.git");
52 cl_git_fail(git_checkout_index(g_repo
, NULL
, NULL
));
55 void test_checkout_index__can_create_missing_files(void)
57 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
59 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/README"));
60 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt"));
61 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt"));
63 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
65 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
67 check_file_contents("./testrepo/README", "hey there\n");
68 check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
69 check_file_contents("./testrepo/new.txt", "my new file\n");
72 void test_checkout_index__can_remove_untracked_files(void)
74 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
76 git_futils_mkdir("./testrepo/dir/subdir/subsubdir", 0755, GIT_MKDIR_PATH
);
77 cl_git_mkfile("./testrepo/dir/one", "one\n");
78 cl_git_mkfile("./testrepo/dir/subdir/two", "two\n");
80 cl_assert_equal_i(true, git_fs_path_isdir("./testrepo/dir/subdir/subsubdir"));
82 opts
.checkout_strategy
=
84 GIT_CHECKOUT_RECREATE_MISSING
|
85 GIT_CHECKOUT_REMOVE_UNTRACKED
;
87 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
89 cl_assert_equal_i(false, git_fs_path_isdir("./testrepo/dir"));
92 void test_checkout_index__can_disable_pathspec_match(void)
94 char *files_to_checkout
[] = { "test10.txt", "test11.txt"};
95 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
99 /* reset to beginning of history (i.e. just a README file) */
100 opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
| GIT_CHECKOUT_REMOVE_UNTRACKED
;
102 cl_git_pass(git_revparse_single(&objects
, g_repo
, "8496071c1b46c854b31185ea97743be6a8774479"));
103 cl_git_pass(git_checkout_tree(g_repo
, objects
, &opts
));
104 cl_git_pass(git_repository_set_head_detached(g_repo
, git_object_id(objects
)));
105 git_object_free(objects
);
107 cl_git_pass(git_repository_index(&index
, g_repo
));
109 /* We create 4 files and commit them */
110 cl_git_mkfile("testrepo/test9.txt", "original\n");
111 cl_git_mkfile("testrepo/test10.txt", "original\n");
112 cl_git_mkfile("testrepo/test11.txt", "original\n");
113 cl_git_mkfile("testrepo/test12.txt", "original\n");
115 cl_git_pass(git_index_add_bypath(index
, "test9.txt"));
116 cl_git_pass(git_index_add_bypath(index
, "test10.txt"));
117 cl_git_pass(git_index_add_bypath(index
, "test11.txt"));
118 cl_git_pass(git_index_add_bypath(index
, "test12.txt"));
119 cl_git_pass(git_index_write(index
));
121 cl_repo_commit_from_index(NULL
, g_repo
, NULL
, 0, "commit our test files");
123 /* We modify the content of all 4 of our files */
124 cl_git_rewritefile("testrepo/test9.txt", "modified\n");
125 cl_git_rewritefile("testrepo/test10.txt", "modified\n");
126 cl_git_rewritefile("testrepo/test11.txt", "modified\n");
127 cl_git_rewritefile("testrepo/test12.txt", "modified\n");
129 /* We checkout only test10.txt and test11.txt */
130 opts
.checkout_strategy
=
132 GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
;
133 opts
.paths
.strings
= files_to_checkout
;
134 opts
.paths
.count
= ARRAY_SIZE(files_to_checkout
);
135 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
137 /* The only files that have been reverted to their original content
138 should be test10.txt and test11.txt */
139 check_file_contents("testrepo/test9.txt", "modified\n");
140 check_file_contents("testrepo/test10.txt", "original\n");
141 check_file_contents("testrepo/test11.txt", "original\n");
142 check_file_contents("testrepo/test12.txt", "modified\n");
144 git_index_free(index
);
147 void test_checkout_index__honor_the_specified_pathspecs(void)
149 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
150 char *entries
[] = { "*.txt" };
152 opts
.paths
.strings
= entries
;
153 opts
.paths
.count
= 1;
155 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/README"));
156 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt"));
157 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt"));
159 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
161 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
163 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/README"));
164 check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
165 check_file_contents("./testrepo/new.txt", "my new file\n");
168 void test_checkout_index__honor_the_gitattributes_directives(void)
170 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
171 const char *attributes
=
172 "branch_file.txt text eol=crlf\n"
173 "new.txt text eol=lf\n";
175 cl_git_mkfile("./testrepo/.gitattributes", attributes
);
176 cl_repo_set_bool(g_repo
, "core.autocrlf", false);
178 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
180 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
182 check_file_contents("./testrepo/README", "hey there\n");
183 check_file_contents("./testrepo/new.txt", "my new file\n");
184 check_file_contents("./testrepo/branch_file.txt", "hi\r\nbye!\r\n");
187 void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void)
190 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
191 const char *expected_readme_text
= "hey there\r\n";
193 cl_git_pass(p_unlink("./testrepo/.gitattributes"));
194 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
196 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
198 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
200 check_file_contents("./testrepo/README", expected_readme_text
);
204 static void populate_symlink_workdir(void)
206 git_str path
= GIT_STR_INIT
;
207 git_repository
*repo
;
211 const char *url
= git_repository_path(g_repo
);
213 cl_git_pass(git_str_joinpath(&path
, clar_sandbox_path(), "symlink.git"));
214 cl_git_pass(git_repository_init(&repo
, path
.ptr
, true));
215 cl_git_pass(git_repository_set_workdir(repo
, "symlink", 1));
217 /* Delete the `origin` repo (if it exists) so we can recreate it. */
218 git_remote_delete(repo
, GIT_REMOTE_ORIGIN
);
220 cl_git_pass(git_remote_create(&origin
, repo
, GIT_REMOTE_ORIGIN
, url
));
221 cl_git_pass(git_remote_fetch(origin
, NULL
, NULL
, NULL
));
222 git_remote_free(origin
);
224 cl_git_pass(git_revparse_single(&target
, repo
, "remotes/origin/master"));
225 cl_git_pass(git_reset(repo
, target
, GIT_RESET_HARD
, NULL
));
227 git_object_free(target
);
228 git_repository_free(repo
);
229 git_str_dispose(&path
);
232 void test_checkout_index__honor_coresymlinks_default_true(void)
234 char link_data
[GIT_PATH_MAX
];
235 int link_size
= GIT_PATH_MAX
;
237 cl_must_pass(p_mkdir("symlink", 0777));
239 if (!git_fs_path_supports_symlinks("symlink/test"))
244 * Windows explicitly requires the global configuration to have
245 * core.symlinks=true in addition to actual filesystem support.
247 create_tmp_global_config("tmp_global_path", "core.symlinks", "true");
250 populate_symlink_workdir();
252 link_size
= p_readlink("./symlink/link_to_new.txt", link_data
, link_size
);
253 cl_assert(link_size
>= 0);
255 link_data
[link_size
] = '\0';
256 cl_assert_equal_i(link_size
, strlen("new.txt"));
257 cl_assert_equal_s(link_data
, "new.txt");
258 check_file_contents("./symlink/link_to_new.txt", "my new file\n");
261 void test_checkout_index__honor_coresymlinks_default_false(void)
263 cl_must_pass(p_mkdir("symlink", 0777));
267 * This test is largely for Windows platforms to ensure that
268 * we respect an unset core.symlinks even when the platform
269 * supports symlinks. Bail entirely on POSIX platforms that
270 * do support symlinks.
272 if (git_fs_path_supports_symlinks("symlink/test"))
276 populate_symlink_workdir();
277 check_file_contents("./symlink/link_to_new.txt", "new.txt");
280 void test_checkout_index__coresymlinks_set_to_true_fails_when_unsupported(void)
282 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
284 if (git_fs_path_supports_symlinks("testrepo/test")) {
288 cl_repo_set_bool(g_repo
, "core.symlinks", true);
290 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
291 cl_git_fail(git_checkout_index(g_repo
, NULL
, &opts
));
294 void test_checkout_index__honor_coresymlinks_setting_set_to_true(void)
296 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
297 char link_data
[GIT_PATH_MAX
];
298 size_t link_size
= GIT_PATH_MAX
;
300 if (!git_fs_path_supports_symlinks("testrepo/test")) {
304 cl_repo_set_bool(g_repo
, "core.symlinks", true);
306 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
308 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
310 link_size
= p_readlink("./testrepo/link_to_new.txt", link_data
, link_size
);
311 link_data
[link_size
] = '\0';
312 cl_assert_equal_i(link_size
, strlen("new.txt"));
313 cl_assert_equal_s(link_data
, "new.txt");
314 check_file_contents("./testrepo/link_to_new.txt", "my new file\n");
317 void test_checkout_index__honor_coresymlinks_setting_set_to_false(void)
319 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
321 cl_repo_set_bool(g_repo
, "core.symlinks", false);
323 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
325 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
327 check_file_contents("./testrepo/link_to_new.txt", "new.txt");
330 void test_checkout_index__donot_overwrite_modified_file_by_default(void)
332 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
334 cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
336 /* set this up to not return an error code on conflicts, but it
337 * still will not have permission to overwrite anything...
339 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_ALLOW_CONFLICTS
;
341 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
343 check_file_contents("./testrepo/new.txt", "This isn't what's stored!");
346 void test_checkout_index__can_overwrite_modified_file(void)
348 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
350 cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
352 opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
354 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
356 check_file_contents("./testrepo/new.txt", "my new file\n");
359 void test_checkout_index__options_disable_filters(void)
361 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
363 cl_git_mkfile("./testrepo/.gitattributes", "*.txt text eol=crlf\n");
365 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
366 opts
.disable_filters
= false;
368 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
370 check_file_contents("./testrepo/new.txt", "my new file\r\n");
372 p_unlink("./testrepo/new.txt");
374 opts
.disable_filters
= true;
375 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
377 check_file_contents("./testrepo/new.txt", "my new file\n");
380 void test_checkout_index__options_dir_modes(void)
382 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
388 if (!cl_is_chmod_supported())
391 cl_git_pass(git_reference_name_to_id(&oid
, g_repo
, "refs/heads/dir"));
392 cl_git_pass(git_commit_lookup(&commit
, g_repo
, &oid
));
394 reset_index_to_treeish((git_object
*)commit
);
396 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
397 opts
.dir_mode
= 0701;
399 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
401 /* umask will influence actual directory creation mode */
402 (void)p_umask(um
= p_umask(022));
404 cl_git_pass(p_stat("./testrepo/a", &st
));
405 /* Haiku & Hurd use other mode bits, so we must mask them out */
406 cl_assert_equal_i_fmt(st
.st_mode
& (S_IFMT
| 07777), (GIT_FILEMODE_TREE
| 0701) & ~um
, "%07o");
408 /* File-mode test, since we're on the 'dir' branch */
409 cl_git_pass(p_stat("./testrepo/a/b.txt", &st
));
410 cl_assert_equal_i_fmt(st
.st_mode
& (S_IFMT
| 07777), GIT_FILEMODE_BLOB_EXECUTABLE
& ~um
, "%07o");
412 git_commit_free(commit
);
415 void test_checkout_index__options_override_file_modes(void)
417 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
420 if (!cl_is_chmod_supported())
423 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
424 opts
.file_mode
= 0700;
426 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
428 cl_git_pass(p_stat("./testrepo/new.txt", &st
));
429 cl_assert_equal_i_fmt(st
.st_mode
& GIT_MODE_PERMS_MASK
, 0700, "%07o");
432 void test_checkout_index__options_open_flags(void)
434 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
436 cl_git_mkfile("./testrepo/new.txt", "hi\n");
438 opts
.checkout_strategy
=
439 GIT_CHECKOUT_FORCE
| GIT_CHECKOUT_DONT_REMOVE_EXISTING
;
440 opts
.file_open_flags
= O_CREAT
| O_RDWR
| O_APPEND
;
442 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
444 check_file_contents("./testrepo/new.txt", "hi\nmy new file\n");
452 static int test_checkout_notify_cb(
453 git_checkout_notify_t why
,
455 const git_diff_file
*baseline
,
456 const git_diff_file
*target
,
457 const git_diff_file
*workdir
,
460 struct notify_data
*expectations
= (struct notify_data
*)payload
;
464 cl_assert_equal_i(GIT_CHECKOUT_NOTIFY_CONFLICT
, why
);
465 cl_assert_equal_s(expectations
->file
, path
);
466 cl_assert_equal_i(0, git_oid_streq(&baseline
->id
, expectations
->sha
));
467 cl_assert_equal_i(0, git_oid_streq(&target
->id
, expectations
->sha
));
472 void test_checkout_index__can_notify_of_skipped_files(void)
474 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
475 struct notify_data data
;
477 cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
481 * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README
482 * 100644 blob 3697d64be941a53d4ae8f6a271e4e3fa56b022cc branch_file.txt
483 * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt
485 data
.file
= "new.txt";
486 data
.sha
= "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd";
488 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
|
489 GIT_CHECKOUT_RECREATE_MISSING
|
490 GIT_CHECKOUT_ALLOW_CONFLICTS
;
491 opts
.notify_flags
= GIT_CHECKOUT_NOTIFY_CONFLICT
;
492 opts
.notify_cb
= test_checkout_notify_cb
;
493 opts
.notify_payload
= &data
;
495 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
498 static int dont_notify_cb(
499 git_checkout_notify_t why
,
501 const git_diff_file
*baseline
,
502 const git_diff_file
*target
,
503 const git_diff_file
*workdir
,
508 GIT_UNUSED(baseline
);
518 void test_checkout_index__wont_notify_of_expected_line_ending_changes(void)
520 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
522 cl_git_pass(p_unlink("./testrepo/.gitattributes"));
523 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
525 cl_git_mkfile("./testrepo/new.txt", "my new file\r\n");
527 opts
.checkout_strategy
=
529 GIT_CHECKOUT_RECREATE_MISSING
|
530 GIT_CHECKOUT_ALLOW_CONFLICTS
;
531 opts
.notify_flags
= GIT_CHECKOUT_NOTIFY_CONFLICT
;
532 opts
.notify_cb
= dont_notify_cb
;
533 opts
.notify_payload
= NULL
;
535 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
538 static void checkout_progress_counter(
539 const char *path
, size_t cur
, size_t tot
, void *payload
)
541 GIT_UNUSED(path
); GIT_UNUSED(cur
); GIT_UNUSED(tot
);
545 void test_checkout_index__calls_progress_callback(void)
547 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
550 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
551 opts
.progress_cb
= checkout_progress_counter
;
552 opts
.progress_payload
= &calls
;
554 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
555 cl_assert(calls
> 0);
558 void test_checkout_index__can_overcome_name_clashes(void)
560 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
563 cl_git_pass(git_repository_index(&index
, g_repo
));
564 git_index_clear(index
);
566 cl_git_mkfile("./testrepo/path0", "content\r\n");
567 cl_git_pass(p_mkdir("./testrepo/path1", 0777));
568 cl_git_mkfile("./testrepo/path1/file1", "content\r\n");
570 cl_git_pass(git_index_add_bypath(index
, "path0"));
571 cl_git_pass(git_index_add_bypath(index
, "path1/file1"));
573 cl_git_pass(p_unlink("./testrepo/path0"));
574 cl_git_pass(git_futils_rmdir_r(
575 "./testrepo/path1", NULL
, GIT_RMDIR_REMOVE_FILES
));
577 cl_git_mkfile("./testrepo/path1", "content\r\n");
578 cl_git_pass(p_mkdir("./testrepo/path0", 0777));
579 cl_git_mkfile("./testrepo/path0/file0", "content\r\n");
581 cl_assert(git_fs_path_isfile("./testrepo/path1"));
582 cl_assert(git_fs_path_isfile("./testrepo/path0/file0"));
584 opts
.checkout_strategy
=
586 GIT_CHECKOUT_RECREATE_MISSING
|
587 GIT_CHECKOUT_ALLOW_CONFLICTS
;
588 cl_git_pass(git_checkout_index(g_repo
, index
, &opts
));
590 cl_assert(git_fs_path_isfile("./testrepo/path1"));
591 cl_assert(git_fs_path_isfile("./testrepo/path0/file0"));
593 opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
594 cl_git_pass(git_checkout_index(g_repo
, index
, &opts
));
596 cl_assert(git_fs_path_isfile("./testrepo/path0"));
597 cl_assert(git_fs_path_isfile("./testrepo/path1/file1"));
599 git_index_free(index
);
602 void test_checkout_index__validates_struct_version(void)
604 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
605 const git_error
*err
;
608 cl_git_fail(git_checkout_index(g_repo
, NULL
, &opts
));
610 err
= git_error_last();
611 cl_assert_equal_i(err
->klass
, GIT_ERROR_INVALID
);
615 cl_git_fail(git_checkout_index(g_repo
, NULL
, &opts
));
617 err
= git_error_last();
618 cl_assert_equal_i(err
->klass
, GIT_ERROR_INVALID
);
621 void test_checkout_index__can_update_prefixed_files(void)
623 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
625 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/README"));
626 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt"));
627 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt"));
629 cl_git_mkfile("./testrepo/READ", "content\n");
630 cl_git_mkfile("./testrepo/README.after", "content\n");
631 cl_git_pass(p_mkdir("./testrepo/branch_file", 0777));
632 cl_git_pass(p_mkdir("./testrepo/branch_file/contained_dir", 0777));
633 cl_git_mkfile("./testrepo/branch_file/contained_file", "content\n");
634 cl_git_pass(p_mkdir("./testrepo/branch_file.txt.after", 0777));
636 opts
.checkout_strategy
=
638 GIT_CHECKOUT_RECREATE_MISSING
|
639 GIT_CHECKOUT_REMOVE_UNTRACKED
;
641 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
643 /* remove untracked will remove the .gitattributes file before the blobs
644 * were created, so they will have had crlf filtering applied on Windows
646 check_file_contents_nocr("./testrepo/README", "hey there\n");
647 check_file_contents_nocr("./testrepo/branch_file.txt", "hi\nbye!\n");
648 check_file_contents_nocr("./testrepo/new.txt", "my new file\n");
650 cl_assert(!git_fs_path_exists("testrepo/READ"));
651 cl_assert(!git_fs_path_exists("testrepo/README.after"));
652 cl_assert(!git_fs_path_exists("testrepo/branch_file"));
653 cl_assert(!git_fs_path_exists("testrepo/branch_file.txt.after"));
656 void test_checkout_index__can_checkout_a_newly_initialized_repository(void)
658 cl_git_sandbox_cleanup();
659 g_repo
= cl_git_sandbox_init("empty_standard_repo");
661 cl_git_remove_placeholders(git_repository_path(g_repo
), "dummy-marker.txt");
663 cl_git_pass(git_checkout_index(g_repo
, NULL
, NULL
));
666 void test_checkout_index__issue_1397(void)
668 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
670 cl_git_sandbox_cleanup();
671 g_repo
= cl_git_sandbox_init("issue_1397");
673 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
675 opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
677 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
679 check_file_contents("./issue_1397/crlf_file.txt", "first line\r\nsecond line\r\nboth with crlf");
682 void test_checkout_index__target_directory(void)
684 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
686 memset(&cts
, 0, sizeof(cts
));
688 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
|
689 GIT_CHECKOUT_RECREATE_MISSING
;
690 opts
.target_directory
= "alternative";
691 cl_assert(!git_fs_path_isdir("alternative"));
693 opts
.notify_flags
= GIT_CHECKOUT_NOTIFY_ALL
;
694 opts
.notify_cb
= checkout_count_callback
;
695 opts
.notify_payload
= &cts
;
697 /* create some files that *would* conflict if we were using the wd */
698 cl_git_mkfile("testrepo/README", "I'm in the way!\n");
699 cl_git_mkfile("testrepo/new.txt", "my new file\n");
701 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
703 cl_assert_equal_i(0, cts
.n_untracked
);
704 cl_assert_equal_i(0, cts
.n_ignored
);
705 cl_assert_equal_i(4, cts
.n_updates
);
707 check_file_contents("./alternative/README", "hey there\n");
708 check_file_contents("./alternative/branch_file.txt", "hi\nbye!\n");
709 check_file_contents("./alternative/new.txt", "my new file\n");
711 cl_git_pass(git_futils_rmdir_r(
712 "alternative", NULL
, GIT_RMDIR_REMOVE_FILES
));
715 void test_checkout_index__target_directory_from_bare(void)
717 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
719 git_object
*head
= NULL
;
721 memset(&cts
, 0, sizeof(cts
));
723 cl_git_sandbox_cleanup();
724 g_repo
= cl_git_sandbox_init("testrepo.git");
725 cl_assert(git_repository_is_bare(g_repo
));
727 cl_git_pass(git_repository_index(&index
, g_repo
));
728 cl_git_pass(git_revparse_single(&head
, g_repo
, "HEAD^{tree}"));
729 cl_git_pass(git_index_read_tree(index
, (const git_tree
*)head
));
730 cl_git_pass(git_index_write(index
));
731 git_index_free(index
);
733 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
|
734 GIT_CHECKOUT_RECREATE_MISSING
;
736 opts
.notify_flags
= GIT_CHECKOUT_NOTIFY_ALL
;
737 opts
.notify_cb
= checkout_count_callback
;
738 opts
.notify_payload
= &cts
;
740 /* fail to checkout a bare repo */
741 cl_git_fail(git_checkout_index(g_repo
, NULL
, &opts
));
743 opts
.target_directory
= "alternative";
744 cl_assert(!git_fs_path_isdir("alternative"));
746 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
748 cl_assert_equal_i(0, cts
.n_untracked
);
749 cl_assert_equal_i(0, cts
.n_ignored
);
750 cl_assert_equal_i(3, cts
.n_updates
);
752 /* files will have been filtered if needed, so strip CR */
753 check_file_contents_nocr("./alternative/README", "hey there\n");
754 check_file_contents_nocr("./alternative/branch_file.txt", "hi\nbye!\n");
755 check_file_contents_nocr("./alternative/new.txt", "my new file\n");
757 cl_git_pass(git_futils_rmdir_r(
758 "alternative", NULL
, GIT_RMDIR_REMOVE_FILES
));
760 git_object_free(head
);
763 void test_checkout_index__can_get_repo_from_index(void)
766 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
768 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/README"));
769 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/branch_file.txt"));
770 cl_assert_equal_i(false, git_fs_path_isfile("./testrepo/new.txt"));
772 opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_RECREATE_MISSING
;
774 cl_git_pass(git_repository_index(&index
, g_repo
));
776 cl_git_pass(git_checkout_index(NULL
, index
, &opts
));
778 check_file_contents("./testrepo/README", "hey there\n");
779 check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
780 check_file_contents("./testrepo/new.txt", "my new file\n");
782 git_index_free(index
);
785 static void add_conflict(git_index
*index
, const char *path
)
787 git_index_entry entry
;
789 memset(&entry
, 0, sizeof(git_index_entry
));
791 entry
.mode
= 0100644;
794 git_oid_fromstr(&entry
.id
, "d427e0b2e138501a3d15cc376077a3631e15bd46");
795 GIT_INDEX_ENTRY_STAGE_SET(&entry
, 1);
796 cl_git_pass(git_index_add(index
, &entry
));
798 git_oid_fromstr(&entry
.id
, "4e886e602529caa9ab11d71f86634bd1b6e0de10");
799 GIT_INDEX_ENTRY_STAGE_SET(&entry
, 2);
800 cl_git_pass(git_index_add(index
, &entry
));
802 git_oid_fromstr(&entry
.id
, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
803 GIT_INDEX_ENTRY_STAGE_SET(&entry
, 3);
804 cl_git_pass(git_index_add(index
, &entry
));
807 void test_checkout_index__writes_conflict_file(void)
810 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
811 git_str conflicting_buf
= GIT_STR_INIT
;
813 cl_git_pass(git_repository_index(&index
, g_repo
));
815 add_conflict(index
, "conflicting.txt");
816 cl_git_pass(git_index_write(index
));
818 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
820 cl_git_pass(git_futils_readbuffer(&conflicting_buf
, "testrepo/conflicting.txt"));
821 cl_assert(strcmp(conflicting_buf
.ptr
,
823 "this file is changed in master and branch\n"
825 "this file is changed in branch and master\n"
826 ">>>>>>> theirs\n") == 0);
827 git_str_dispose(&conflicting_buf
);
829 git_index_free(index
);
832 void test_checkout_index__adding_conflict_removes_stage_0(void)
834 git_index
*new_index
, *index
;
835 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
837 cl_git_pass(git_index_new(&new_index
));
839 add_conflict(new_index
, "new.txt");
840 cl_git_pass(git_checkout_index(g_repo
, new_index
, &opts
));
842 cl_git_pass(git_repository_index(&index
, g_repo
));
844 cl_assert(git_index_get_bypath(index
, "new.txt", 0) == NULL
);
845 cl_assert(git_index_get_bypath(index
, "new.txt", 1) != NULL
);
846 cl_assert(git_index_get_bypath(index
, "new.txt", 2) != NULL
);
847 cl_assert(git_index_get_bypath(index
, "new.txt", 3) != NULL
);
849 git_index_free(index
);
850 git_index_free(new_index
);
853 void test_checkout_index__conflicts_honor_coreautocrlf(void)
857 git_checkout_options opts
= GIT_CHECKOUT_OPTIONS_INIT
;
858 git_str conflicting_buf
= GIT_STR_INIT
;
860 cl_git_pass(p_unlink("./testrepo/.gitattributes"));
861 cl_repo_set_bool(g_repo
, "core.autocrlf", true);
863 cl_git_pass(git_repository_index(&index
, g_repo
));
865 add_conflict(index
, "conflicting.txt");
866 cl_git_pass(git_index_write(index
));
868 cl_git_pass(git_checkout_index(g_repo
, NULL
, &opts
));
870 cl_git_pass(git_futils_readbuffer(&conflicting_buf
, "testrepo/conflicting.txt"));
871 cl_assert(strcmp(conflicting_buf
.ptr
,
873 "this file is changed in master and branch\r\n"
875 "this file is changed in branch and master\r\n"
876 ">>>>>>> theirs\r\n") == 0);
877 git_str_dispose(&conflicting_buf
);
879 git_index_free(index
);