git_reference **branch_reference_out,
git_repository *repo,
const char *branch_name,
- int is_remote)
+ bool is_remote)
{
git_reference *branch = NULL;
int error = 0;
repository, branch_name, commit->commit, commit->description, force);
}
-static int branch_equals(git_repository *repo, const char *path, void *payload)
+static int branch_is_checked_out(git_repository *worktree, void *payload)
{
git_reference *branch = (git_reference *) payload;
git_reference *head = NULL;
- int equal = 0;
+ int error;
- if (git_reference__read_head(&head, repo, path) < 0 ||
- git_reference_type(head) != GIT_REFERENCE_SYMBOLIC)
- goto done;
+ if (git_repository_is_bare(worktree))
+ return 0;
- equal = !git__strcmp(head->target.symbolic, branch->name);
+ if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) {
+ if (error == GIT_ENOTFOUND)
+ error = 0;
+ goto out;
+ }
-done:
+ if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC)
+ goto out;
+
+ error = !git__strcmp(head->target.symbolic, branch->name);
+
+out:
git_reference_free(head);
- return equal;
+ return error;
}
int git_branch_is_checked_out(const git_reference *branch)
{
- assert(branch && git_reference_is_branch(branch));
-
- return git_repository_foreach_head(git_reference_owner(branch),
- branch_equals, (void *) branch) == 1;
+ if (!git_reference_is_branch(branch))
+ return 0;
+ return git_repository_foreach_worktree(git_reference_owner(branch),
+ branch_is_checked_out, (void *)branch) == 1;
}
int git_branch_delete(git_reference *branch)
const char *branch_name,
git_branch_t branch_type)
{
+ int error = -1;
assert(ref_out && repo && branch_name);
- return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
+ switch (branch_type) {
+ case GIT_BRANCH_LOCAL:
+ case GIT_BRANCH_REMOTE:
+ error = retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
+ break;
+ case GIT_BRANCH_ALL:
+ error = retrieve_branch_reference(ref_out, repo, branch_name, false);
+ if (error == GIT_ENOTFOUND)
+ error = retrieve_branch_reference(ref_out, repo, branch_name, true);
+ break;
+ default:
+ assert(false);
+ }
+ return error;
}
int git_branch_name(
if (error < 0)
git_buf_dispose(buf);
- git_strarray_free(&remote_list);
+ git_strarray_dispose(&remote_list);
return error;
}
return -1;
}
-int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
+int git_branch_set_upstream(git_reference *branch, const char *branch_name)
{
- git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT;
+ git_buf key = GIT_BUF_INIT, remote_name = GIT_BUF_INIT, merge_refspec = GIT_BUF_INIT;
git_reference *upstream;
git_repository *repo;
git_remote *remote = NULL;
git_config *config;
- const char *name, *shortname;
+ const char *refname, *shortname;
int local, error;
const git_refspec *fetchspec;
- name = git_reference_name(branch);
- if (!git_reference__is_branch(name))
- return not_a_local_branch(name);
+ refname = git_reference_name(branch);
+ if (!git_reference__is_branch(refname))
+ return not_a_local_branch(refname);
if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
return -1;
- shortname = name + strlen(GIT_REFS_HEADS_DIR);
+ shortname = refname + strlen(GIT_REFS_HEADS_DIR);
- if (upstream_name == NULL)
+ /* We're unsetting, delegate and bail-out */
+ if (branch_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)
+ /* First we need to resolve name to a branch */
+ if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_LOCAL) == 0)
local = 1;
- else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0)
+ else if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_REMOTE) == 0)
local = 0;
else {
git_error_set(GIT_ERROR_REFERENCE,
}
/*
- * 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 it's a local-tracking branch, its remote is "." (as "the local
+ * repository"), 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)
- error = git_buf_puts(&value, ".");
+ error = git_buf_puts(&remote_name, ".");
else
- error = git_branch_remote_name(&value, repo, git_reference_name(upstream));
+ error = git_branch_remote_name(&remote_name, repo, git_reference_name(upstream));
if (error < 0)
goto on_error;
+ /* Update the upsteam branch config with the new name */
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)
+ if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&remote_name)) < 0)
goto on_error;
if (local) {
- git_buf_clear(&value);
- if (git_buf_puts(&value, git_reference_name(upstream)) < 0)
+ /* A local branch uses the upstream refname directly */
+ if (git_buf_puts(&merge_refspec, git_reference_name(upstream)) < 0)
goto on_error;
} else {
- /* Get the remoe-tracking branch's refname in its repo */
- if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0)
+ /* We transform the upstream branch name according to the remote's refspecs */
+ if (git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name)) < 0)
goto on_error;
fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
- git_buf_clear(&value);
- if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0)
+ if (!fetchspec || git_refspec_rtransform(&merge_refspec, fetchspec, git_reference_name(upstream)) < 0)
goto on_error;
git_remote_free(remote);
remote = NULL;
}
+ /* Update the merge branch config with the refspec */
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)
+ if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&merge_refspec)) < 0)
goto on_error;
git_reference_free(upstream);
git_buf_dispose(&key);
- git_buf_dispose(&value);
+ git_buf_dispose(&remote_name);
+ git_buf_dispose(&merge_refspec);
return 0;
on_error:
git_reference_free(upstream);
git_buf_dispose(&key);
- git_buf_dispose(&value);
+ git_buf_dispose(&remote_name);
+ git_buf_dispose(&merge_refspec);
git_remote_free(remote);
return -1;