1 #include "clar_libgit2.h"
5 #include "merge_helpers.h"
8 #include "git2/merge.h"
9 #include "git2/sys/index.h"
10 #include "git2/annotated_commit.h"
12 int merge_trees_from_branches(
13 git_index
**index
, git_repository
*repo
,
14 const char *ours_name
, const char *theirs_name
,
15 git_merge_options
*opts
)
17 git_commit
*our_commit
, *their_commit
, *ancestor_commit
= NULL
;
18 git_tree
*our_tree
, *their_tree
, *ancestor_tree
= NULL
;
19 git_oid our_oid
, their_oid
, ancestor_oid
;
20 git_buf branch_buf
= GIT_BUF_INIT
;
23 git_buf_printf(&branch_buf
, "%s%s", GIT_REFS_HEADS_DIR
, ours_name
);
24 cl_git_pass(git_reference_name_to_id(&our_oid
, repo
, branch_buf
.ptr
));
25 cl_git_pass(git_commit_lookup(&our_commit
, repo
, &our_oid
));
27 git_buf_clear(&branch_buf
);
28 git_buf_printf(&branch_buf
, "%s%s", GIT_REFS_HEADS_DIR
, theirs_name
);
29 cl_git_pass(git_reference_name_to_id(&their_oid
, repo
, branch_buf
.ptr
));
30 cl_git_pass(git_commit_lookup(&their_commit
, repo
, &their_oid
));
32 error
= git_merge_base(&ancestor_oid
, repo
, git_commit_id(our_commit
), git_commit_id(their_commit
));
34 if (error
!= GIT_ENOTFOUND
) {
37 cl_git_pass(git_commit_lookup(&ancestor_commit
, repo
, &ancestor_oid
));
38 cl_git_pass(git_commit_tree(&ancestor_tree
, ancestor_commit
));
41 cl_git_pass(git_commit_tree(&our_tree
, our_commit
));
42 cl_git_pass(git_commit_tree(&their_tree
, their_commit
));
44 error
= git_merge_trees(index
, repo
, ancestor_tree
, our_tree
, their_tree
, opts
);
46 git_buf_dispose(&branch_buf
);
47 git_tree_free(our_tree
);
48 git_tree_free(their_tree
);
49 git_tree_free(ancestor_tree
);
50 git_commit_free(our_commit
);
51 git_commit_free(their_commit
);
52 git_commit_free(ancestor_commit
);
57 int merge_commits_from_branches(
58 git_index
**index
, git_repository
*repo
,
59 const char *ours_name
, const char *theirs_name
,
60 git_merge_options
*opts
)
62 git_commit
*our_commit
, *their_commit
;
63 git_oid our_oid
, their_oid
;
64 git_buf branch_buf
= GIT_BUF_INIT
;
67 git_buf_printf(&branch_buf
, "%s%s", GIT_REFS_HEADS_DIR
, ours_name
);
68 cl_git_pass(git_reference_name_to_id(&our_oid
, repo
, branch_buf
.ptr
));
69 cl_git_pass(git_commit_lookup(&our_commit
, repo
, &our_oid
));
71 git_buf_clear(&branch_buf
);
72 git_buf_printf(&branch_buf
, "%s%s", GIT_REFS_HEADS_DIR
, theirs_name
);
73 cl_git_pass(git_reference_name_to_id(&their_oid
, repo
, branch_buf
.ptr
));
74 cl_git_pass(git_commit_lookup(&their_commit
, repo
, &their_oid
));
76 error
= git_merge_commits(index
, repo
, our_commit
, their_commit
, opts
);
78 git_buf_dispose(&branch_buf
);
79 git_commit_free(our_commit
);
80 git_commit_free(their_commit
);
85 int merge_branches(git_repository
*repo
,
86 const char *ours_branch
, const char *theirs_branch
,
87 git_merge_options
*merge_opts
, git_checkout_options
*checkout_opts
)
89 git_reference
*head_ref
, *theirs_ref
;
90 git_annotated_commit
*theirs_head
;
91 git_checkout_options head_checkout_opts
= GIT_CHECKOUT_OPTIONS_INIT
;
93 head_checkout_opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
95 cl_git_pass(git_reference_symbolic_create(&head_ref
, repo
, "HEAD", ours_branch
, 1, NULL
));
96 cl_git_pass(git_checkout_head(repo
, &head_checkout_opts
));
98 cl_git_pass(git_reference_lookup(&theirs_ref
, repo
, theirs_branch
));
99 cl_git_pass(git_annotated_commit_from_ref(&theirs_head
, repo
, theirs_ref
));
101 cl_git_pass(git_merge(repo
, (const git_annotated_commit
**)&theirs_head
, 1, merge_opts
, checkout_opts
));
103 git_reference_free(head_ref
);
104 git_reference_free(theirs_ref
);
105 git_annotated_commit_free(theirs_head
);
110 void merge__dump_index_entries(git_vector
*index_entries
)
113 const git_index_entry
*index_entry
;
115 printf ("\nINDEX [%"PRIuZ
"]:\n", index_entries
->length
);
116 for (i
= 0; i
< index_entries
->length
; i
++) {
117 index_entry
= index_entries
->contents
[i
];
119 printf("%o ", index_entry
->mode
);
120 printf("%s ", git_oid_allocfmt(&index_entry
->id
));
121 printf("%d ", git_index_entry_stage(index_entry
));
122 printf("%s ", index_entry
->path
);
128 void merge__dump_names(git_index
*index
)
131 const git_index_name_entry
*conflict_name
;
133 for (i
= 0; i
< git_index_name_entrycount(index
); i
++) {
134 conflict_name
= git_index_name_get_byindex(index
, i
);
136 printf("%s %s %s\n", conflict_name
->ancestor
, conflict_name
->ours
, conflict_name
->theirs
);
141 void merge__dump_reuc(git_index
*index
)
144 const git_index_reuc_entry
*reuc
;
146 printf ("\nREUC:\n");
147 for (i
= 0; i
< git_index_reuc_entrycount(index
); i
++) {
148 reuc
= git_index_reuc_get_byindex(index
, i
);
150 printf("%s ", reuc
->path
);
151 printf("%o ", reuc
->mode
[0]);
152 printf("%s\n", git_oid_allocfmt(&reuc
->oid
[0]));
153 printf(" %o ", reuc
->mode
[1]);
154 printf(" %s\n", git_oid_allocfmt(&reuc
->oid
[1]));
155 printf(" %o ", reuc
->mode
[2]);
156 printf(" %s ", git_oid_allocfmt(&reuc
->oid
[2]));
162 static int index_entry_eq_merge_index_entry(const struct merge_index_entry
*expected
, const git_index_entry
*actual
)
164 git_oid expected_oid
;
167 if (strlen(expected
->oid_str
) != 0) {
168 cl_git_pass(git_oid_fromstr(&expected_oid
, expected
->oid_str
));
173 if (actual
->mode
!= expected
->mode
||
174 (test_oid
&& git_oid_cmp(&actual
->id
, &expected_oid
) != 0) ||
175 git_index_entry_stage(actual
) != expected
->stage
)
178 if (actual
->mode
== 0 && (actual
->path
!= NULL
|| strlen(expected
->path
) > 0))
181 if (actual
->mode
!= 0 && (strcmp(actual
->path
, expected
->path
) != 0))
187 static int name_entry_eq(const char *expected
, const char *actual
)
189 if (strlen(expected
) == 0)
190 return (actual
== NULL
) ? 1 : 0;
192 return (strcmp(expected
, actual
) == 0) ? 1 : 0;
195 static int name_entry_eq_merge_name_entry(const struct merge_name_entry
*expected
, const git_index_name_entry
*actual
)
197 if (name_entry_eq(expected
->ancestor_path
, actual
->ancestor
) == 0 ||
198 name_entry_eq(expected
->our_path
, actual
->ours
) == 0 ||
199 name_entry_eq(expected
->their_path
, actual
->theirs
) == 0)
205 static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data
*expected
, git_merge_diff
*actual
)
207 if (!index_entry_eq_merge_index_entry(&expected
->ancestor
.entry
, &actual
->ancestor_entry
) ||
208 !index_entry_eq_merge_index_entry(&expected
->ours
.entry
, &actual
->our_entry
) ||
209 !index_entry_eq_merge_index_entry(&expected
->theirs
.entry
, &actual
->their_entry
))
212 if (expected
->ours
.status
!= actual
->our_status
||
213 expected
->theirs
.status
!= actual
->their_status
)
219 int merge_test_merge_conflicts(git_vector
*conflicts
, const struct merge_index_conflict_data expected
[], size_t expected_len
)
221 git_merge_diff
*actual
;
224 if (conflicts
->length
!= expected_len
)
227 for (i
= 0; i
< expected_len
; i
++) {
228 actual
= conflicts
->contents
[i
];
230 if (!index_conflict_data_eq_merge_diff(&expected
[i
], actual
))
237 int merge_test_index(git_index
*index
, const struct merge_index_entry expected
[], size_t expected_len
)
240 const git_index_entry
*index_entry
;
243 merge__dump_index_entries(&index->entries);
246 if (git_index_entrycount(index
) != expected_len
)
249 for (i
= 0; i
< expected_len
; i
++) {
250 if ((index_entry
= git_index_get_byindex(index
, i
)) == NULL
)
253 if (!index_entry_eq_merge_index_entry(&expected
[i
], index_entry
))
260 int merge_test_names(git_index
*index
, const struct merge_name_entry expected
[], size_t expected_len
)
263 const git_index_name_entry
*name_entry
;
269 if (git_index_name_entrycount(index
) != expected_len
)
272 for (i
= 0; i
< expected_len
; i
++) {
273 if ((name_entry
= git_index_name_get_byindex(index
, i
)) == NULL
)
276 if (! name_entry_eq_merge_name_entry(&expected
[i
], name_entry
))
283 int merge_test_reuc(git_index
*index
, const struct merge_reuc_entry expected
[], size_t expected_len
)
286 const git_index_reuc_entry
*reuc_entry
;
287 git_oid expected_oid
;
293 if (git_index_reuc_entrycount(index
) != expected_len
)
296 for (i
= 0; i
< expected_len
; i
++) {
297 if ((reuc_entry
= git_index_reuc_get_byindex(index
, i
)) == NULL
)
300 if (strcmp(reuc_entry
->path
, expected
[i
].path
) != 0 ||
301 reuc_entry
->mode
[0] != expected
[i
].ancestor_mode
||
302 reuc_entry
->mode
[1] != expected
[i
].our_mode
||
303 reuc_entry
->mode
[2] != expected
[i
].their_mode
)
306 if (expected
[i
].ancestor_mode
> 0) {
307 cl_git_pass(git_oid_fromstr(&expected_oid
, expected
[i
].ancestor_oid_str
));
309 if (git_oid_cmp(&reuc_entry
->oid
[0], &expected_oid
) != 0)
313 if (expected
[i
].our_mode
> 0) {
314 cl_git_pass(git_oid_fromstr(&expected_oid
, expected
[i
].our_oid_str
));
316 if (git_oid_cmp(&reuc_entry
->oid
[1], &expected_oid
) != 0)
320 if (expected
[i
].their_mode
> 0) {
321 cl_git_pass(git_oid_fromstr(&expected_oid
, expected
[i
].their_oid_str
));
323 if (git_oid_cmp(&reuc_entry
->oid
[2], &expected_oid
) != 0)
331 int dircount(void *payload
, git_buf
*pathbuf
)
333 size_t *entries
= payload
;
334 size_t len
= git_buf_len(pathbuf
);
336 if (len
< 5 || strcmp(pathbuf
->ptr
+ (git_buf_len(pathbuf
) - 5), "/.git") != 0)
342 int merge_test_workdir(git_repository
*repo
, const struct merge_index_entry expected
[], size_t expected_len
)
344 size_t actual_len
= 0, i
;
345 git_oid actual_oid
, expected_oid
;
346 git_buf wd
= GIT_BUF_INIT
;
348 git_buf_puts(&wd
, repo
->workdir
);
349 git_path_direach(&wd
, 0, dircount
, &actual_len
);
351 if (actual_len
!= expected_len
)
354 for (i
= 0; i
< expected_len
; i
++) {
355 git_blob_create_from_workdir(&actual_oid
, repo
, expected
[i
].path
);
356 git_oid_fromstr(&expected_oid
, expected
[i
].oid_str
);
358 if (git_oid_cmp(&actual_oid
, &expected_oid
) != 0)
362 git_buf_dispose(&wd
);