summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornulltoken <emeric.fermas@gmail.com>2012-07-20 16:38:54 +0200
committernulltoken <emeric.fermas@gmail.com>2012-07-24 16:09:48 +0200
commitfb910281d6598e2c235f6ec93384d4e08838d655 (patch)
tree03b18d2edfc6abfff5512b2e7b15b15bfbd44950
parentbf9e8cc86b9c32946a395fd12a9b1a5cb71575a9 (diff)
downloadlibgit2-fb910281d6598e2c235f6ec93384d4e08838d655.tar.gz
branch: introduce git_branch_tracking()
-rw-r--r--include/git2/branch.h16
-rw-r--r--src/branch.c68
-rw-r--r--src/revparse.c2
-rw-r--r--tests-clar/network/remotelocal.c4
-rw-r--r--tests-clar/refs/branches/foreach.c4
-rw-r--r--tests-clar/refs/branches/tracking.c69
-rw-r--r--tests-clar/refs/foreachglob.c4
-rw-r--r--tests-clar/resources/testrepo.git/config3
-rw-r--r--tests-clar/resources/testrepo.git/refs/heads/track-local1
9 files changed, 164 insertions, 7 deletions
diff --git a/include/git2/branch.h b/include/git2/branch.h
index 724cfba12..15894b709 100644
--- a/include/git2/branch.h
+++ b/include/git2/branch.h
@@ -136,6 +136,22 @@ GIT_EXTERN(int) git_branch_lookup(
const char *branch_name,
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
#endif
diff --git a/src/branch.c b/src/branch.c
index 4a56fd1b9..d0ebb2dc3 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -8,6 +8,8 @@
#include "common.h"
#include "commit.h"
#include "tag.h"
+#include "config.h"
+#include "refspec.h"
#include "git2/branch.h"
@@ -220,3 +222,69 @@ int git_branch_lookup(
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;
+}
diff --git a/src/revparse.c b/src/revparse.c
index b0469286b..e2c0de612 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -328,7 +328,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch
*base_ref = NULL;
}
- if ((error = git_reference_remote_tracking_from_branch(&tracking, ref)) < 0)
+ if ((error = git_branch_tracking(&tracking, ref)) < 0)
goto cleanup;
*base_ref = tracking;
diff --git a/tests-clar/network/remotelocal.c b/tests-clar/network/remotelocal.c
index 5e20b4240..16e3fe2dd 100644
--- a/tests-clar/network/remotelocal.c
+++ b/tests-clar/network/remotelocal.c
@@ -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_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)
@@ -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_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 */
remote = NULL;
diff --git a/tests-clar/refs/branches/foreach.c b/tests-clar/refs/branches/foreach.c
index 185ca36ba..794233cc9 100644
--- a/tests-clar/refs/branches/foreach.c
+++ b/tests-clar/refs/branches/foreach.c
@@ -47,7 +47,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count)
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)
@@ -57,7 +57,7 @@ void test_refs_branches_foreach__retrieve_remote_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 {
diff --git a/tests-clar/refs/branches/tracking.c b/tests-clar/refs/branches/tracking.c
new file mode 100644
index 000000000..8f7019437
--- /dev/null
+++ b/tests-clar/refs/branches/tracking.c
@@ -0,0 +1,69 @@
+#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);
+}
diff --git a/tests-clar/refs/foreachglob.c b/tests-clar/refs/foreachglob.c
index d1412a94b..b024d36d4 100644
--- a/tests-clar/refs/foreachglob.c
+++ b/tests-clar/refs/foreachglob.c
@@ -46,7 +46,7 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_
void test_refs_foreachglob__retrieve_all_refs(void)
{
/* 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)
@@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_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)
diff --git a/tests-clar/resources/testrepo.git/config b/tests-clar/resources/testrepo.git/config
index b4fdac6c2..6b03dacb5 100644
--- a/tests-clar/resources/testrepo.git/config
+++ b/tests-clar/resources/testrepo.git/config
@@ -10,3 +10,6 @@
[branch "master"]
remote = test
merge = refs/heads/master
+[branch "track-local"]
+ remote = .
+ merge = refs/heads/master
diff --git a/tests-clar/resources/testrepo.git/refs/heads/track-local b/tests-clar/resources/testrepo.git/refs/heads/track-local
new file mode 100644
index 000000000..f37febb2c
--- /dev/null
+++ b/tests-clar/resources/testrepo.git/refs/heads/track-local
@@ -0,0 +1 @@
+9fd738e8f7967c078dceed8190330fc8648ee56a