]> git.proxmox.com Git - libgit2.git/blob - tests/merge/merge_helpers.c
Merge pull request #1983 from ethomson/revert
[libgit2.git] / tests / merge / merge_helpers.c
1 #include "clar_libgit2.h"
2 #include "fileops.h"
3 #include "refs.h"
4 #include "tree.h"
5 #include "merge_helpers.h"
6 #include "merge.h"
7 #include "git2/merge.h"
8 #include "git2/sys/index.h"
9
10 int merge_trees_from_branches(
11 git_index **index, git_repository *repo,
12 const char *ours_name, const char *theirs_name,
13 git_merge_tree_opts *opts)
14 {
15 git_commit *our_commit, *their_commit, *ancestor_commit = NULL;
16 git_tree *our_tree, *their_tree, *ancestor_tree = NULL;
17 git_oid our_oid, their_oid, ancestor_oid;
18 git_buf branch_buf = GIT_BUF_INIT;
19 int error;
20
21 git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours_name);
22 cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr));
23 cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid));
24
25 git_buf_clear(&branch_buf);
26 git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs_name);
27 cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr));
28 cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid));
29
30 error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit));
31
32 if (error != GIT_ENOTFOUND) {
33 cl_git_pass(error);
34
35 cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid));
36 cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit));
37 }
38
39 cl_git_pass(git_commit_tree(&our_tree, our_commit));
40 cl_git_pass(git_commit_tree(&their_tree, their_commit));
41
42 cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, opts));
43
44 git_buf_free(&branch_buf);
45 git_tree_free(our_tree);
46 git_tree_free(their_tree);
47 git_tree_free(ancestor_tree);
48 git_commit_free(our_commit);
49 git_commit_free(their_commit);
50 git_commit_free(ancestor_commit);
51
52 return 0;
53 }
54
55 int merge_commits_from_branches(
56 git_index **index, git_repository *repo,
57 const char *ours_name, const char *theirs_name,
58 git_merge_tree_opts *opts)
59 {
60 git_commit *our_commit, *their_commit;
61 git_oid our_oid, their_oid;
62 git_buf branch_buf = GIT_BUF_INIT;
63 int error;
64
65 git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours_name);
66 cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr));
67 cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid));
68
69 git_buf_clear(&branch_buf);
70 git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs_name);
71 cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr));
72 cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid));
73
74 cl_git_pass(git_merge_commits(index, repo, our_commit, their_commit, opts));
75
76 git_buf_free(&branch_buf);
77 git_commit_free(our_commit);
78 git_commit_free(their_commit);
79
80 return 0;
81 }
82
83 int merge_branches(git_merge_result **result, git_repository *repo, const char *ours_branch, const char *theirs_branch, git_merge_opts *opts)
84 {
85 git_reference *head_ref, *theirs_ref;
86 git_merge_head *theirs_head;
87 git_checkout_opts head_checkout_opts = GIT_CHECKOUT_OPTS_INIT;
88
89 head_checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
90
91 cl_git_pass(git_reference_symbolic_create(&head_ref, repo, "HEAD", ours_branch, 1));
92 cl_git_pass(git_checkout_head(repo, &head_checkout_opts));
93
94 cl_git_pass(git_reference_lookup(&theirs_ref, repo, theirs_branch));
95 cl_git_pass(git_merge_head_from_ref(&theirs_head, repo, theirs_ref));
96
97 cl_git_pass(git_merge(result, repo, (const git_merge_head **)&theirs_head, 1, opts));
98
99 git_reference_free(head_ref);
100 git_reference_free(theirs_ref);
101 git_merge_head_free(theirs_head);
102
103 return 0;
104 }
105
106 void merge__dump_index_entries(git_vector *index_entries)
107 {
108 size_t i;
109 const git_index_entry *index_entry;
110
111 printf ("\nINDEX [%d]:\n", (int)index_entries->length);
112 for (i = 0; i < index_entries->length; i++) {
113 index_entry = index_entries->contents[i];
114
115 printf("%o ", index_entry->mode);
116 printf("%s ", git_oid_allocfmt(&index_entry->oid));
117 printf("%d ", git_index_entry_stage(index_entry));
118 printf("%s ", index_entry->path);
119 printf("\n");
120 }
121 printf("\n");
122 }
123
124 void merge__dump_names(git_index *index)
125 {
126 size_t i;
127 const git_index_name_entry *conflict_name;
128
129 for (i = 0; i < git_index_name_entrycount(index); i++) {
130 conflict_name = git_index_name_get_byindex(index, i);
131
132 printf("%s %s %s\n", conflict_name->ancestor, conflict_name->ours, conflict_name->theirs);
133 }
134 printf("\n");
135 }
136
137 void merge__dump_reuc(git_index *index)
138 {
139 size_t i;
140 const git_index_reuc_entry *reuc;
141
142 printf ("\nREUC:\n");
143 for (i = 0; i < git_index_reuc_entrycount(index); i++) {
144 reuc = git_index_reuc_get_byindex(index, i);
145
146 printf("%s ", reuc->path);
147 printf("%o ", reuc->mode[0]);
148 printf("%s\n", git_oid_allocfmt(&reuc->oid[0]));
149 printf(" %o ", reuc->mode[1]);
150 printf(" %s\n", git_oid_allocfmt(&reuc->oid[1]));
151 printf(" %o ", reuc->mode[2]);
152 printf(" %s ", git_oid_allocfmt(&reuc->oid[2]));
153 printf("\n");
154 }
155 printf("\n");
156 }
157
158 static int index_entry_eq_merge_index_entry(const struct merge_index_entry *expected, const git_index_entry *actual)
159 {
160 git_oid expected_oid;
161 bool test_oid;
162
163 if (strlen(expected->oid_str) != 0) {
164 cl_git_pass(git_oid_fromstr(&expected_oid, expected->oid_str));
165 test_oid = 1;
166 } else
167 test_oid = 0;
168
169 if (actual->mode != expected->mode ||
170 (test_oid && git_oid_cmp(&actual->oid, &expected_oid) != 0) ||
171 git_index_entry_stage(actual) != expected->stage)
172 return 0;
173
174 if (actual->mode == 0 && (actual->path != NULL || strlen(expected->path) > 0))
175 return 0;
176
177 if (actual->mode != 0 && (strcmp(actual->path, expected->path) != 0))
178 return 0;
179
180 return 1;
181 }
182
183 static int name_entry_eq(const char *expected, const char *actual)
184 {
185 if (strlen(expected) == 0)
186 return (actual == NULL) ? 1 : 0;
187
188 return (strcmp(expected, actual) == 0) ? 1 : 0;
189 }
190
191 static int name_entry_eq_merge_name_entry(const struct merge_name_entry *expected, const git_index_name_entry *actual)
192 {
193 if (name_entry_eq(expected->ancestor_path, actual->ancestor) == 0 ||
194 name_entry_eq(expected->our_path, actual->ours) == 0 ||
195 name_entry_eq(expected->their_path, actual->theirs) == 0)
196 return 0;
197
198 return 1;
199 }
200
201 static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data *expected, git_merge_diff *actual)
202 {
203 if (!index_entry_eq_merge_index_entry(&expected->ancestor.entry, &actual->ancestor_entry) ||
204 !index_entry_eq_merge_index_entry(&expected->ours.entry, &actual->our_entry) ||
205 !index_entry_eq_merge_index_entry(&expected->theirs.entry, &actual->their_entry))
206 return 0;
207
208 if (expected->ours.status != actual->our_status ||
209 expected->theirs.status != actual->their_status)
210 return 0;
211
212 return 1;
213 }
214
215 int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len)
216 {
217 git_merge_diff *actual;
218 size_t i;
219
220 if (conflicts->length != expected_len)
221 return 0;
222
223 for (i = 0; i < expected_len; i++) {
224 actual = conflicts->contents[i];
225
226 if (!index_conflict_data_eq_merge_diff(&expected[i], actual))
227 return 0;
228 }
229
230 return 1;
231 }
232
233 int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len)
234 {
235 size_t i;
236 const git_index_entry *index_entry;
237
238 /*
239 dump_index_entries(&index->entries);
240 */
241
242 if (git_index_entrycount(index) != expected_len)
243 return 0;
244
245 for (i = 0; i < expected_len; i++) {
246 if ((index_entry = git_index_get_byindex(index, i)) == NULL)
247 return 0;
248
249 if (!index_entry_eq_merge_index_entry(&expected[i], index_entry))
250 return 0;
251 }
252
253 return 1;
254 }
255
256 int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len)
257 {
258 size_t i;
259 const git_index_name_entry *name_entry;
260
261 /*
262 dump_names(index);
263 */
264
265 if (git_index_name_entrycount(index) != expected_len)
266 return 0;
267
268 for (i = 0; i < expected_len; i++) {
269 if ((name_entry = git_index_name_get_byindex(index, i)) == NULL)
270 return 0;
271
272 if (! name_entry_eq_merge_name_entry(&expected[i], name_entry))
273 return 0;
274 }
275
276 return 1;
277 }
278
279 int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len)
280 {
281 size_t i;
282 const git_index_reuc_entry *reuc_entry;
283 git_oid expected_oid;
284
285 /*
286 dump_reuc(index);
287 */
288
289 if (git_index_reuc_entrycount(index) != expected_len)
290 return 0;
291
292 for (i = 0; i < expected_len; i++) {
293 if ((reuc_entry = git_index_reuc_get_byindex(index, i)) == NULL)
294 return 0;
295
296 if (strcmp(reuc_entry->path, expected[i].path) != 0 ||
297 reuc_entry->mode[0] != expected[i].ancestor_mode ||
298 reuc_entry->mode[1] != expected[i].our_mode ||
299 reuc_entry->mode[2] != expected[i].their_mode)
300 return 0;
301
302 if (expected[i].ancestor_mode > 0) {
303 cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].ancestor_oid_str));
304
305 if (git_oid_cmp(&reuc_entry->oid[0], &expected_oid) != 0)
306 return 0;
307 }
308
309 if (expected[i].our_mode > 0) {
310 cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].our_oid_str));
311
312 if (git_oid_cmp(&reuc_entry->oid[1], &expected_oid) != 0)
313 return 0;
314 }
315
316 if (expected[i].their_mode > 0) {
317 cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].their_oid_str));
318
319 if (git_oid_cmp(&reuc_entry->oid[2], &expected_oid) != 0)
320 return 0;
321 }
322 }
323
324 return 1;
325 }
326
327 int dircount(void *payload, git_buf *pathbuf)
328 {
329 int *entries = payload;
330 size_t len = git_buf_len(pathbuf);
331
332 if (len < 5 || strcmp(pathbuf->ptr + (git_buf_len(pathbuf) - 5), "/.git") != 0)
333 (*entries)++;
334
335 return 0;
336 }
337
338 int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len)
339 {
340 size_t actual_len = 0, i;
341 git_oid actual_oid, expected_oid;
342 git_buf wd = GIT_BUF_INIT;
343
344 git_buf_puts(&wd, repo->workdir);
345 git_path_direach(&wd, 0, dircount, &actual_len);
346
347 if (actual_len != expected_len)
348 return 0;
349
350 for (i = 0; i < expected_len; i++) {
351 git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path);
352 git_oid_fromstr(&expected_oid, expected[i].oid_str);
353
354 if (git_oid_cmp(&actual_oid, &expected_oid) != 0)
355 return 0;
356 }
357
358 git_buf_free(&wd);
359
360 return 1;
361 }