From 7db0e6ee48fd68009a7e78cbcbca125d6ce9008d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 18 Jul 2014 16:00:21 +0200 Subject: merge: expose multiple merge bases We always calculate multiple merge bases, but up to now we had only exposed the "best" merge base. Introduce git_oidarray which analogously to git_strarray lets us return multiple ids. --- CHANGELOG.md | 3 +++ include/git2/merge.h | 16 ++++++++++++++ include/git2/oidarray.h | 40 +++++++++++++++++++++++++++++++++++ src/merge.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++- src/oidarray.c | 21 ++++++++++++++++++ src/oidarray.h | 18 ++++++++++++++++ tests/revwalk/mergebase.c | 18 ++++++++++++++++ 7 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 include/git2/oidarray.h create mode 100644 src/oidarray.c create mode 100644 src/oidarray.h diff --git a/CHANGELOG.md b/CHANGELOG.md index d389b2cb0..dc453f3fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,3 +39,6 @@ v0.21 + 1 * Add support for refspecs with the asterisk in the middle of a pattern. + +* Introduce git_merge_bases() and the git_oidarray type to expose all + merge bases between two commits. diff --git a/include/git2/merge.h b/include/git2/merge.h index 9eb14ccb1..bd5ebc1bd 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -10,6 +10,7 @@ #include "common.h" #include "types.h" #include "oid.h" +#include "oidarray.h" #include "checkout.h" #include "index.h" @@ -320,6 +321,21 @@ GIT_EXTERN(int) git_merge_base( const git_oid *one, const git_oid *two); +/** + * Find merge bases between two commits + * + * @param out array in which to store the resulting ids + * @param repo the repository where the commits exist + * @param one one of the commits + * @param two the other commit + * @return 0 on success, GIT_ENOTFOUND if not found or error code + */ +GIT_EXTERN(int) git_merge_bases( + git_oidarray *out, + git_repository *repo, + const git_oid *one, + const git_oid *two); + /** * Find a merge base given a list of commits * diff --git a/include/git2/oidarray.h b/include/git2/oidarray.h new file mode 100644 index 000000000..0b3204597 --- /dev/null +++ b/include/git2/oidarray.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_oidarray_h__ +#define INCLUDE_git_oidarray_h__ + +#include "common.h" +#include "oid.h" + +GIT_BEGIN_DECL + +/** Array of object ids */ +typedef struct git_oidarray { + git_oid *ids; + size_t count; +} git_oidarray; + +/** + * Free the OID array + * + * This method must (and must only) be called on `git_oidarray` + * objects where the array is allocated by the library. Not doing so, + * will result in a memory leak. + * + * This does not free the `git_oidarray` itself, since the library will + * never allocate that object directly itself (it is more commonly embedded + * inside another struct or created on the stack). + * + * @param array git_oidarray from which to free oid data + */ +GIT_EXTERN(void) git_oidarray_free(git_oidarray *array); + +/** @} */ +GIT_END_DECL + +#endif + diff --git a/src/merge.c b/src/merge.c index f8d008a6d..14b5b5c8e 100644 --- a/src/merge.c +++ b/src/merge.c @@ -27,6 +27,7 @@ #include "index.h" #include "filebuf.h" #include "config.h" +#include "oidarray.h" #include "git2/types.h" #include "git2/repository.h" @@ -39,6 +40,7 @@ #include "git2/signature.h" #include "git2/config.h" #include "git2/tree.h" +#include "git2/oidarray.h" #include "git2/sys/index.h" #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) @@ -139,7 +141,7 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co return 0; } -int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two) +static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, const git_oid *one, const git_oid *two) { git_revwalk *walk; git_vector list; @@ -173,13 +175,63 @@ int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const return GIT_ENOTFOUND; } + *out = result; + *walk_out = walk; + + return 0; + +on_error: + git_revwalk_free(walk); + return -1; + +} + +int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two) +{ + int error; + git_revwalk *walk; + git_commit_list *result; + + if ((error = merge_bases(&result, &walk, repo, one, two)) < 0) + return error; + git_oid_cpy(out, &result->item->oid); git_commit_list_free(&result); git_revwalk_free(walk); + return 0; +} + +int git_merge_bases(git_oidarray *out, git_repository *repo, const git_oid *one, const git_oid *two) +{ + int error; + git_revwalk *walk; + git_commit_list *result, *list; + git_array_oid_t array; + + git_array_init(array); + + if ((error = merge_bases(&result, &walk, repo, one, two)) < 0) + return error; + + list = result; + while (list) { + git_oid *id = git_array_alloc(array); + if (id == NULL) + goto on_error; + + git_oid_cpy(id, &list->item->oid); + list = list->next; + } + + git_oidarray__from_array(out, &array); + git_commit_list_free(&result); + git_revwalk_free(walk); + return 0; on_error: + git_commit_list_free(&result); git_revwalk_free(walk); return -1; } diff --git a/src/oidarray.c b/src/oidarray.c new file mode 100644 index 000000000..1d51a2958 --- /dev/null +++ b/src/oidarray.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2/oidarray.h" +#include "oidarray.h" +#include "array.h" + +void git_oidarray_free(git_oidarray *arr) +{ + git__free(arr->ids); +} + +void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array) +{ + arr->count = array->size; + arr->ids = array->ptr; +} diff --git a/src/oidarray.h b/src/oidarray.h new file mode 100644 index 000000000..a7215ae6c --- /dev/null +++ b/src/oidarray.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_oidarray_h__ +#define INCLUDE_oidarray_h__ + +#include "common.h" +#include "git2/oidarray.h" +#include "array.h" + +typedef git_array_t(git_oid) git_array_oid_t; + +extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array); + +#endif diff --git a/tests/revwalk/mergebase.c b/tests/revwalk/mergebase.c index 2c7184fc7..e12e59762 100644 --- a/tests/revwalk/mergebase.c +++ b/tests/revwalk/mergebase.c @@ -135,6 +135,24 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void) cl_assert_equal_oid(&expected, &result); } +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(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_oid_fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); + cl_git_pass(git_oid_fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a")); + + cl_git_pass(git_merge_bases(&result, _repo, &one, &two)); + 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; -- cgit v1.2.1