diff --git a/include/git2/branch.h b/include/git2/branch.h index f072799c5..f06609a51 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -148,6 +148,17 @@ GIT_EXTERN(int) git_branch_tracking( git_reference **tracking_out, git_reference *branch); +/** + * Determine if the current local branch is pointed at by HEAD. + * + * @param branch Current underlying reference of the branch. + * + * @return 1 if HEAD points at the branch, 0 if it isn't, + * error code otherwise. + */ +GIT_EXTERN(int) git_branch_is_head( + git_reference *branch); + /** @} */ GIT_END_DECL #endif diff --git a/src/branch.c b/src/branch.c index 103dfe621..3cee956f0 100644 --- a/src/branch.c +++ b/src/branch.c @@ -271,3 +271,26 @@ cleanup: git_buf_free(&buf); return error; } + +int git_branch_is_head( + git_reference *branch) +{ + git_reference *head; + bool is_same = false; + + assert(branch); + + if (!git_reference_is_branch(branch)) + return false; + + if (git_repository_head(&head, git_reference_owner(branch)) < 0) + return -1; + + is_same = strcmp( + git_reference_name(branch), + git_reference_name(head)) == 0; + + git_reference_free(head); + + return is_same; +} diff --git a/tests-clar/refs/branches/ishead.c b/tests-clar/refs/branches/ishead.c new file mode 100644 index 000000000..c40a43189 --- /dev/null +++ b/tests-clar/refs/branches/ishead.c @@ -0,0 +1,80 @@ +#include "clar_libgit2.h" +#include "refs.h" + +static git_repository *repo; +static git_reference *branch; + +void test_refs_branches_ishead__initialize(void) +{ + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); +} + +void test_refs_branches_ishead__cleanup(void) +{ + git_reference_free(branch); + git_repository_free(repo); +} + +void test_refs_branches_ishead__can_tell_if_a_branch_is_pointed_at_by_HEAD(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); + + cl_assert_equal_i(true, git_branch_is_head(branch)); +} + +void test_refs_branches_ishead__can_tell_if_a_branch_is_not_pointed_at_by_HEAD(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/br2")); + + cl_assert_equal_i(false, git_branch_is_head(branch)); +} + +void test_refs_branches_ishead__wont_be_fooled_by_a_non_branch(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b")); + + cl_assert_equal_i(false, git_branch_is_head(branch)); +} + +/* + * $ git init . + * Initialized empty Git repository in d:/temp/tempee/.git/ + * + * $ touch a && git add a + * $ git commit -m" boom" + * [master (root-commit) b47b758] boom + * 0 files changed + * create mode 100644 a + * + * $ echo "ref: refs/heads/master" > .git/refs/heads/linked + * $ echo "ref: refs/heads/linked" > .git/refs/heads/super + * $ echo "ref: refs/heads/super" > .git/HEAD + * + * $ git branch + * linked -> master + * * master + * super -> master + */ +void test_refs_branches_ishead__only_direct_references_are_considered(void) +{ + git_reference *linked, *super, *head; + + git_repository_free(repo); + repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_reference_create_symbolic(&linked, repo, "refs/heads/linked", "refs/heads/master", 0)); + cl_git_pass(git_reference_create_symbolic(&super, repo, "refs/heads/super", "refs/heads/linked", 0)); + cl_git_pass(git_reference_create_symbolic(&head, repo, GIT_HEAD_FILE, "refs/heads/super", 1)); + + cl_assert_equal_i(false, git_branch_is_head(linked)); + cl_assert_equal_i(false, git_branch_is_head(super)); + + cl_git_pass(git_repository_head(&branch, repo)); + cl_assert_equal_s("refs/heads/master", git_reference_name(branch)); + + git_reference_free(linked); + git_reference_free(super); + git_reference_free(head); + cl_git_sandbox_cleanup(); + repo = NULL; +}