]> git.proxmox.com Git - libgit2.git/blob - tests/cherrypick/workdir.c
10e8c2d8b4f64fbc4fd52b04254120472ba6a91a
[libgit2.git] / tests / cherrypick / workdir.c
1 #include "clar.h"
2 #include "clar_libgit2.h"
3
4 #include "buffer.h"
5 #include "futils.h"
6 #include "git2/cherrypick.h"
7
8 #include "../merge/merge_helpers.h"
9
10 #define TEST_REPO_PATH "cherrypick"
11
12 static git_repository *repo;
13 static git_index *repo_index;
14
15 /* Fixture setup and teardown */
16 void test_cherrypick_workdir__initialize(void)
17 {
18 repo = cl_git_sandbox_init(TEST_REPO_PATH);
19 git_repository_index(&repo_index, repo);
20 }
21
22 void test_cherrypick_workdir__cleanup(void)
23 {
24 git_index_free(repo_index);
25 cl_git_sandbox_cleanup();
26 }
27
28 /* git reset --hard d3d77487660ee3c0194ee01dc5eaf478782b1c7e
29 * git cherry-pick cfc4f0999a8367568e049af4f72e452d40828a15
30 * git cherry-pick 964ea3da044d9083181a88ba6701de9e35778bf4
31 * git cherry-pick a43a050c588d4e92f11a6b139680923e9728477d
32 */
33 void test_cherrypick_workdir__automerge(void)
34 {
35 git_oid head_oid;
36 git_signature *signature = NULL;
37 size_t i;
38
39 const char *cherrypick_oids[] = {
40 "cfc4f0999a8367568e049af4f72e452d40828a15",
41 "964ea3da044d9083181a88ba6701de9e35778bf4",
42 "a43a050c588d4e92f11a6b139680923e9728477d",
43 };
44
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" },
49
50 { 0100644, "38c05a857e831a7e759d83778bfc85d003e21c45", 0, "file1.txt" },
51 { 0100644, "bd8fc3c59fb52d3c8b5907ace7defa5803f82419", 0, "file2.txt" },
52 { 0100644, "df6b290e0bd6a89b01d69f66687e8abf385283ca", 0, "file3.txt" },
53
54 { 0100644, "f06427bee380364bc7e0cb26a9245158e4726ce0", 0, "file1.txt" },
55 { 0100644, "bd8fc3c59fb52d3c8b5907ace7defa5803f82419", 0, "file2.txt" },
56 { 0100644, "df6b290e0bd6a89b01d69f66687e8abf385283ca", 0, "file3.txt" },
57 };
58
59 cl_git_pass(git_signature_new(&signature, "Picker", "picker@example.org", time(NULL), 0));
60
61 git_oid_fromstr(&head_oid, "d3d77487660ee3c0194ee01dc5eaf478782b1c7e");
62
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;
67
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));
70
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));
74
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"));
77
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));
82
83 cl_assert(merge_test_index(repo_index, merge_index_entries + i * 3, 3));
84
85 git_oid_cpy(&head_oid, &cherrypicked_oid);
86
87 git_tree_free(cherrypicked_tree);
88 git_commit_free(head);
89 git_commit_free(commit);
90 }
91
92 git_signature_free(signature);
93 }
94
95 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
96 * git cherry-pick a43a050c588d4e92f11a6b139680923e9728477d*/
97 void test_cherrypick_workdir__empty_result(void)
98 {
99 git_oid head_oid;
100 git_signature *signature = NULL;
101 git_commit *head = NULL, *commit = NULL;
102 git_oid cherry_oid;
103
104 const char *cherrypick_oid = "a43a050c588d4e92f11a6b139680923e9728477d";
105
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" },
110 };
111
112 cl_git_pass(git_signature_new(&signature, "Picker", "picker@example.org", time(NULL), 0));
113
114 git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15");
115
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"));
119
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));
122
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));
126
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));
129
130 git_commit_free(head);
131 git_commit_free(commit);
132
133 git_signature_free(signature);
134 }
135
136 /* git reset --hard bafbf6912c09505ac60575cd43d3f2aba3bd84d8
137 * git cherry-pick e9b63f3655b2ad80c0ff587389b5a9589a3a7110
138 */
139 void test_cherrypick_workdir__conflicts(void)
140 {
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;
144
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" },
153 };
154
155 git_oid_fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8");
156
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));
159
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));
163
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"));
166
167 cl_assert(merge_test_index(repo_index, merge_index_entries, 7));
168
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" \
173 "\n" \
174 "Conflicts:\n" \
175 "\tfile2.txt\n" \
176 "\tfile3.txt\n") == 0);
177
178 cl_git_pass(git_futils_readbuffer(&conflicting_buf,
179 TEST_REPO_PATH "/file2.txt"));
180
181 cl_assert(strcmp(git_buf_cstr(&conflicting_buf),
182 "!File 2\n" \
183 "File 2\n" \
184 "File 2\n" \
185 "File 2\n" \
186 "File 2\n" \
187 "File 2\n" \
188 "File 2\n" \
189 "File 2\n" \
190 "File 2\n" \
191 "File 2\n" \
192 "File 2!!\n" \
193 "File 2\n" \
194 "File 2\n" \
195 "File 2\n" \
196 "<<<<<<< HEAD\n" \
197 "File 2\n" \
198 "=======\n" \
199 "File 2!\n" \
200 "File 2\n" \
201 "File 2!\n" \
202 ">>>>>>> e9b63f3... Change all files\n") == 0);
203
204 cl_git_pass(git_futils_readbuffer(&conflicting_buf,
205 TEST_REPO_PATH "/file3.txt"));
206
207 cl_assert(strcmp(git_buf_cstr(&conflicting_buf),
208 "!File 3\n" \
209 "File 3\n" \
210 "File 3\n" \
211 "File 3\n" \
212 "File 3\n" \
213 "File 3\n" \
214 "File 3\n" \
215 "File 3\n" \
216 "File 3\n" \
217 "File 3\n" \
218 "File 3\n" \
219 "File 3!!\n" \
220 "File 3\n" \
221 "File 3\n" \
222 "File 3\n" \
223 "<<<<<<< HEAD\n" \
224 "=======\n" \
225 "File 3!\n" \
226 "File 3!\n" \
227 ">>>>>>> e9b63f3... Change all files\n") == 0);
228
229 git_commit_free(commit);
230 git_commit_free(head);
231 git_buf_dispose(&mergemsg_buf);
232 git_buf_dispose(&conflicting_buf);
233 }
234
235 /* git reset --hard bafbf6912c09505ac60575cd43d3f2aba3bd84d8
236 * git cherry-pick -X ours e9b63f3655b2ad80c0ff587389b5a9589a3a7110
237 */
238 void test_cherrypick_workdir__conflict_use_ours(void)
239 {
240 git_commit *head = NULL, *commit = NULL;
241 git_oid head_oid, cherry_oid;
242 git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
243
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" },
252 };
253
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" },
258 };
259
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;
262
263 git_oid_fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8");
264
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));
267
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));
271
272 cl_assert(merge_test_index(repo_index, merge_index_entries, 7));
273 cl_assert(merge_test_workdir(repo, merge_filesystem_entries, 3));
274
275 /* resolve conflicts in the index by taking "ours" */
276 opts.merge_opts.file_favor = GIT_MERGE_FILE_FAVOR_OURS;
277
278 cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL));
279 cl_git_pass(git_cherrypick(repo, commit, &opts));
280
281 cl_assert(merge_test_index(repo_index, merge_filesystem_entries, 3));
282 cl_assert(merge_test_workdir(repo, merge_filesystem_entries, 3));
283
284 git_commit_free(commit);
285 git_commit_free(head);
286 }
287
288 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
289 * git cherry-pick 2a26c7e88b285613b302ba76712bc998863f3cbc
290 */
291 void test_cherrypick_workdir__rename(void)
292 {
293 git_commit *head, *commit;
294 git_oid head_oid, cherry_oid;
295 git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
296
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" },
301 };
302
303 opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES;
304 opts.merge_opts.rename_threshold = 50;
305
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));
309
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));
313
314 cl_assert(merge_test_index(repo_index, merge_index_entries, 3));
315
316 git_commit_free(commit);
317 git_commit_free(head);
318 }
319
320 /* git reset --hard 44cd2ed2052c9c68f9a439d208e9614dc2a55c70
321 * git cherry-pick 2a26c7e88b285613b302ba76712bc998863f3cbc
322 */
323 void test_cherrypick_workdir__both_renamed(void)
324 {
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;
329
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" },
336 };
337
338 opts.merge_opts.flags |= GIT_MERGE_FIND_RENAMES;
339 opts.merge_opts.rename_threshold = 50;
340
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));
344
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));
348
349 cl_assert(merge_test_index(repo_index, merge_index_entries, 5));
350
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" \
355 "\n" \
356 "Conflicts:\n" \
357 "\tfile3.txt\n" \
358 "\tfile3.txt.renamed\n" \
359 "\tfile3.txt.renamed_on_branch\n") == 0);
360
361 git_buf_dispose(&mergemsg_buf);
362 git_commit_free(commit);
363 git_commit_free(head);
364 }
365
366 void test_cherrypick_workdir__nonmerge_fails_mainline_specified(void)
367 {
368 git_reference *head;
369 git_commit *commit;
370 git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
371
372 cl_git_pass(git_repository_head(&head, repo));
373 cl_git_pass(git_reference_peel((git_object **)&commit, head, GIT_OBJECT_COMMIT));
374
375 opts.mainline = 1;
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"));
379
380 git_reference_free(head);
381 git_commit_free(commit);
382 }
383
384 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
385 * git cherry-pick abe4603bc7cd5b8167a267e0e2418fd2348f8cff
386 */
387 void test_cherrypick_workdir__merge_fails_without_mainline_specified(void)
388 {
389 git_commit *head, *commit;
390 git_oid head_oid, cherry_oid;
391
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));
395
396 git_oid_fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff");
397 cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid));
398
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"));
402
403 git_commit_free(commit);
404 git_commit_free(head);
405 }
406
407 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
408 * git cherry-pick -m1 abe4603bc7cd5b8167a267e0e2418fd2348f8cff
409 */
410 void test_cherrypick_workdir__merge_first_parent(void)
411 {
412 git_commit *head, *commit;
413 git_oid head_oid, cherry_oid;
414 git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
415
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" },
420 };
421
422 opts.mainline = 1;
423
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));
427
428 git_oid_fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff");
429 cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid));
430
431 cl_git_pass(git_cherrypick(repo, commit, &opts));
432
433 cl_assert(merge_test_index(repo_index, merge_index_entries, 3));
434
435 git_commit_free(commit);
436 git_commit_free(head);
437 }
438
439 /* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15
440 * git cherry-pick -m2 abe4603bc7cd5b8167a267e0e2418fd2348f8cff
441 */
442 void test_cherrypick_workdir__merge_second_parent(void)
443 {
444 git_commit *head, *commit;
445 git_oid head_oid, cherry_oid;
446 git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
447
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" },
452 };
453
454 opts.mainline = 2;
455
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));
459
460 git_oid_fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff");
461 cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid));
462
463 cl_git_pass(git_cherrypick(repo, commit, &opts));
464
465 cl_assert(merge_test_index(repo_index, merge_index_entries, 3));
466
467 git_commit_free(commit);
468 git_commit_free(head);
469 }
470