diff --git a/include/git2.h b/include/git2.h index 501128c43..36f2416c0 100644 --- a/include/git2.h +++ b/include/git2.h @@ -23,6 +23,7 @@ #include "git2/repository.h" #include "git2/revwalk.h" #include "git2/merge.h" +#include "git2/graph.h" #include "git2/refs.h" #include "git2/reflog.h" #include "git2/revparse.h" diff --git a/include/git2/graph.h b/include/git2/graph.h new file mode 100644 index 000000000..c89efa6dd --- /dev/null +++ b/include/git2/graph.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * 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_graph_h__ +#define INCLUDE_git_graph_h__ + +#include "common.h" +#include "types.h" +#include "oid.h" + +/** + * @file git2/graph.h + * @brief Git graph traversal routines + * @defgroup git_revwalk Git graph traversal routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Count the number of unique commits between two commit objects + * + * @param ahead number of commits, starting at `one`, unique from commits in `two` + * @param behind number of commits, starting at `two`, unique from commits in `one` + * @param repo the repository where the commits exist + * @param one one of the commits + * @param two the other commit + */ +GIT_EXTERN(int) git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *one, const git_oid *two); + +/** @} */ +GIT_END_DECL +#endif diff --git a/include/git2/merge.h b/include/git2/merge.h index 928c4758c..59493969c 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -50,17 +50,6 @@ GIT_EXTERN(int) git_merge_base_many( const git_oid input_array[], size_t length); -/** - * Count the number of unique commits between two commit objects - * - * @param ahead number of commits, starting at `one`, unique from commits in `two` - * @param behind number of commits, starting at `two`, unique from commits in `one` - * @param repo the repository where the commits exist - * @param one one of the commits - * @param two the other commit - */ -GIT_EXTERN(int) git_count_ahead_behind(int *ahead, int *behind, git_repository *repo, git_oid *one, git_oid *two); - /** @} */ GIT_END_DECL #endif diff --git a/src/graph.c b/src/graph.c new file mode 100644 index 000000000..db4d73025 --- /dev/null +++ b/src/graph.c @@ -0,0 +1,100 @@ + +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * 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 "repository.h" +#include "revwalk.h" +#include "buffer.h" +#include "merge.h" +#include "refs.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "git2/reset.h" +#include "commit_list.h" +#include "git2/graph.h" + +static int ahead_behind(git_commit_list_node *one, git_commit_list_node *two, + size_t *ahead, size_t *behind) +{ + git_commit_list_node *commit; + git_pqueue pq; + int i; + *ahead = 0; + *behind = 0; + + if (git_pqueue_init(&pq, 2, git_commit_list_time_cmp) < 0) + return -1; + if (git_pqueue_insert(&pq, one) < 0) + return -1; + if (git_pqueue_insert(&pq, two) < 0) + return -1; + + while ((commit = git_pqueue_pop(&pq)) != NULL) { + if (commit->flags & RESULT || + (commit->flags & (PARENT1 | PARENT2)) == (PARENT1 | PARENT2)) + continue; + else if (commit->flags & PARENT1) + (*behind)++; + else if (commit->flags & PARENT2) + (*ahead)++; + + for (i = 0; i < commit->out_degree; i++) { + git_commit_list_node *p = commit->parents[i]; + if (git_pqueue_insert(&pq, p) < 0) + return -1; + } + commit->flags |= RESULT; + } + + return 0; +} + +int git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, + const git_oid *one, const git_oid *two) +{ + git_revwalk *walk; + git_vector list; + struct git_commit_list *result = NULL; + git_commit_list_node *commit1, *commit2; + void *contents[1]; + + if (git_revwalk_new(&walk, repo) < 0) + return -1; + + commit2 = commit_lookup(walk, two); + if (commit2 == NULL) + goto on_error; + + /* This is just one value, so we can do it on the stack */ + memset(&list, 0x0, sizeof(git_vector)); + contents[0] = commit2; + list.length = 1; + list.contents = contents; + + commit1 = commit_lookup(walk, one); + if (commit1 == NULL) + goto on_error; + + if (git_merge__bases_many(&result, walk, commit1, &list) < 0) + goto on_error; + if (ahead_behind(commit1, commit2, ahead, behind) < 0) + goto on_error; + + if (!result) { + git_revwalk_free(walk); + return GIT_ENOTFOUND; + } + + git_commit_list_free(&result); + git_revwalk_free(walk); + + return 0; + +on_error: + git_revwalk_free(walk); + return -1; +} diff --git a/src/merge.c b/src/merge.c index 96d2168ba..323b7b877 100644 --- a/src/merge.c +++ b/src/merge.c @@ -241,85 +241,3 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l *out = result; return 0; } - -static int count_ahead_behind(git_commit_list_node *one, git_commit_list_node *two, - int *ahead, int *behind) -{ - git_commit_list_node *commit; - git_pqueue pq; - int i; - *ahead = 0; - *behind = 0; - - if (git_pqueue_init(&pq, 2, git_commit_list_time_cmp) < 0) - return -1; - if (git_pqueue_insert(&pq, one) < 0) - return -1; - if (git_pqueue_insert(&pq, two) < 0) - return -1; - - while ((commit = git_pqueue_pop(&pq)) != NULL) { - if (commit->flags & RESULT || - (commit->flags & (PARENT1 | PARENT2)) == (PARENT1 | PARENT2)) - continue; - else if (commit->flags & PARENT1) - (*behind)++; - else if (commit->flags & PARENT2) - (*ahead)++; - - for (i = 0; i < commit->out_degree; i++) { - git_commit_list_node *p = commit->parents[i]; - if (git_pqueue_insert(&pq, p) < 0) - return -1; - } - commit->flags |= RESULT; - } - - return 0; -} - -int git_count_ahead_behind(int *ahead, int *behind, git_repository *repo, git_oid *one, - git_oid *two) -{ - git_revwalk *walk; - git_vector list; - struct git_commit_list *result = NULL; - git_commit_list_node *commit1, *commit2; - void *contents[1]; - - if (git_revwalk_new(&walk, repo) < 0) - return -1; - - commit2 = commit_lookup(walk, two); - if (commit2 == NULL) - goto on_error; - - /* This is just one value, so we can do it on the stack */ - memset(&list, 0x0, sizeof(git_vector)); - contents[0] = commit2; - list.length = 1; - list.contents = contents; - - commit1 = commit_lookup(walk, one); - if (commit1 == NULL) - goto on_error; - - if (git_merge__bases_many(&result, walk, commit1, &list) < 0) - goto on_error; - if (count_ahead_behind(commit1, commit2, ahead, behind) < 0) - goto on_error; - - if (!result) { - git_revwalk_free(walk); - return GIT_ENOTFOUND; - } - - git_commit_list_free(&result); - git_revwalk_free(walk); - - return 0; - -on_error: - git_revwalk_free(walk); - return -1; -} diff --git a/tests-clar/revwalk/mergebase.c b/tests-clar/revwalk/mergebase.c index a44e35b54..2cd18601f 100644 --- a/tests-clar/revwalk/mergebase.c +++ b/tests-clar/revwalk/mergebase.c @@ -20,7 +20,7 @@ void test_revwalk_mergebase__cleanup(void) void test_revwalk_mergebase__single1(void) { git_oid result, one, two, expected; - int ahead, behind; + size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "c47800c7266a2be04c571c04d5a6614691ea99bd ")); cl_git_pass(git_oid_fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a")); @@ -29,11 +29,11 @@ void test_revwalk_mergebase__single1(void) cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert(git_oid_cmp(&result, &expected) == 0); - cl_git_pass(git_count_ahead_behind(&ahead, &behind, _repo, &one, &two)); + cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &one, &two)); cl_assert(ahead == 2); cl_assert(behind == 1); - cl_git_pass(git_count_ahead_behind(&ahead, &behind, _repo, &two, &one)); + cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &two, &one)); cl_assert(ahead == 1); cl_assert(behind == 2); } @@ -41,7 +41,7 @@ void test_revwalk_mergebase__single1(void) void test_revwalk_mergebase__single2(void) { git_oid result, one, two, expected; - int ahead, behind; + size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_oid_fromstr(&two, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); @@ -50,11 +50,11 @@ void test_revwalk_mergebase__single2(void) cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert(git_oid_cmp(&result, &expected) == 0); - cl_git_pass(git_count_ahead_behind( &ahead, &behind, _repo, &one, &two)); + cl_git_pass(git_graph_ahead_behind( &ahead, &behind, _repo, &one, &two)); cl_assert(ahead == 4); cl_assert(behind == 1); - cl_git_pass(git_count_ahead_behind( &ahead, &behind, _repo, &two, &one)); + cl_git_pass(git_graph_ahead_behind( &ahead, &behind, _repo, &two, &one)); cl_assert(ahead == 1); cl_assert(behind == 4); } @@ -62,7 +62,7 @@ void test_revwalk_mergebase__single2(void) void test_revwalk_mergebase__merged_branch(void) { git_oid result, one, two, expected; - int ahead, behind; + size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); cl_git_pass(git_oid_fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a")); @@ -74,11 +74,11 @@ void test_revwalk_mergebase__merged_branch(void) cl_git_pass(git_merge_base(&result, _repo, &two, &one)); cl_assert(git_oid_cmp(&result, &expected) == 0); - cl_git_pass(git_count_ahead_behind(&ahead, &behind, _repo, &one, &two)); + cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &one, &two)); cl_assert(ahead == 0); cl_assert(behind == 3); - cl_git_pass(git_count_ahead_behind(&ahead, &behind, _repo, &two, &one)); + cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &two, &one)); cl_assert(ahead == 3); cl_assert(behind == 0); } @@ -86,11 +86,11 @@ void test_revwalk_mergebase__merged_branch(void) void test_revwalk_meregebase__two_way_merge(void) { git_oid one, two; - int ahead, behind; + size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "9b219343610c88a1187c996d0dc58330b55cee28")); cl_git_pass(git_oid_fromstr(&two, "a953a018c5b10b20c86e69fef55ebc8ad4c5a417")); - cl_git_pass(git_count_ahead_behind(&ahead, &behind, _repo2, &one, &two)); + cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo2, &one, &two)); cl_assert(ahead == 8); cl_assert(behind == 2); @@ -99,7 +99,7 @@ void test_revwalk_meregebase__two_way_merge(void) void test_revwalk_mergebase__no_common_ancestor_returns_ENOTFOUND(void) { git_oid result, one, two; - int ahead, behind; + size_t ahead, behind; int error; cl_git_pass(git_oid_fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af")); @@ -110,7 +110,7 @@ void test_revwalk_mergebase__no_common_ancestor_returns_ENOTFOUND(void) cl_assert_equal_i(GIT_ENOTFOUND, error); - cl_git_fail(git_count_ahead_behind(&ahead, &behind, _repo, &one, &two)); + cl_git_fail(git_graph_ahead_behind(&ahead, &behind, _repo, &one, &two)); cl_git_fail(error); cl_assert_equal_i(GIT_ENOTFOUND, error);