Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5b9c63c

Browse files
ethomsonEdward Thomson
authored and
Edward Thomson
committed
recursive merge: add a recursion limit
1 parent 78859c6 commit 5b9c63c

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

include/git2/merge.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ typedef struct {
265265
/** Pluggable similarity metric; pass NULL to use internal metric */
266266
git_diff_similarity_metric *metric;
267267

268+
/**
269+
* Maximum number of times to merge common ancestors to build a
270+
* virtual merge base when faced with criss-cross merges. When this
271+
* limit is reached, the next ancestor will simply be used instead of
272+
* attempting to merge it. The default is unlimited.
273+
*/
274+
unsigned int recursion_limit;
275+
268276
/** Flags for handling conflicting content. */
269277
git_merge_file_favor_t file_favor;
270278

src/merge.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,33 +2019,40 @@ static int compute_base(
20192019
git_repository *repo,
20202020
const git_annotated_commit *one,
20212021
const git_annotated_commit *two,
2022-
const git_merge_options *opts,
2022+
const git_merge_options *given_opts,
20232023
size_t recursion_level)
20242024
{
20252025
git_array_oid_t head_ids = GIT_ARRAY_INIT;
20262026
git_oidarray bases = {0};
20272027
git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL;
2028+
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
20282029
size_t i;
20292030
int error;
20302031

20312032
*out = NULL;
20322033

2034+
if (given_opts)
2035+
memcpy(&opts, given_opts, sizeof(git_merge_options));
2036+
20332037
if ((error = insert_head_ids(&head_ids, one)) < 0 ||
20342038
(error = insert_head_ids(&head_ids, two)) < 0)
20352039
goto done;
20362040

20372041
if ((error = git_merge_bases_many(&bases, repo,
20382042
head_ids.size, head_ids.ptr)) < 0 ||
20392043
(error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0 ||
2040-
(opts && (opts->flags & GIT_MERGE_NO_RECURSIVE)))
2044+
(opts.flags & GIT_MERGE_NO_RECURSIVE))
20412045
goto done;
20422046

20432047
for (i = 1; i < bases.count; i++) {
20442048
recursion_level++;
20452049

2050+
if (opts.recursion_limit && recursion_level > opts.recursion_limit)
2051+
break;
2052+
20462053
if ((error = git_annotated_commit_lookup(&other, repo,
20472054
&bases.ids[i])) < 0 ||
2048-
(error = create_virtual_base(&new_base, repo, base, other, opts,
2055+
(error = create_virtual_base(&new_base, repo, base, other, &opts,
20492056
recursion_level)) < 0)
20502057
goto done;
20512058

tests/merge/trees/recursive.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,34 @@ void test_merge_trees_recursive__conflicting_merge_base_since_resolved(void)
377377

378378
git_index_free(index);
379379
}
380+
381+
/* There are multiple levels of criss-cross merges, and multiple recursive
382+
* merges would create a common ancestor that allows the merge to complete
383+
* successfully. Test that we can build a single virtual base, then stop,
384+
* which will produce a conflicting merge.
385+
*/
386+
void test_merge_trees_recursive__recursionlimit(void)
387+
{
388+
git_index *index;
389+
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
390+
391+
struct merge_index_entry merge_index_entries[] = {
392+
{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
393+
{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
394+
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
395+
{ 0100644, "ce7e553c6feb6e5f3bd67e3c3be04182fe3094b4", 1, "gravy.txt" },
396+
{ 0100644, "d8dd349b78f19a4ebe3357bacb8138f00bf5ed41", 2, "gravy.txt" },
397+
{ 0100644, "e50fbbd701458757bdfe9815f58ed717c588d1b5", 3, "gravy.txt" },
398+
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
399+
{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
400+
};
401+
402+
opts.recursion_limit = 1;
403+
404+
cl_git_pass(merge_commits_from_branches(&index, repo, "branchE-1", "branchE-2", &opts));
405+
406+
cl_assert(merge_test_index(index, merge_index_entries, 8));
407+
408+
git_index_free(index);
409+
}
410+

0 commit comments

Comments
 (0)