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 | |
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')
-rw-r--r-- | src/branch.c | 125 | ||||
-rw-r--r-- | src/branch.h | 17 | ||||
-rw-r--r-- | src/refs.c | 73 | ||||
-rw-r--r-- | src/revparse.c | 2 |
4 files changed, 107 insertions, 110 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; +} diff --git a/src/branch.h b/src/branch.h deleted file mode 100644 index d0e5abc8b..000000000 --- a/src/branch.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2009-2012 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_branch_h__ -#define INCLUDE_branch_h__ - -#include "git2/branch.h" - -struct git_branch { - char *remote; /* TODO: Make this a git_remote */ - char *merge; -}; - -#endif diff --git a/src/refs.c b/src/refs.c index b3c140bec..32f54fc31 100644 --- a/src/refs.c +++ b/src/refs.c @@ -11,7 +11,6 @@ #include "fileops.h" #include "pack.h" #include "reflog.h" -#include "config.h" #include <git2/tag.h> #include <git2/object.h> @@ -1816,75 +1815,9 @@ int git_reference_has_log( return result; } -//TODO: How about also taking care of local tracking branches? -//cf. http://alblue.bandlem.com/2011/07/git-tip-of-week-tracking-branches.html -int git_reference_remote_tracking_from_branch( - git_reference **tracking_ref, - git_reference *branch_ref) +int git_reference_is_branch(git_reference *ref) { - git_config *config = NULL; - const char *name, *remote, *merge; - git_buf buf = GIT_BUF_INIT; - int error = -1; - - assert(tracking_ref && branch_ref); - - name = git_reference_name(branch_ref); - - if (git__prefixcmp(name, GIT_REFS_HEADS_DIR)) { - giterr_set( - GITERR_INVALID, - "Failed to retrieve tracking reference - '%s' is not a branch.", - name); - return -1; - } - - if (git_repository_config(&config, branch_ref->owner) < 0) - return -1; - - if (git_buf_printf( - &buf, - "branch.%s.remote", - name + strlen(GIT_REFS_HEADS_DIR)) < 0) - goto cleanup; - - if ((error = git_config_get_string(&remote, config, git_buf_cstr(&buf))) < 0) - goto cleanup; - - error = -1; - - git_buf_clear(&buf); - - //TODO: Is it ok to fail when no merge target is found? - if (git_buf_printf( - &buf, - "branch.%s.merge", - name + strlen(GIT_REFS_HEADS_DIR)) < 0) - goto cleanup; - - if (git_config_get_string(&merge, config, git_buf_cstr(&buf)) < 0) - goto cleanup; - - //TODO: Should we test this? - if (git__prefixcmp(merge, GIT_REFS_HEADS_DIR)) - goto cleanup; - - git_buf_clear(&buf); - - if (git_buf_printf( - &buf, - "refs/remotes/%s/%s", - remote, - merge + strlen(GIT_REFS_HEADS_DIR)) < 0) - goto cleanup; - - error = git_reference_lookup( - tracking_ref, - branch_ref->owner, - git_buf_cstr(&buf)); + assert(ref); -cleanup: - git_config_free(config); - git_buf_free(&buf); - return error; + return git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0; } 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; |