Commit fb910281 by nulltoken

branch: introduce git_branch_tracking()

parent bf9e8cc8
...@@ -136,6 +136,22 @@ GIT_EXTERN(int) git_branch_lookup( ...@@ -136,6 +136,22 @@ GIT_EXTERN(int) git_branch_lookup(
const char *branch_name, const char *branch_name,
git_branch_t branch_type); git_branch_t branch_type);
/**
* Return the reference supporting the remote tracking branch,
* given a local branch reference.
*
* @param tracking_out Pointer where to store the retrieved
* reference.
*
* @param branch Current underlying reference of the branch.
*
* @return 0 on success; GIT_ENOTFOUND when no remote tracking
* reference exists, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_tracking(
git_reference **tracking_out,
git_reference *branch);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "common.h" #include "common.h"
#include "commit.h" #include "commit.h"
#include "tag.h" #include "tag.h"
#include "config.h"
#include "refspec.h"
#include "git2/branch.h" #include "git2/branch.h"
...@@ -220,3 +222,69 @@ int git_branch_lookup( ...@@ -220,3 +222,69 @@ int git_branch_lookup(
return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE); return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
} }
int retrieve_tracking_configuration(const char **out, git_reference *branch, const char *format)
{
git_config *config;
git_buf buf = GIT_BUF_INIT;
int error;
if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
return -1;
if (git_buf_printf(&buf, format,
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
return -1;
error = git_config_get_string(out, config, git_buf_cstr(&buf));
git_buf_free(&buf);
return error;
}
int git_branch_tracking(
git_reference **tracking_out,
git_reference *branch)
{
const char *remote_name, *merge_name;
git_buf buf = GIT_BUF_INIT;
int error = -1;
git_remote *remote = NULL;
const git_refspec *refspec;
assert(tracking_out && branch);
if (!git_reference_is_branch(branch))
return not_a_local_branch(branch);
if ((error = retrieve_tracking_configuration(&remote_name, branch, "branch.%s.remote")) < 0)
goto cleanup;
if ((error = retrieve_tracking_configuration(&merge_name, branch, "branch.%s.merge")) < 0)
goto cleanup;
if (strcmp(".", remote_name) != 0) {
if ((error = git_remote_load(&remote, git_reference_owner(branch), remote_name)) < 0)
goto cleanup;
refspec = git_remote_fetchspec(remote);
if (refspec == NULL) {
error = GIT_ENOTFOUND;
goto cleanup;
}
if (git_refspec_transform_r(&buf, refspec, merge_name) < 0)
goto cleanup;
} else
if (git_buf_sets(&buf, merge_name) < 0)
goto cleanup;
error = git_reference_lookup(
tracking_out,
git_reference_owner(branch),
git_buf_cstr(&buf));
cleanup:
git_remote_free(remote);
git_buf_free(&buf);
return error;
}
...@@ -328,7 +328,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch ...@@ -328,7 +328,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch
*base_ref = NULL; *base_ref = NULL;
} }
if ((error = git_reference_remote_tracking_from_branch(&tracking, ref)) < 0) if ((error = git_branch_tracking(&tracking, ref)) < 0)
goto cleanup; goto cleanup;
*base_ref = tracking; *base_ref = tracking;
......
...@@ -107,7 +107,7 @@ void test_network_remotelocal__retrieve_advertised_references(void) ...@@ -107,7 +107,7 @@ void test_network_remotelocal__retrieve_advertised_references(void)
cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
cl_assert_equal_i(how_many_refs, 22); cl_assert_equal_i(how_many_refs, 23);
} }
void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void) void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void)
...@@ -121,7 +121,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi ...@@ -121,7 +121,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi
cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
cl_assert_equal_i(how_many_refs, 22); cl_assert_equal_i(how_many_refs, 23);
git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */ git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */
remote = NULL; remote = NULL;
......
...@@ -47,7 +47,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count) ...@@ -47,7 +47,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count)
void test_refs_branches_foreach__retrieve_all_branches(void) void test_refs_branches_foreach__retrieve_all_branches(void)
{ {
assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 10); assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 11);
} }
void test_refs_branches_foreach__retrieve_remote_branches(void) void test_refs_branches_foreach__retrieve_remote_branches(void)
...@@ -57,7 +57,7 @@ void test_refs_branches_foreach__retrieve_remote_branches(void) ...@@ -57,7 +57,7 @@ void test_refs_branches_foreach__retrieve_remote_branches(void)
void test_refs_branches_foreach__retrieve_local_branches(void) void test_refs_branches_foreach__retrieve_local_branches(void)
{ {
assert_retrieval(GIT_BRANCH_LOCAL, 8); assert_retrieval(GIT_BRANCH_LOCAL, 9);
} }
struct expectations { struct expectations {
......
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *repo;
static git_reference *branch;
void test_refs_branches_tracking__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
branch = NULL;
}
void test_refs_branches_tracking__cleanup(void)
{
git_reference_free(branch);
git_repository_free(repo);
}
void test_refs_branches_tracking__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_git_pass(git_branch_tracking(&tracking, branch));
cl_assert_equal_s("refs/remotes/test/master", git_reference_name(tracking));
git_reference_free(branch);
git_reference_free(tracking);
}
void test_refs_branches_tracking__can_retrieve_the_local_tracking_reference_of_a_local_branch(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local"));
cl_git_pass(git_branch_tracking(&tracking, branch));
cl_assert_equal_s("refs/heads/master", git_reference_name(tracking));
git_reference_free(branch);
git_reference_free(tracking);
}
void test_refs_branches_tracking__cannot_retrieve_a_remote_tracking_reference_from_a_non_branch(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b"));
cl_git_fail(git_branch_tracking(&tracking, branch));
git_reference_free(branch);
}
void test_refs_branches_tracking__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees"));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch));
git_reference_free(branch);
}
...@@ -46,7 +46,7 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_ ...@@ -46,7 +46,7 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_
void test_refs_foreachglob__retrieve_all_refs(void) void test_refs_foreachglob__retrieve_all_refs(void)
{ {
/* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */ /* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */
assert_retrieval("*", GIT_REF_LISTALL, 17); assert_retrieval("*", GIT_REF_LISTALL, 18);
} }
void test_refs_foreachglob__retrieve_remote_branches(void) void test_refs_foreachglob__retrieve_remote_branches(void)
...@@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_branches(void) ...@@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_branches(void)
void test_refs_foreachglob__retrieve_local_branches(void) void test_refs_foreachglob__retrieve_local_branches(void)
{ {
assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 8); assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 9);
} }
void test_refs_foreachglob__retrieve_partially_named_references(void) void test_refs_foreachglob__retrieve_partially_named_references(void)
......
...@@ -10,3 +10,6 @@ ...@@ -10,3 +10,6 @@
[branch "master"] [branch "master"]
remote = test remote = test
merge = refs/heads/master merge = refs/heads/master
[branch "track-local"]
remote = .
merge = refs/heads/master
9fd738e8f7967c078dceed8190330fc8648ee56a
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