2 #include "clar_libgit2.h"
6 #include "git2/cherrypick.h"
8 #include "../merge/merge_helpers.h"
10 #define TEST_REPO_PATH "cherrypick"
12 static git_repository
*repo
;
13 static git_index
*repo_index
;
15 // Fixture setup and teardown
16 void test_cherrypick_workdir__initialize(void)
18 repo
= cl_git_sandbox_init(TEST_REPO_PATH
);
19 git_repository_index(&repo_index
, repo
);
22 void test_cherrypick_workdir__cleanup(void)
24 git_index_free(repo_index
);
25 cl_git_sandbox_cleanup();
28 /* git reset --hard d3d77487660ee3c0194ee01dc5eaf478782b1c7e
29 * git cherry-pick cfc4f0999a8367568e049af4f72e452d40828a15
30 * git cherry-pick 964ea3da044d9083181a88ba6701de9e35778bf4
31 * git cherry-pick a43a050c588d4e92f11a6b139680923e9728477d
33 void test_cherrypick_workdir__automerge(void)
36 git_signature
*signature
= NULL
;
39 const char *cherrypick_oids
[] = {
40 "cfc4f0999a8367568e049af4f72e452d40828a15",
41 "964ea3da044d9083181a88ba6701de9e35778bf4",
42 "a43a050c588d4e92f11a6b139680923e9728477d",
45 struct merge_index_entry merge_index_entries
[] = {
46 { 0100644, "38c05a857e831a7e759d83778bfc85d003e21c45", 0, "file1.txt" },
47 { 0100644, "a661b5dec1004e2c62654ded3762370c27cf266b", 0, "file2.txt" },
48 { 0100644, "df6b290e0bd6a89b01d69f66687e8abf385283ca", 0, "file3.txt" },
50 { 0100644, "38c05a857e831a7e759d83778bfc85d003e21c45", 0, "file1.txt" },
51 { 0100644, "bd8fc3c59fb52d3c8b5907ace7defa5803f82419", 0, "file2.txt" },
52 { 0100644, "df6b290e0bd6a89b01d69f66687e8abf385283ca", 0, "file3.txt" },
54 { 0100644, "f06427bee380364bc7e0cb26a9245158e4726ce0", 0, "file1.txt" },
55 { 0100644, "bd8fc3c59fb52d3c8b5907ace7defa5803f82419", 0, "file2.txt" },
56 { 0100644, "df6b290e0bd6a89b01d69f66687e8abf385283ca", 0, "file3.txt" },
59 cl_git_pass(git_signature_new(&signature
, "Picker", "picker@example.org", time(NULL
), 0));
61 git_oid_fromstr(&head_oid
, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e");
63 for (i
= 0; i
< 3; ++i
) {
64 git_commit
*head
= NULL
, *commit
= NULL
;
65 git_oid cherry_oid
, cherrypicked_oid
, cherrypicked_tree_oid
;
66 git_tree
*cherrypicked_tree
= NULL
;
68 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
69 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
71 git_oid_fromstr(&cherry_oid
, cherrypick_oids
[i
]);
72 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
73 cl_git_pass(git_cherrypick(repo
, commit
, NULL
));
75 cl_assert(git_path_exists(TEST_REPO_PATH
"/.git/CHERRY_PICK_HEAD"));
76 cl_assert(git_path_exists(TEST_REPO_PATH
"/.git/MERGE_MSG"));
78 cl_git_pass(git_index_write_tree(&cherrypicked_tree_oid
, repo_index
));
79 cl_git_pass(git_tree_lookup(&cherrypicked_tree
, repo
, &cherrypicked_tree_oid
));
80 cl_git_pass(git_commit_create(&cherrypicked_oid
, repo
, "HEAD", signature
, signature
, NULL
,
81 "Cherry picked!", cherrypicked_tree
, 1, (const git_commit
**)&head
));
83 cl_assert(merge_test_index(repo_index
, merge_index_entries
+ i
* 3, 3));
85 git_oid_cpy(&head_oid
, &cherrypicked_oid
);
87 git_tree_free(cherrypicked_tree
);
88 git_commit_free(head
);
89 git_commit_free(commit
);
92 git_signature_free(signature
);
95 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
96 * git cherry-pick a43a050c588d4e92f11a6b139680923e9728477d*/
97 void test_cherrypick_workdir__empty_result(void)
100 git_signature
*signature
= NULL
;
101 git_commit
*head
= NULL
, *commit
= NULL
;
104 const char *cherrypick_oid
= "a43a050c588d4e92f11a6b139680923e9728477d";
106 struct merge_index_entry merge_index_entries
[] = {
107 { 0100644, "19c5c7207054604b69c84d08a7571ef9672bb5c2", 0, "file1.txt" },
108 { 0100644, "a58ca3fee5eb68b11adc2703e5843f968c9dad1e", 0, "file2.txt" },
109 { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 0, "file3.txt" },
112 cl_git_pass(git_signature_new(&signature
, "Picker", "picker@example.org", time(NULL
), 0));
114 git_oid_fromstr(&head_oid
, "cfc4f0999a8367568e049af4f72e452d40828a15");
116 /* Create an untracked file that should not conflict */
117 cl_git_mkfile(TEST_REPO_PATH
"/file4.txt", "");
118 cl_assert(git_path_exists(TEST_REPO_PATH
"/file4.txt"));
120 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
121 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
));
123 git_oid_fromstr(&cherry_oid
, cherrypick_oid
);
124 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
125 cl_git_pass(git_cherrypick(repo
, commit
, NULL
));
127 /* The resulting tree should not have changed, the change was already on HEAD */
128 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 3));
130 git_commit_free(head
);
131 git_commit_free(commit
);
133 git_signature_free(signature
);
136 /* git reset --hard bafbf6912c09505ac60575cd43d3f2aba3bd84d8
137 * git cherry-pick e9b63f3655b2ad80c0ff587389b5a9589a3a7110
139 void test_cherrypick_workdir__conflicts(void)
141 git_commit
*head
= NULL
, *commit
= NULL
;
142 git_oid head_oid
, cherry_oid
;
143 git_buf conflicting_buf
= GIT_BUF_INIT
, mergemsg_buf
= GIT_BUF_INIT
;
145 struct merge_index_entry merge_index_entries
[] = {
146 { 0100644, "242e7977ba73637822ffb265b46004b9b0e5153b", 0, "file1.txt" },
147 { 0100644, "a58ca3fee5eb68b11adc2703e5843f968c9dad1e", 1, "file2.txt" },
148 { 0100644, "bd6ffc8c6c41f0f85ff9e3d61c9479516bac0024", 2, "file2.txt" },
149 { 0100644, "563f6473a3858f99b80e5f93c660512ed38e1e6f", 3, "file2.txt" },
150 { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 1, "file3.txt" },
151 { 0100644, "1124c2c1ae07b26fded662d6c3f3631d9dc16f88", 2, "file3.txt" },
152 { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 3, "file3.txt" },
155 git_oid_fromstr(&head_oid
, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8");
157 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
158 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
160 git_oid_fromstr(&cherry_oid
, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110");
161 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
162 cl_git_pass(git_cherrypick(repo
, commit
, NULL
));
164 cl_assert(git_path_exists(TEST_REPO_PATH
"/.git/CHERRY_PICK_HEAD"));
165 cl_assert(git_path_exists(TEST_REPO_PATH
"/.git/MERGE_MSG"));
167 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 7));
169 cl_git_pass(git_futils_readbuffer(&mergemsg_buf
,
170 TEST_REPO_PATH
"/.git/MERGE_MSG"));
171 cl_assert(strcmp(git_buf_cstr(&mergemsg_buf
),
172 "Change all files\n" \
176 "\tfile3.txt\n") == 0);
178 cl_git_pass(git_futils_readbuffer(&conflicting_buf
,
179 TEST_REPO_PATH
"/file2.txt"));
181 cl_assert(strcmp(git_buf_cstr(&conflicting_buf
),
202 ">>>>>>> e9b63f3... Change all files\n") == 0);
204 cl_git_pass(git_futils_readbuffer(&conflicting_buf
,
205 TEST_REPO_PATH
"/file3.txt"));
207 cl_assert(strcmp(git_buf_cstr(&conflicting_buf
),
227 ">>>>>>> e9b63f3... Change all files\n") == 0);
229 git_commit_free(commit
);
230 git_commit_free(head
);
231 git_buf_free(&mergemsg_buf
);
232 git_buf_free(&conflicting_buf
);
235 /* git reset --hard bafbf6912c09505ac60575cd43d3f2aba3bd84d8
236 * git cherry-pick -X ours e9b63f3655b2ad80c0ff587389b5a9589a3a7110
238 void test_cherrypick_workdir__conflict_use_ours(void)
240 git_commit
*head
= NULL
, *commit
= NULL
;
241 git_oid head_oid
, cherry_oid
;
242 git_cherrypick_options opts
= GIT_CHERRYPICK_OPTIONS_INIT
;
244 struct merge_index_entry merge_index_entries
[] = {
245 { 0100644, "242e7977ba73637822ffb265b46004b9b0e5153b", 0, "file1.txt" },
246 { 0100644, "a58ca3fee5eb68b11adc2703e5843f968c9dad1e", 1, "file2.txt" },
247 { 0100644, "bd6ffc8c6c41f0f85ff9e3d61c9479516bac0024", 2, "file2.txt" },
248 { 0100644, "563f6473a3858f99b80e5f93c660512ed38e1e6f", 3, "file2.txt" },
249 { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 1, "file3.txt" },
250 { 0100644, "1124c2c1ae07b26fded662d6c3f3631d9dc16f88", 2, "file3.txt" },
251 { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 3, "file3.txt" },
254 struct merge_index_entry merge_filesystem_entries
[] = {
255 { 0100644, "242e7977ba73637822ffb265b46004b9b0e5153b", 0, "file1.txt" },
256 { 0100644, "bd6ffc8c6c41f0f85ff9e3d61c9479516bac0024", 0, "file2.txt" },
257 { 0100644, "1124c2c1ae07b26fded662d6c3f3631d9dc16f88", 0, "file3.txt" },
260 /* leave the index in a conflicted state, but checkout "ours" to the workdir */
261 opts
.checkout_opts
.checkout_strategy
= GIT_CHECKOUT_SAFE
| GIT_CHECKOUT_USE_OURS
;
263 git_oid_fromstr(&head_oid
, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8");
265 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
266 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
268 git_oid_fromstr(&cherry_oid
, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110");
269 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
270 cl_git_pass(git_cherrypick(repo
, commit
, &opts
));
272 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 7));
273 cl_assert(merge_test_workdir(repo
, merge_filesystem_entries
, 3));
275 /* resolve conflicts in the index by taking "ours" */
276 opts
.merge_opts
.file_favor
= GIT_MERGE_FILE_FAVOR_OURS
;
278 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
279 cl_git_pass(git_cherrypick(repo
, commit
, &opts
));
281 cl_assert(merge_test_index(repo_index
, merge_filesystem_entries
, 3));
282 cl_assert(merge_test_workdir(repo
, merge_filesystem_entries
, 3));
284 git_commit_free(commit
);
285 git_commit_free(head
);
288 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
289 * git cherry-pick 2a26c7e88b285613b302ba76712bc998863f3cbc
291 void test_cherrypick_workdir__rename(void)
293 git_commit
*head
, *commit
;
294 git_oid head_oid
, cherry_oid
;
295 git_cherrypick_options opts
= GIT_CHERRYPICK_OPTIONS_INIT
;
297 struct merge_index_entry merge_index_entries
[] = {
298 { 0100644, "19c5c7207054604b69c84d08a7571ef9672bb5c2", 0, "file1.txt" },
299 { 0100644, "a58ca3fee5eb68b11adc2703e5843f968c9dad1e", 0, "file2.txt" },
300 { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 0, "file3.txt.renamed" },
303 opts
.merge_opts
.flags
|= GIT_MERGE_TREE_FIND_RENAMES
;
304 opts
.merge_opts
.rename_threshold
= 50;
306 git_oid_fromstr(&head_oid
, "cfc4f0999a8367568e049af4f72e452d40828a15");
307 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
308 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
310 git_oid_fromstr(&cherry_oid
, "2a26c7e88b285613b302ba76712bc998863f3cbc");
311 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
312 cl_git_pass(git_cherrypick(repo
, commit
, &opts
));
314 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 3));
316 git_commit_free(commit
);
317 git_commit_free(head
);
320 /* git reset --hard 44cd2ed2052c9c68f9a439d208e9614dc2a55c70
321 * git cherry-pick 2a26c7e88b285613b302ba76712bc998863f3cbc
323 void test_cherrypick_workdir__both_renamed(void)
325 git_commit
*head
, *commit
;
326 git_oid head_oid
, cherry_oid
;
327 git_buf mergemsg_buf
= GIT_BUF_INIT
;
328 git_cherrypick_options opts
= GIT_CHERRYPICK_OPTIONS_INIT
;
330 struct merge_index_entry merge_index_entries
[] = {
331 { 0100644, "19c5c7207054604b69c84d08a7571ef9672bb5c2", 0, "file1.txt" },
332 { 0100644, "a58ca3fee5eb68b11adc2703e5843f968c9dad1e", 0, "file2.txt" },
333 { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 1, "file3.txt" },
334 { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 3, "file3.txt.renamed" },
335 { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 2, "file3.txt.renamed_on_branch" },
338 opts
.merge_opts
.flags
|= GIT_MERGE_TREE_FIND_RENAMES
;
339 opts
.merge_opts
.rename_threshold
= 50;
341 git_oid_fromstr(&head_oid
, "44cd2ed2052c9c68f9a439d208e9614dc2a55c70");
342 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
343 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
345 git_oid_fromstr(&cherry_oid
, "2a26c7e88b285613b302ba76712bc998863f3cbc");
346 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
347 cl_git_pass(git_cherrypick(repo
, commit
, &opts
));
349 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 5));
351 cl_git_pass(git_futils_readbuffer(&mergemsg_buf
,
352 TEST_REPO_PATH
"/.git/MERGE_MSG"));
353 cl_assert(strcmp(git_buf_cstr(&mergemsg_buf
),
354 "Renamed file3.txt -> file3.txt.renamed\n" \
358 "\tfile3.txt.renamed\n" \
359 "\tfile3.txt.renamed_on_branch\n") == 0);
361 git_buf_free(&mergemsg_buf
);
362 git_commit_free(commit
);
363 git_commit_free(head
);
366 void test_cherrypick_workdir__nonmerge_fails_mainline_specified(void)
370 git_cherrypick_options opts
= GIT_CHERRYPICK_OPTIONS_INIT
;
372 cl_git_pass(git_repository_head(&head
, repo
));
373 cl_git_pass(git_reference_peel((git_object
**)&commit
, head
, GIT_OBJ_COMMIT
));
376 cl_must_fail(git_cherrypick(repo
, commit
, &opts
));
377 cl_assert(!git_path_exists(TEST_REPO_PATH
"/.git/CHERRY_PICK_HEAD"));
378 cl_assert(!git_path_exists(TEST_REPO_PATH
"/.git/MERGE_MSG"));
380 git_reference_free(head
);
381 git_commit_free(commit
);
384 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
385 * git cherry-pick abe4603bc7cd5b8167a267e0e2418fd2348f8cff
387 void test_cherrypick_workdir__merge_fails_without_mainline_specified(void)
389 git_commit
*head
, *commit
;
390 git_oid head_oid
, cherry_oid
;
392 git_oid_fromstr(&head_oid
, "cfc4f0999a8367568e049af4f72e452d40828a15");
393 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
394 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
396 git_oid_fromstr(&cherry_oid
, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff");
397 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
399 cl_must_fail(git_cherrypick(repo
, commit
, NULL
));
400 cl_assert(!git_path_exists(TEST_REPO_PATH
"/.git/CHERRY_PICK_HEAD"));
401 cl_assert(!git_path_exists(TEST_REPO_PATH
"/.git/MERGE_MSG"));
403 git_commit_free(commit
);
404 git_commit_free(head
);
407 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
408 * git cherry-pick -m1 abe4603bc7cd5b8167a267e0e2418fd2348f8cff
410 void test_cherrypick_workdir__merge_first_parent(void)
412 git_commit
*head
, *commit
;
413 git_oid head_oid
, cherry_oid
;
414 git_cherrypick_options opts
= GIT_CHERRYPICK_OPTIONS_INIT
;
416 struct merge_index_entry merge_index_entries
[] = {
417 { 0100644, "f90f9dcbdac2cce5cc166346160e19cb693ef4e8", 0, "file1.txt" },
418 { 0100644, "563f6473a3858f99b80e5f93c660512ed38e1e6f", 0, "file2.txt" },
419 { 0100644, "e233b9ed408a95e9d4b65fec7fc34943a556deb2", 0, "file3.txt" },
424 git_oid_fromstr(&head_oid
, "cfc4f0999a8367568e049af4f72e452d40828a15");
425 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
426 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
428 git_oid_fromstr(&cherry_oid
, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff");
429 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
431 cl_git_pass(git_cherrypick(repo
, commit
, &opts
));
433 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 3));
435 git_commit_free(commit
);
436 git_commit_free(head
);
439 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
440 * git cherry-pick -m2 abe4603bc7cd5b8167a267e0e2418fd2348f8cff
442 void test_cherrypick_workdir__merge_second_parent(void)
444 git_commit
*head
, *commit
;
445 git_oid head_oid
, cherry_oid
;
446 git_cherrypick_options opts
= GIT_CHERRYPICK_OPTIONS_INIT
;
448 struct merge_index_entry merge_index_entries
[] = {
449 { 0100644, "487434cace79238a7091e2220611d4f20a765690", 0, "file1.txt" },
450 { 0100644, "e5183bfd18e3a0a691fadde2f0d5610b73282d31", 0, "file2.txt" },
451 { 0100644, "409a1bec58bf35348e8b62b72bb9c1f45cf5a587", 0, "file3.txt" },
456 git_oid_fromstr(&head_oid
, "cfc4f0999a8367568e049af4f72e452d40828a15");
457 cl_git_pass(git_commit_lookup(&head
, repo
, &head_oid
));
458 cl_git_pass(git_reset(repo
, (git_object
*)head
, GIT_RESET_HARD
, NULL
, NULL
, NULL
));
460 git_oid_fromstr(&cherry_oid
, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff");
461 cl_git_pass(git_commit_lookup(&commit
, repo
, &cherry_oid
));
463 cl_git_pass(git_cherrypick(repo
, commit
, &opts
));
465 cl_assert(merge_test_index(repo_index
, merge_index_entries
, 3));
467 git_commit_free(commit
);
468 git_commit_free(head
);