diff options
author | Vicent Martà <vicent@github.com> | 2013-04-11 06:34:59 -0700 |
---|---|---|
committer | Vicent Martà <vicent@github.com> | 2013-04-11 06:34:59 -0700 |
commit | ea8bac37b0c3a302b8f740cbeb4af50d0626815b (patch) | |
tree | a6d3eb230c55f683d4c65921552a132bcc2c7a37 /src | |
parent | acd4077182b508f5c88353ddfcf31e14614d0d46 (diff) | |
parent | d59942c2aba2fa5f9570b37e3bc9eaf34f16d671 (diff) | |
download | libgit2-ea8bac37b0c3a302b8f740cbeb4af50d0626815b.tar.gz |
Merge pull request #1450 from carlosmn/branch-upstream
Branch upstream configuration
Diffstat (limited to 'src')
-rw-r--r-- | src/branch.c | 179 | ||||
-rw-r--r-- | src/branch.h | 2 | ||||
-rw-r--r-- | src/remote.c | 2 | ||||
-rw-r--r-- | src/revparse.c | 2 | ||||
-rw-r--r-- | src/submodule.c | 2 |
5 files changed, 149 insertions, 38 deletions
diff --git a/src/branch.c b/src/branch.c index 45ecca751..e7088790e 100644 --- a/src/branch.c +++ b/src/branch.c @@ -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, @@ -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) @@ -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; @@ -305,23 +305,16 @@ cleanup: 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)) { @@ -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); @@ -362,23 +355,10 @@ 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: @@ -386,7 +366,24 @@ cleanup: 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, @@ -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; @@ -422,14 +419,14 @@ cleanup: 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; @@ -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) { diff --git a/src/branch.h b/src/branch.h index 8a26c4fea..d02f2af0d 100644 --- a/src/branch.h +++ b/src/branch.h @@ -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); diff --git a/src/remote.c b/src/remote.c index a6f62d6a5..896361e30 100644 --- a/src/remote.c +++ b/src/remote.c @@ -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) diff --git a/src/revparse.c b/src/revparse.c index b1eb51b41..fd62a2fd2 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -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; diff --git a/src/submodule.c b/src/submodule.c index 066a881cb..2fdaf2f77 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -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 */ |