Add `git_graph_descendant_of`.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
diff --git a/include/git2/graph.h b/include/git2/graph.h
index a271021..c997d8c 100644
--- a/include/git2/graph.h
+++ b/include/git2/graph.h
@@ -36,6 +36,20 @@ GIT_BEGIN_DECL
*/
GIT_EXTERN(int) git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream);
+
+/**
+ * Determine if a commit is the descendant of another commit.
+ *
+ * @param commit a previously loaded commit.
+ * @param ancestor a potential ancestor commit.
+ * @return 1 if the given commit is a descendant of the potential ancestor,
+ * 0 if not, error code otherwise.
+ */
+GIT_EXTERN(int) git_graph_descendant_of(
+ git_repository *repo,
+ const git_oid *commit,
+ const git_oid *ancestor);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/graph.c b/src/graph.c
index 277f588..f39af5e 100644
--- a/src/graph.c
+++ b/src/graph.c
@@ -176,3 +176,17 @@ on_error:
git_revwalk_free(walk);
return -1;
}
+
+int git_graph_descendant_of(git_repository *repo, const git_oid *commit, const git_oid *ancestor)
+{
+ git_oid merge_base;
+ int error;
+
+ if (git_oid_equal(commit, ancestor))
+ return 0;
+
+ if ((error = git_merge_base(&merge_base, repo, commit, ancestor) < 0))
+ return error;
+
+ return git_oid_equal(&merge_base, ancestor);
+}
diff --git a/tests/graph/descendant_of.c b/tests/graph/descendant_of.c
new file mode 100644
index 0000000..ffdd0cf
--- /dev/null
+++ b/tests/graph/descendant_of.c
@@ -0,0 +1,47 @@
+#include "clar_libgit2.h"
+
+static git_repository *_repo;
+static git_commit *commit;
+
+void test_graph_descendant_of__initialize(void)
+{
+ git_oid oid;
+
+ cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git")));
+
+ git_oid_fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
+ cl_git_pass(git_commit_lookup(&commit, _repo, &oid));
+}
+
+void test_graph_descendant_of__cleanup(void)
+{
+ git_commit_free(commit);
+ commit = NULL;
+
+ git_repository_free(_repo);
+ _repo = NULL;
+}
+
+void test_graph_descendant_of__returns_correct_result(void)
+{
+ git_commit *other;
+
+ cl_assert_equal_i(0, git_graph_descendant_of(_repo, git_commit_id(commit), git_commit_id(commit)));
+
+
+ cl_git_pass(git_commit_nth_gen_ancestor(&other, commit, 1));
+
+ cl_assert_equal_i(1, git_graph_descendant_of(_repo, git_commit_id(commit), git_commit_id(other)));
+ cl_assert_equal_i(0, git_graph_descendant_of(_repo, git_commit_id(other), git_commit_id(commit)));
+
+ git_commit_free(other);
+
+
+ cl_git_pass(git_commit_nth_gen_ancestor(&other, commit, 3));
+
+ cl_assert_equal_i(1, git_graph_descendant_of(_repo, git_commit_id(commit), git_commit_id(other)));
+ cl_assert_equal_i(0, git_graph_descendant_of(_repo, git_commit_id(other), git_commit_id(commit)));
+
+ git_commit_free(other);
+
+}