From eca07bcd83ae7aa18230779be1bc73d150da8af2 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Thu, 9 Oct 2014 13:58:23 +0200 Subject: [PATCH] Add git_merge_bases_many. --- CHANGELOG.md | 3 ++ include/git2/merge.h | 15 +++++++++ src/merge.c | 67 +++++++++++++++++++++++++++++++++++++++ tests/revwalk/mergebase.c | 24 ++++++++++++-- 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b23e07d93..6ea198407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,3 +58,6 @@ v0.21 + 1 * Introduce git_merge_bases() and the git_oidarray type to expose all merge bases between two commits. + +* Introduce git_merge_bases_many() to expose all merge bases between + multiple commits. diff --git a/include/git2/merge.h b/include/git2/merge.h index bd5ebc1bd..ed1b9a30f 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -351,6 +351,21 @@ GIT_EXTERN(int) git_merge_base_many( size_t length, const git_oid input_array[]); +/** + * Find all merge bases given a list of commits + * + * @param out array in which to store the resulting ids + * @param repo the repository where the commits exist + * @param length The number of commits in the provided `input_array` + * @param input_array oids of the commits + * @return Zero on success; GIT_ENOTFOUND or -1 on failure. + */ +GIT_EXTERN(int) git_merge_bases_many( + git_oidarray *out, + git_repository *repo, + size_t length, + const git_oid input_array[]); + /** * Find a merge base in preparation for an octopus merge * diff --git a/src/merge.c b/src/merge.c index 1e72520a4..c7ca97c12 100644 --- a/src/merge.c +++ b/src/merge.c @@ -116,6 +116,73 @@ cleanup: return error; } +int git_merge_bases_many(git_oidarray *out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_revwalk *walk; + git_vector list; + git_commit_list *current, *result = NULL; + int error = -1; + unsigned int i; + git_commit_list_node *commit; + git_array_oid_t array; + + assert(out && repo && input_array); + + if (length < 2) { + giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length); + return -1; + } + + if (git_vector_init(&list, length - 1, NULL) < 0) + return -1; + + if (git_revwalk_new(&walk, repo) < 0) + goto cleanup; + + for (i = 1; i < length; i++) { + commit = git_revwalk__commit_lookup(walk, &input_array[i]); + if (commit == NULL) + goto cleanup; + + git_vector_insert(&list, commit); + } + + commit = git_revwalk__commit_lookup(walk, &input_array[0]); + if (commit == NULL) + goto cleanup; + + if (git_merge__bases_many(&result, walk, commit, &list) < 0) + goto cleanup; + + if (!result) { + giterr_set(GITERR_MERGE, "No merge base found"); + error = GIT_ENOTFOUND; + goto cleanup; + } + + git_array_init(array); + + current = result; + while (current) { + git_oid *id = git_array_alloc(array); + if (id == NULL) + goto cleanup; + + git_oid_cpy(id, ¤t->item->oid); + current = current->next; + } + + git_oidarray__from_array(out, &array); + + error = 0; + +cleanup: + git_commit_list_free(&result); + git_revwalk_free(walk); + git_vector_free(&list); + return error; +} + int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) { git_oid result; diff --git a/tests/revwalk/mergebase.c b/tests/revwalk/mergebase.c index 677e1a1b6..fa974eb9a 100644 --- a/tests/revwalk/mergebase.c +++ b/tests/revwalk/mergebase.c @@ -127,7 +127,7 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void) { git_oid result, one, two, expected; - cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f ")); + cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f")); cl_git_pass(git_oid_fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_oid_fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd")); @@ -140,7 +140,7 @@ void test_revwalk_mergebase__multiple_merge_bases(void) git_oid one, two, expected1, expected2; git_oidarray result = {NULL, 0}; - cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f ")); + cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f")); cl_git_pass(git_oid_fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_oid_fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_oid_fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a")); @@ -153,6 +153,26 @@ void test_revwalk_mergebase__multiple_merge_bases(void) git_oidarray_free(&result); } +void test_revwalk_mergebase__multiple_merge_bases_many_commits(void) +{ + git_oid expected1, expected2; + git_oidarray result = {NULL, 0}; + + git_oid *input = git__malloc(sizeof(git_oid) * 2); + + cl_git_pass(git_oid_fromstr(&input[0], "a4a7dce85cf63874e984719f4fdd239f5145052f")); + cl_git_pass(git_oid_fromstr(&input[1], "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_oid_fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); + cl_git_pass(git_oid_fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a")); + + cl_git_pass(git_merge_bases_many(&result, _repo, 2, input)); + cl_assert_equal_i(2, result.count); + cl_assert_equal_oid(&expected1, &result.ids[0]); + cl_assert_equal_oid(&expected2, &result.ids[1]); + + git_oidarray_free(&result); +} + void test_revwalk_mergebase__no_off_by_one_missing(void) { git_oid result, one, two;