summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-07-18 16:00:21 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-07-27 17:17:22 +0200
commit7db0e6ee48fd68009a7e78cbcbca125d6ce9008d (patch)
treec8d053d8dd5eccf98811ab80a2cc6c6be44a57e7
parent091165c53b2bcd5d41fb71d43ed5a23a3d96bf5d (diff)
downloadlibgit2-cmn/oidarray.tar.gz
merge: expose multiple merge basescmn/oidarray
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.
-rw-r--r--CHANGELOG.md3
-rw-r--r--include/git2/merge.h16
-rw-r--r--include/git2/oidarray.h40
-rw-r--r--src/merge.c54
-rw-r--r--src/oidarray.c21
-rw-r--r--src/oidarray.h18
-rw-r--r--tests/revwalk/mergebase.c18
7 files changed, 169 insertions, 1 deletions
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"
@@ -321,6 +322,21 @@ GIT_EXTERN(int) git_merge_base(
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
*
* @param out the OID of a merge base considering all the 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;