Commit 7db0e6ee by Carlos Martín Nieto

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.
parent 091165c5
...@@ -39,3 +39,6 @@ v0.21 + 1 ...@@ -39,3 +39,6 @@ v0.21 + 1
* Add support for refspecs with the asterisk in the middle of a * Add support for refspecs with the asterisk in the middle of a
pattern. pattern.
* Introduce git_merge_bases() and the git_oidarray type to expose all
merge bases between two commits.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "common.h" #include "common.h"
#include "types.h" #include "types.h"
#include "oid.h" #include "oid.h"
#include "oidarray.h"
#include "checkout.h" #include "checkout.h"
#include "index.h" #include "index.h"
...@@ -321,6 +322,21 @@ GIT_EXTERN(int) git_merge_base( ...@@ -321,6 +322,21 @@ GIT_EXTERN(int) git_merge_base(
const git_oid *two); 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 * Find a merge base given a list of commits
* *
* @param out the OID of a merge base considering all the commits * @param out the OID of a merge base considering all the commits
......
/*
* 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
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "index.h" #include "index.h"
#include "filebuf.h" #include "filebuf.h"
#include "config.h" #include "config.h"
#include "oidarray.h"
#include "git2/types.h" #include "git2/types.h"
#include "git2/repository.h" #include "git2/repository.h"
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
#include "git2/signature.h" #include "git2/signature.h"
#include "git2/config.h" #include "git2/config.h"
#include "git2/tree.h" #include "git2/tree.h"
#include "git2/oidarray.h"
#include "git2/sys/index.h" #include "git2/sys/index.h"
#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) #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 ...@@ -139,7 +141,7 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co
return 0; 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_revwalk *walk;
git_vector list; git_vector list;
...@@ -173,13 +175,63 @@ int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const ...@@ -173,13 +175,63 @@ int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const
return GIT_ENOTFOUND; 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_oid_cpy(out, &result->item->oid);
git_commit_list_free(&result); git_commit_list_free(&result);
git_revwalk_free(walk); git_revwalk_free(walk);
return 0; 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: on_error:
git_commit_list_free(&result);
git_revwalk_free(walk); git_revwalk_free(walk);
return -1; return -1;
} }
......
/*
* 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;
}
/*
* 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
...@@ -135,6 +135,24 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void) ...@@ -135,6 +135,24 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void)
cl_assert_equal_oid(&expected, &result); 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) void test_revwalk_mergebase__no_off_by_one_missing(void)
{ {
git_oid result, one, two; git_oid result, one, two;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment