]> git.proxmox.com Git - libgit2.git/blob - tests/checkout/index.c
Merge pull request #2654 from linquize/missing-obj
[libgit2.git] / tests / checkout / index.c
1 #include "clar_libgit2.h"
2 #include "checkout_helpers.h"
3
4 #include "git2/checkout.h"
5 #include "fileops.h"
6 #include "repository.h"
7
8 static git_repository *g_repo;
9
10 void test_checkout_index__initialize(void)
11 {
12 git_tree *tree;
13
14 g_repo = cl_git_sandbox_init("testrepo");
15
16 cl_git_pass(git_repository_head_tree(&tree, g_repo));
17
18 reset_index_to_treeish((git_object *)tree);
19 git_tree_free(tree);
20
21 cl_git_rewritefile(
22 "./testrepo/.gitattributes",
23 "* text eol=lf\n");
24 }
25
26 void test_checkout_index__cleanup(void)
27 {
28 cl_git_sandbox_cleanup();
29
30 /* try to remove alternative dir */
31 if (git_path_isdir("alternative"))
32 git_futils_rmdir_r("alternative", NULL, GIT_RMDIR_REMOVE_FILES);
33 }
34
35 void test_checkout_index__cannot_checkout_a_bare_repository(void)
36 {
37 test_checkout_index__cleanup();
38
39 g_repo = cl_git_sandbox_init("testrepo.git");
40
41 cl_git_fail(git_checkout_index(g_repo, NULL, NULL));
42 }
43
44 void test_checkout_index__can_create_missing_files(void)
45 {
46 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
47
48 cl_assert_equal_i(false, git_path_isfile("./testrepo/README"));
49 cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt"));
50 cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt"));
51
52 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
53
54 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
55
56 check_file_contents("./testrepo/README", "hey there\n");
57 check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
58 check_file_contents("./testrepo/new.txt", "my new file\n");
59 }
60
61 void test_checkout_index__can_remove_untracked_files(void)
62 {
63 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
64
65 git_futils_mkdir("./testrepo/dir/subdir/subsubdir", NULL, 0755, GIT_MKDIR_PATH);
66 cl_git_mkfile("./testrepo/dir/one", "one\n");
67 cl_git_mkfile("./testrepo/dir/subdir/two", "two\n");
68
69 cl_assert_equal_i(true, git_path_isdir("./testrepo/dir/subdir/subsubdir"));
70
71 opts.checkout_strategy =
72 GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_REMOVE_UNTRACKED;
73
74 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
75
76 cl_assert_equal_i(false, git_path_isdir("./testrepo/dir"));
77 }
78
79 void test_checkout_index__honor_the_specified_pathspecs(void)
80 {
81 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
82 char *entries[] = { "*.txt" };
83
84 opts.paths.strings = entries;
85 opts.paths.count = 1;
86
87 cl_assert_equal_i(false, git_path_isfile("./testrepo/README"));
88 cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt"));
89 cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt"));
90
91 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
92
93 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
94
95 cl_assert_equal_i(false, git_path_isfile("./testrepo/README"));
96 check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
97 check_file_contents("./testrepo/new.txt", "my new file\n");
98 }
99
100 void test_checkout_index__honor_the_gitattributes_directives(void)
101 {
102 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
103 const char *attributes =
104 "branch_file.txt text eol=crlf\n"
105 "new.txt text eol=lf\n";
106
107 cl_git_mkfile("./testrepo/.gitattributes", attributes);
108 cl_repo_set_bool(g_repo, "core.autocrlf", false);
109
110 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
111
112 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
113
114 check_file_contents("./testrepo/README", "hey there\n");
115 check_file_contents("./testrepo/new.txt", "my new file\n");
116 check_file_contents("./testrepo/branch_file.txt", "hi\r\nbye!\r\n");
117 }
118
119 void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void)
120 {
121 #ifdef GIT_WIN32
122 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
123 const char *expected_readme_text = "hey there\r\n";
124
125 cl_git_pass(p_unlink("./testrepo/.gitattributes"));
126 cl_repo_set_bool(g_repo, "core.autocrlf", true);
127
128 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
129
130 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
131
132 check_file_contents("./testrepo/README", expected_readme_text);
133 #endif
134 }
135
136 void test_checkout_index__honor_coresymlinks_setting_set_to_true(void)
137 {
138 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
139
140 cl_repo_set_bool(g_repo, "core.symlinks", true);
141
142 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
143
144 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
145
146 #ifdef GIT_WIN32
147 check_file_contents("./testrepo/link_to_new.txt", "new.txt");
148 #else
149 {
150 char link_data[1024];
151 size_t link_size = 1024;
152
153 link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size);
154 link_data[link_size] = '\0';
155 cl_assert_equal_i(link_size, strlen("new.txt"));
156 cl_assert_equal_s(link_data, "new.txt");
157 check_file_contents("./testrepo/link_to_new.txt", "my new file\n");
158 }
159 #endif
160 }
161
162 void test_checkout_index__honor_coresymlinks_setting_set_to_false(void)
163 {
164 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
165
166 cl_repo_set_bool(g_repo, "core.symlinks", false);
167
168 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
169
170 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
171
172 check_file_contents("./testrepo/link_to_new.txt", "new.txt");
173 }
174
175 void test_checkout_index__donot_overwrite_modified_file_by_default(void)
176 {
177 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
178
179 cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
180
181 /* set this up to not return an error code on conflicts, but it
182 * still will not have permission to overwrite anything...
183 */
184 opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
185
186 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
187
188 check_file_contents("./testrepo/new.txt", "This isn't what's stored!");
189 }
190
191 void test_checkout_index__can_overwrite_modified_file(void)
192 {
193 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
194
195 cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
196
197 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
198
199 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
200
201 check_file_contents("./testrepo/new.txt", "my new file\n");
202 }
203
204 void test_checkout_index__options_disable_filters(void)
205 {
206 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
207
208 cl_git_mkfile("./testrepo/.gitattributes", "*.txt text eol=crlf\n");
209
210 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
211 opts.disable_filters = false;
212
213 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
214
215 check_file_contents("./testrepo/new.txt", "my new file\r\n");
216
217 p_unlink("./testrepo/new.txt");
218
219 opts.disable_filters = true;
220 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
221
222 check_file_contents("./testrepo/new.txt", "my new file\n");
223 }
224
225 void test_checkout_index__options_dir_modes(void)
226 {
227 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
228 struct stat st;
229 git_oid oid;
230 git_commit *commit;
231 mode_t um;
232
233 if (!cl_is_chmod_supported())
234 return;
235
236 cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
237 cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
238
239 reset_index_to_treeish((git_object *)commit);
240
241 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
242 opts.dir_mode = 0701;
243
244 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
245
246 /* umask will influence actual directory creation mode */
247 (void)p_umask(um = p_umask(022));
248
249 cl_git_pass(p_stat("./testrepo/a", &st));
250 cl_assert_equal_i_fmt(st.st_mode, (GIT_FILEMODE_TREE | 0701) & ~um, "%07o");
251
252 /* File-mode test, since we're on the 'dir' branch */
253 cl_git_pass(p_stat("./testrepo/a/b.txt", &st));
254 cl_assert_equal_i_fmt(st.st_mode, GIT_FILEMODE_BLOB_EXECUTABLE, "%07o");
255
256 git_commit_free(commit);
257 }
258
259 void test_checkout_index__options_override_file_modes(void)
260 {
261 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
262 struct stat st;
263
264 if (!cl_is_chmod_supported())
265 return;
266
267 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
268 opts.file_mode = 0700;
269
270 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
271
272 cl_git_pass(p_stat("./testrepo/new.txt", &st));
273 cl_assert_equal_i_fmt(st.st_mode & GIT_MODE_PERMS_MASK, 0700, "%07o");
274 }
275
276 void test_checkout_index__options_open_flags(void)
277 {
278 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
279
280 cl_git_mkfile("./testrepo/new.txt", "hi\n");
281
282 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
283 opts.file_open_flags = O_CREAT | O_RDWR | O_APPEND;
284
285 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
286 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
287
288 check_file_contents("./testrepo/new.txt", "hi\nmy new file\n");
289 }
290
291 struct notify_data {
292 const char *file;
293 const char *sha;
294 };
295
296 static int test_checkout_notify_cb(
297 git_checkout_notify_t why,
298 const char *path,
299 const git_diff_file *baseline,
300 const git_diff_file *target,
301 const git_diff_file *workdir,
302 void *payload)
303 {
304 struct notify_data *expectations = (struct notify_data *)payload;
305
306 GIT_UNUSED(workdir);
307
308 cl_assert_equal_i(GIT_CHECKOUT_NOTIFY_CONFLICT, why);
309 cl_assert_equal_s(expectations->file, path);
310 cl_assert_equal_i(0, git_oid_streq(&baseline->id, expectations->sha));
311 cl_assert_equal_i(0, git_oid_streq(&target->id, expectations->sha));
312
313 return 0;
314 }
315
316 void test_checkout_index__can_notify_of_skipped_files(void)
317 {
318 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
319 struct notify_data data;
320
321 cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
322
323 /*
324 * $ git ls-tree HEAD
325 * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README
326 * 100644 blob 3697d64be941a53d4ae8f6a271e4e3fa56b022cc branch_file.txt
327 * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt
328 */
329 data.file = "new.txt";
330 data.sha = "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd";
331
332 opts.checkout_strategy =
333 GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_ALLOW_CONFLICTS;
334 opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT;
335 opts.notify_cb = test_checkout_notify_cb;
336 opts.notify_payload = &data;
337
338 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
339 }
340
341 static int dont_notify_cb(
342 git_checkout_notify_t why,
343 const char *path,
344 const git_diff_file *baseline,
345 const git_diff_file *target,
346 const git_diff_file *workdir,
347 void *payload)
348 {
349 GIT_UNUSED(why);
350 GIT_UNUSED(path);
351 GIT_UNUSED(baseline);
352 GIT_UNUSED(target);
353 GIT_UNUSED(workdir);
354 GIT_UNUSED(payload);
355
356 cl_assert(false);
357
358 return 0;
359 }
360
361 void test_checkout_index__wont_notify_of_expected_line_ending_changes(void)
362 {
363 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
364
365 cl_git_pass(p_unlink("./testrepo/.gitattributes"));
366 cl_repo_set_bool(g_repo, "core.autocrlf", true);
367
368 cl_git_mkfile("./testrepo/new.txt", "my new file\r\n");
369
370 opts.checkout_strategy =
371 GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_ALLOW_CONFLICTS;
372 opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT;
373 opts.notify_cb = dont_notify_cb;
374 opts.notify_payload = NULL;
375
376 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
377 }
378
379 static void checkout_progress_counter(
380 const char *path, size_t cur, size_t tot, void *payload)
381 {
382 GIT_UNUSED(path); GIT_UNUSED(cur); GIT_UNUSED(tot);
383 (*(int *)payload)++;
384 }
385
386 void test_checkout_index__calls_progress_callback(void)
387 {
388 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
389 int calls = 0;
390
391 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
392 opts.progress_cb = checkout_progress_counter;
393 opts.progress_payload = &calls;
394
395 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
396 cl_assert(calls > 0);
397 }
398
399 void test_checkout_index__can_overcome_name_clashes(void)
400 {
401 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
402 git_index *index;
403
404 cl_git_pass(git_repository_index(&index, g_repo));
405 git_index_clear(index);
406
407 cl_git_mkfile("./testrepo/path0", "content\r\n");
408 cl_git_pass(p_mkdir("./testrepo/path1", 0777));
409 cl_git_mkfile("./testrepo/path1/file1", "content\r\n");
410
411 cl_git_pass(git_index_add_bypath(index, "path0"));
412 cl_git_pass(git_index_add_bypath(index, "path1/file1"));
413
414 cl_git_pass(p_unlink("./testrepo/path0"));
415 cl_git_pass(git_futils_rmdir_r(
416 "./testrepo/path1", NULL, GIT_RMDIR_REMOVE_FILES));
417
418 cl_git_mkfile("./testrepo/path1", "content\r\n");
419 cl_git_pass(p_mkdir("./testrepo/path0", 0777));
420 cl_git_mkfile("./testrepo/path0/file0", "content\r\n");
421
422 cl_assert(git_path_isfile("./testrepo/path1"));
423 cl_assert(git_path_isfile("./testrepo/path0/file0"));
424
425 opts.checkout_strategy =
426 GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_ALLOW_CONFLICTS;
427 cl_git_pass(git_checkout_index(g_repo, index, &opts));
428
429 cl_assert(git_path_isfile("./testrepo/path1"));
430 cl_assert(git_path_isfile("./testrepo/path0/file0"));
431
432 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
433 cl_git_pass(git_checkout_index(g_repo, index, &opts));
434
435 cl_assert(git_path_isfile("./testrepo/path0"));
436 cl_assert(git_path_isfile("./testrepo/path1/file1"));
437
438 git_index_free(index);
439 }
440
441 void test_checkout_index__validates_struct_version(void)
442 {
443 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
444 const git_error *err;
445
446 opts.version = 1024;
447 cl_git_fail(git_checkout_index(g_repo, NULL, &opts));
448
449 err = giterr_last();
450 cl_assert_equal_i(err->klass, GITERR_INVALID);
451
452 opts.version = 0;
453 giterr_clear();
454 cl_git_fail(git_checkout_index(g_repo, NULL, &opts));
455
456 err = giterr_last();
457 cl_assert_equal_i(err->klass, GITERR_INVALID);
458 }
459
460 void test_checkout_index__can_update_prefixed_files(void)
461 {
462 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
463
464 cl_assert_equal_i(false, git_path_isfile("./testrepo/README"));
465 cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt"));
466 cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt"));
467
468 cl_git_mkfile("./testrepo/READ", "content\n");
469 cl_git_mkfile("./testrepo/README.after", "content\n");
470 cl_git_pass(p_mkdir("./testrepo/branch_file", 0777));
471 cl_git_pass(p_mkdir("./testrepo/branch_file/contained_dir", 0777));
472 cl_git_mkfile("./testrepo/branch_file/contained_file", "content\n");
473 cl_git_pass(p_mkdir("./testrepo/branch_file.txt.after", 0777));
474
475 opts.checkout_strategy =
476 GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_REMOVE_UNTRACKED;
477
478 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
479
480 /* remove untracked will remove the .gitattributes file before the blobs
481 * were created, so they will have had crlf filtering applied on Windows
482 */
483 check_file_contents_nocr("./testrepo/README", "hey there\n");
484 check_file_contents_nocr("./testrepo/branch_file.txt", "hi\nbye!\n");
485 check_file_contents_nocr("./testrepo/new.txt", "my new file\n");
486
487 cl_assert(!git_path_exists("testrepo/READ"));
488 cl_assert(!git_path_exists("testrepo/README.after"));
489 cl_assert(!git_path_exists("testrepo/branch_file"));
490 cl_assert(!git_path_exists("testrepo/branch_file.txt.after"));
491 }
492
493 void test_checkout_index__can_checkout_a_newly_initialized_repository(void)
494 {
495 test_checkout_index__cleanup();
496
497 g_repo = cl_git_sandbox_init("empty_standard_repo");
498 cl_git_remove_placeholders(git_repository_path(g_repo), "dummy-marker.txt");
499
500 cl_git_pass(git_checkout_index(g_repo, NULL, NULL));
501 }
502
503 void test_checkout_index__issue_1397(void)
504 {
505 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
506
507 test_checkout_index__cleanup();
508
509 g_repo = cl_git_sandbox_init("issue_1397");
510
511 cl_repo_set_bool(g_repo, "core.autocrlf", true);
512
513 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
514
515 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
516
517 check_file_contents("./issue_1397/crlf_file.txt", "first line\r\nsecond line\r\nboth with crlf");
518 }
519
520 void test_checkout_index__target_directory(void)
521 {
522 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
523 checkout_counts cts;
524 memset(&cts, 0, sizeof(cts));
525
526 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
527 opts.target_directory = "alternative";
528 cl_assert(!git_path_isdir("alternative"));
529
530 opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
531 opts.notify_cb = checkout_count_callback;
532 opts.notify_payload = &cts;
533
534 /* create some files that *would* conflict if we were using the wd */
535 cl_git_mkfile("testrepo/README", "I'm in the way!\n");
536 cl_git_mkfile("testrepo/new.txt", "my new file\n");
537
538 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
539
540 cl_assert_equal_i(0, cts.n_untracked);
541 cl_assert_equal_i(0, cts.n_ignored);
542 cl_assert_equal_i(4, cts.n_updates);
543
544 check_file_contents("./alternative/README", "hey there\n");
545 check_file_contents("./alternative/branch_file.txt", "hi\nbye!\n");
546 check_file_contents("./alternative/new.txt", "my new file\n");
547
548 cl_git_pass(git_futils_rmdir_r(
549 "alternative", NULL, GIT_RMDIR_REMOVE_FILES));
550 }
551
552 void test_checkout_index__target_directory_from_bare(void)
553 {
554 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
555 git_index *index;
556 git_object *head = NULL;
557 checkout_counts cts;
558 memset(&cts, 0, sizeof(cts));
559
560 test_checkout_index__cleanup();
561
562 g_repo = cl_git_sandbox_init("testrepo.git");
563 cl_assert(git_repository_is_bare(g_repo));
564
565 cl_git_pass(git_repository_index(&index, g_repo));
566 cl_git_pass(git_revparse_single(&head, g_repo, "HEAD^{tree}"));
567 cl_git_pass(git_index_read_tree(index, (const git_tree *)head));
568 cl_git_pass(git_index_write(index));
569 git_index_free(index);
570
571 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
572
573 opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
574 opts.notify_cb = checkout_count_callback;
575 opts.notify_payload = &cts;
576
577 /* fail to checkout a bare repo */
578 cl_git_fail(git_checkout_index(g_repo, NULL, &opts));
579
580 opts.target_directory = "alternative";
581 cl_assert(!git_path_isdir("alternative"));
582
583 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
584
585 cl_assert_equal_i(0, cts.n_untracked);
586 cl_assert_equal_i(0, cts.n_ignored);
587 cl_assert_equal_i(3, cts.n_updates);
588
589 /* files will have been filtered if needed, so strip CR */
590 check_file_contents_nocr("./alternative/README", "hey there\n");
591 check_file_contents_nocr("./alternative/branch_file.txt", "hi\nbye!\n");
592 check_file_contents_nocr("./alternative/new.txt", "my new file\n");
593
594 cl_git_pass(git_futils_rmdir_r(
595 "alternative", NULL, GIT_RMDIR_REMOVE_FILES));
596
597 git_object_free(head);
598 }
599
600 void test_checkout_index__can_get_repo_from_index(void)
601 {
602 git_index *index;
603 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
604
605 cl_assert_equal_i(false, git_path_isfile("./testrepo/README"));
606 cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt"));
607 cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt"));
608
609 opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
610
611 cl_git_pass(git_repository_index(&index, g_repo));
612
613 cl_git_pass(git_checkout_index(NULL, index, &opts));
614
615 check_file_contents("./testrepo/README", "hey there\n");
616 check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
617 check_file_contents("./testrepo/new.txt", "my new file\n");
618
619 git_index_free(index);
620 }
621
622 static void add_conflict(git_index *index, const char *path)
623 {
624 git_index_entry entry;
625
626 memset(&entry, 0, sizeof(git_index_entry));
627
628 entry.mode = 0100644;
629 entry.path = path;
630
631 git_oid_fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46");
632 entry.flags = (1 << GIT_IDXENTRY_STAGESHIFT);
633 cl_git_pass(git_index_add(index, &entry));
634
635 git_oid_fromstr(&entry.id, "4e886e602529caa9ab11d71f86634bd1b6e0de10");
636 entry.flags = (2 << GIT_IDXENTRY_STAGESHIFT);
637 cl_git_pass(git_index_add(index, &entry));
638
639 git_oid_fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
640 entry.flags = (3 << GIT_IDXENTRY_STAGESHIFT);
641 cl_git_pass(git_index_add(index, &entry));
642 }
643
644 void test_checkout_index__writes_conflict_file(void)
645 {
646 git_index *index;
647 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
648 git_buf conflicting_buf = GIT_BUF_INIT;
649
650 cl_git_pass(git_repository_index(&index, g_repo));
651
652 add_conflict(index, "conflicting.txt");
653 cl_git_pass(git_index_write(index));
654
655 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
656
657 cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt"));
658 cl_assert(strcmp(conflicting_buf.ptr,
659 "<<<<<<< ours\n"
660 "this file is changed in master and branch\n"
661 "=======\n"
662 "this file is changed in branch and master\n"
663 ">>>>>>> theirs\n") == 0);
664 git_buf_free(&conflicting_buf);
665
666 git_index_free(index);
667 }
668
669 void test_checkout_index__adding_conflict_removes_stage_0(void)
670 {
671 git_index *new_index, *index;
672 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
673
674 cl_git_pass(git_index_new(&new_index));
675
676 add_conflict(new_index, "new.txt");
677 cl_git_pass(git_checkout_index(g_repo, new_index, &opts));
678
679 cl_git_pass(git_repository_index(&index, g_repo));
680
681 cl_assert(git_index_get_bypath(index, "new.txt", 0) == NULL);
682 cl_assert(git_index_get_bypath(index, "new.txt", 1) != NULL);
683 cl_assert(git_index_get_bypath(index, "new.txt", 2) != NULL);
684 cl_assert(git_index_get_bypath(index, "new.txt", 3) != NULL);
685
686 git_index_free(index);
687 git_index_free(new_index);
688 }
689
690 void test_checkout_index__conflicts_honor_coreautocrlf(void)
691 {
692 #ifdef GIT_WIN32
693 git_index *index;
694 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
695 git_buf conflicting_buf = GIT_BUF_INIT;
696
697 cl_git_pass(p_unlink("./testrepo/.gitattributes"));
698 cl_repo_set_bool(g_repo, "core.autocrlf", true);
699
700 cl_git_pass(git_repository_index(&index, g_repo));
701
702 add_conflict(index, "conflicting.txt");
703 cl_git_pass(git_index_write(index));
704
705 cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
706
707 cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt"));
708 cl_assert(strcmp(conflicting_buf.ptr,
709 "<<<<<<< ours\r\n"
710 "this file is changed in master and branch\r\n"
711 "=======\r\n"
712 "this file is changed in branch and master\r\n"
713 ">>>>>>> theirs\r\n") == 0);
714 git_buf_free(&conflicting_buf);
715
716 git_index_free(index);
717 #endif
718 }