diff options
| author | Vicent Marti <tanoku@gmail.com> | 2012-07-27 18:45:55 +0200 |
|---|---|---|
| committer | Vicent Marti <tanoku@gmail.com> | 2012-07-27 18:45:55 +0200 |
| commit | b41a30bdbb96dc0eb2d7e30497918ecbb45fd090 (patch) | |
| tree | 00c7d7b1883ac812cde389f771d6371c30615d0e /src/branch.c | |
| parent | b84f75c357208ce54c5cc35921ff0b4a1abbe7d2 (diff) | |
| parent | 786a17cd282cf81c76c45a8e62f2a1003235a673 (diff) | |
| download | libgit2-b41a30bdbb96dc0eb2d7e30497918ecbb45fd090.tar.gz | |
Merge remote-tracking branch 'nulltoken/topic/branch-rework' into development
Diffstat (limited to 'src/branch.c')
| -rw-r--r-- | src/branch.c | 125 |
1 files changed, 103 insertions, 22 deletions
diff --git a/src/branch.c b/src/branch.c index 671e42051..d11eca8da 100644 --- a/src/branch.c +++ b/src/branch.c @@ -7,8 +7,11 @@ #include "common.h" #include "commit.h" -#include "branch.h" #include "tag.h" +#include "config.h" +#include "refspec.h" + +#include "git2/branch.h" static int retrieve_branch_reference( git_reference **branch_reference_out, @@ -48,8 +51,7 @@ static int create_error_invalid(const char *msg) } int git_branch_create( - git_oid *oid_out, - git_repository *repo, + git_reference **ref_out, const char *branch_name, const git_object *target, int force) @@ -60,10 +62,7 @@ int git_branch_create( git_buf canonical_branch_name = GIT_BUF_INIT; int error = -1; - assert(repo && branch_name && target && oid_out); - - if (git_object_owner(target) != repo) - return create_error_invalid("The given target does not belong to this repository"); + assert(branch_name && target && ref_out); target_type = git_object_type(target); @@ -90,17 +89,17 @@ int git_branch_create( if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; - if (git_reference_create_oid(&branch, repo, git_buf_cstr(&canonical_branch_name), git_object_id(commit), force) < 0) + if (git_reference_create_oid(&branch, git_object_owner(commit), + git_buf_cstr(&canonical_branch_name), git_object_id(commit), force) < 0) goto cleanup; - git_oid_cpy(oid_out, git_reference_oid(branch)); + *ref_out = branch; error = 0; cleanup: if (target_type == GIT_OBJ_TAG) git_object_free(commit); - git_reference_free(branch); git_buf_free(&canonical_branch_name); return error; } @@ -111,6 +110,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_ git_reference *head = NULL; int error; + assert(repo && branch_name); assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE)); if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0) @@ -183,28 +183,109 @@ int git_branch_foreach( return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter); } -int git_branch_move(git_repository *repo, const char *old_branch_name, const char *new_branch_name, int force) +static int not_a_local_branch(git_reference *ref) +{ + giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref)); + return -1; +} + +int git_branch_move( + git_reference *branch, + const char *new_branch_name, + int force) { - git_reference *reference = NULL; - git_buf old_reference_name = GIT_BUF_INIT, new_reference_name = GIT_BUF_INIT; - int error = 0; + git_buf new_reference_name = GIT_BUF_INIT; + int error; - if ((error = git_buf_joinpath(&old_reference_name, GIT_REFS_HEADS_DIR, old_branch_name)) < 0) - goto cleanup; + assert(branch && new_branch_name); - /* We need to be able to return GIT_ENOTFOUND */ - if ((error = git_reference_lookup(&reference, repo, git_buf_cstr(&old_reference_name))) < 0) - goto cleanup; + if (!git_reference_is_branch(branch)) + return not_a_local_branch(branch); if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0) goto cleanup; - error = git_reference_rename(reference, git_buf_cstr(&new_reference_name), force); + error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force); cleanup: - git_reference_free(reference); - git_buf_free(&old_reference_name); git_buf_free(&new_reference_name); return error; } + +int git_branch_lookup( + git_reference **ref_out, + git_repository *repo, + const char *branch_name, + git_branch_t branch_type) +{ + assert(ref_out && repo && branch_name); + + 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; +} |
