Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Branch upstream configuration #1450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 11, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions include/git2/branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,22 @@ GIT_EXTERN(int) git_branch_name(const char **out,
* @return 0 on success; GIT_ENOTFOUND when no remote tracking
* reference exists, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_tracking(
GIT_EXTERN(int) git_branch_upstream(
git_reference **out,
git_reference *branch);

/**
* Set the upstream configuration for a given local branch
*
* @param branch the branch to configure
*
* @param upstream_name remote-tracking or local branch to set as
* upstream. Pass NULL to unset.
*
* @return 0 or an error code
*/
GIT_EXTERN(int) git_branch_set_upstream(git_reference *branch, const char *upstream_name);

/**
* Return the name of the reference supporting the remote tracking branch,
* given the name of a local branch reference.
Expand All @@ -195,7 +207,7 @@ GIT_EXTERN(int) git_branch_tracking(
* including the trailing NUL byte; GIT_ENOTFOUND when no remote tracking
* reference exists, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_tracking_name(
GIT_EXTERN(int) git_branch_upstream_name(
char *tracking_branch_name_out,
size_t buffer_size,
git_repository *repo,
Expand Down
179 changes: 145 additions & 34 deletions src/branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ int git_branch_name(const char **out, git_reference *ref)
return 0;
}

static int retrieve_tracking_configuration(
static int retrieve_upstream_configuration(
const char **out,
git_repository *repo,
const char *canonical_branch_name,
Expand All @@ -250,7 +250,7 @@ static int retrieve_tracking_configuration(
return error;
}

int git_branch_tracking__name(
int git_branch_upstream__name(
git_buf *tracking_name,
git_repository *repo,
const char *canonical_branch_name)
Expand All @@ -266,11 +266,11 @@ int git_branch_tracking__name(
if (!git_reference__is_branch(canonical_branch_name))
return not_a_local_branch(canonical_branch_name);

if ((error = retrieve_tracking_configuration(
if ((error = retrieve_upstream_configuration(
&remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0)
goto cleanup;

if ((error = retrieve_tracking_configuration(
if ((error = retrieve_upstream_configuration(
&merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0)
goto cleanup;

Expand Down Expand Up @@ -305,23 +305,16 @@ int git_branch_tracking__name(
return error;
}

int git_branch_remote_name(
char *remote_name_out,
size_t buffer_size,
git_repository *repo,
const char *canonical_branch_name)
static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name)
{
git_strarray remote_list = {0};
size_t i, remote_name_size;
size_t i;
git_remote *remote;
const git_refspec *fetchspec;
int error = 0;
char *remote_name = NULL;

assert(repo && canonical_branch_name);

if (remote_name_out && buffer_size)
*remote_name_out = '\0';
assert(buf && repo && canonical_branch_name);

/* Verify that this is a remote branch */
if (!git_reference__is_remote(canonical_branch_name)) {
Expand All @@ -338,7 +331,7 @@ int git_branch_remote_name(
/* Find matching remotes */
for (i = 0; i < remote_list.count; i++) {
if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0)
goto cleanup;
continue;

fetchspec = git_remote_fetchspec(remote);

Expand All @@ -362,31 +355,35 @@ int git_branch_remote_name(
}

if (remote_name) {
remote_name_size = strlen(remote_name) + 1;
error = (int) remote_name_size;

if (remote_name_out) {
if(remote_name_size > buffer_size) {
giterr_set(
GITERR_INVALID,
"Buffer too short to hold the remote name.");
error = GIT_ERROR;
goto cleanup;
}

memcpy(remote_name_out, remote_name, remote_name_size);
}
git_buf_clear(buf);
error = git_buf_puts(buf, remote_name);
} else {
error = GIT_ENOTFOUND;
goto cleanup;
}

cleanup:
git_strarray_free(&remote_list);
return error;
}

int git_branch_tracking_name(
int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname)
{
int ret;
git_buf buf = GIT_BUF_INIT;

if ((ret = remote_name(&buf, repo, refname)) < 0)
return ret;

if (buffer)
git_buf_copy_cstr(buffer, buffer_len, &buf);

ret = git_buf_len(&buf) + 1;
git_buf_free(&buf);

return ret;
}

int git_branch_upstream_name(
char *tracking_branch_name_out,
size_t buffer_size,
git_repository *repo,
Expand All @@ -400,7 +397,7 @@ int git_branch_tracking_name(
if (tracking_branch_name_out && buffer_size)
*tracking_branch_name_out = '\0';

if ((error = git_branch_tracking__name(
if ((error = git_branch_upstream__name(
&buf, repo, canonical_branch_name)) < 0)
goto cleanup;

Expand All @@ -422,14 +419,14 @@ int git_branch_tracking_name(
return (int)error;
}

int git_branch_tracking(
int git_branch_upstream(
git_reference **tracking_out,
git_reference *branch)
{
int error;
git_buf tracking_name = GIT_BUF_INIT;

if ((error = git_branch_tracking__name(&tracking_name,
if ((error = git_branch_upstream__name(&tracking_name,
git_reference_owner(branch), git_reference_name(branch))) < 0)
return error;

Expand All @@ -442,6 +439,120 @@ int git_branch_tracking(
return error;
}

static int unset_upstream(git_config *config, const char *shortname)
{
git_buf buf = GIT_BUF_INIT;

if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0)
return -1;

if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
goto on_error;

git_buf_clear(&buf);
if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0)
goto on_error;

if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
goto on_error;

git_buf_free(&buf);
return 0;

on_error:
git_buf_free(&buf);
return -1;
}

int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
{
git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT;
git_reference *upstream;
git_repository *repo;
git_remote *remote = NULL;
git_config *config;
const char *name, *shortname;
int local;
const git_refspec *fetchspec;

name = git_reference_name(branch);
if (!git_reference__is_branch(name))
return not_a_local_branch(name);

if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
return -1;

shortname = name + strlen(GIT_REFS_HEADS_DIR);

if (upstream_name == NULL)
return unset_upstream(config, shortname);

repo = git_reference_owner(branch);

/* First we need to figure out whether it's a branch or remote-tracking */
if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0)
local = 1;
else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0)
local = 0;
else
return GIT_ENOTFOUND;

/*
* If it's local, the remote is "." and the branch name is
* simply the refname. Otherwise we need to figure out what
* the remote-tracking branch's name on the remote is and use
* that.
*/
if (local)
git_buf_puts(&value, ".");
else
remote_name(&value, repo, git_reference_name(upstream));

if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0)
goto on_error;

if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
goto on_error;

if (local) {
if (git_buf_puts(&value, git_reference_name(branch)) < 0)
goto on_error;
} else {
/* Get the remoe-tracking branch's refname in its repo */
if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0)
goto on_error;

fetchspec = git_remote_fetchspec(remote);
git_buf_clear(&value);
if (git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0)
goto on_error;

git_remote_free(remote);
remote = NULL;
}

git_buf_clear(&key);
if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0)
goto on_error;

if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
goto on_error;

git_reference_free(upstream);
git_buf_free(&key);
git_buf_free(&value);

return 0;

on_error:
git_reference_free(upstream);
git_buf_free(&key);
git_buf_free(&value);
git_remote_free(remote);

return -1;
}

int git_branch_is_head(
git_reference *branch)
{
Expand Down
2 changes: 1 addition & 1 deletion src/branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include "buffer.h"

int git_branch_tracking__name(
int git_branch_upstream__name(
git_buf *tracking_name,
git_repository *repo,
const char *canonical_branch_name);
Expand Down
2 changes: 1 addition & 1 deletion src/remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_ve

if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 ||
(!git_reference_is_branch(resolved_ref)) ||
(error = git_branch_tracking(&tracking_ref, resolved_ref)) < 0 ||
(error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 ||
(error = git_refspec_transform_l(&remote_name, &remote->fetch, git_reference_name(tracking_ref))) < 0) {
/* Not an error if HEAD is orphaned or no tracking branch */
if (error == GIT_ENOTFOUND)
Expand Down
2 changes: 1 addition & 1 deletion src/revparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch
goto cleanup;
}

if ((error = git_branch_tracking(&tracking, ref)) < 0)
if ((error = git_branch_upstream(&tracking, ref)) < 0)
goto cleanup;

*base_ref = tracking;
Expand Down
2 changes: 1 addition & 1 deletion src/submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ static int lookup_head_remote(git_buf *url, git_repository *repo)
goto cleanup;
}

if ((error = git_branch_tracking(&remote, head)) < 0)
if ((error = git_branch_upstream(&remote, head)) < 0)
goto cleanup;

/* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
Expand Down
2 changes: 1 addition & 1 deletion tests-clar/clone/empty.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void test_clone_empty__can_clone_an_empty_local_repo_barely(void)

/* ...one can still retrieve the name of the remote tracking reference */
cl_assert_equal_i((int)strlen(expected_tracked_branch_name) + 1,
git_branch_tracking_name(buffer, 1024, g_repo_cloned, local_name));
git_branch_upstream_name(buffer, 1024, g_repo_cloned, local_name));

cl_assert_equal_s(expected_tracked_branch_name, buffer);

Expand Down
2 changes: 1 addition & 1 deletion tests-clar/refs/branches/remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void test_refs_branches_remote__insufficient_buffer_returns_error(void)

cl_git_fail_with(git_branch_remote_name(remotename,
expected_remote_name_length - 1, g_repo, remote_tracking_branch_name),
GIT_ERROR);
expected_remote_name_length);
}

void test_refs_branches_remote__no_matching_remote_returns_error(void)
Expand Down
Loading