diff options
Diffstat (limited to 'src/remote.c')
-rw-r--r-- | src/remote.c | 461 |
1 files changed, 286 insertions, 175 deletions
diff --git a/src/remote.c b/src/remote.c index 0e8354a11..3d890a5f1 100644 --- a/src/remote.c +++ b/src/remote.c @@ -10,6 +10,7 @@ #include "git2/oid.h" #include "git2/net.h" +#include "common.h" #include "config.h" #include "repository.h" #include "remote.h" @@ -18,7 +19,7 @@ #include "refspec.h" #include "fetchhead.h" -#include <regex.h> +static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs); static int add_refspec(git_remote *remote, const char *string, bool is_fetch) { @@ -81,6 +82,37 @@ static int ensure_remote_name_is_valid(const char *name) return error; } +static int get_check_cert(int *out, git_repository *repo) +{ + git_config *cfg; + const char *val; + int error = 0; + + assert(out && repo); + + /* By default, we *DO* want to verify the certificate. */ + *out = 1; + + /* Go through the possible sources for SSL verification settings, from + * most specific to least specific. */ + + /* GIT_SSL_NO_VERIFY environment variable */ + if ((val = getenv("GIT_SSL_NO_VERIFY")) != NULL) + return git_config_parse_bool(out, val); + + /* http.sslVerify config setting */ + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) + return error; + + if ((error = git_config_get_bool(out, cfg, "http.sslVerify")) == 0) + return 0; + else if (error != GIT_ENOTFOUND) + return error; + + giterr_clear(); + return 0; +} + static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) { git_remote *remote; @@ -94,9 +126,11 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n GITERR_CHECK_ALLOC(remote); remote->repo = repo; - remote->check_cert = 1; remote->update_fetchhead = 1; + if (get_check_cert(&remote->check_cert, repo) < 0) + goto on_error; + if (git_vector_init(&remote->refs, 32, NULL) < 0) goto on_error; @@ -183,6 +217,32 @@ on_error: return -1; } +int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) +{ + git_remote *remote = NULL; + int error; + + if ((error = ensure_remote_name_is_valid(name)) < 0) + return error; + + if ((error = ensure_remote_doesnot_exist(repo, name)) < 0) + return error; + + if (create_internal(&remote, repo, name, url, fetch) < 0) + goto on_error; + + if (git_remote_save(remote) < 0) + goto on_error; + + *out = remote; + + return 0; + +on_error: + git_remote_free(remote); + return -1; +} + int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url) { int error; @@ -208,7 +268,8 @@ static int refspec_cb(const git_config_entry *entry, void *payload) } static int get_optional_config( - git_config *config, git_buf *buf, git_config_foreach_cb cb, void *payload) + bool *found, git_config *config, git_buf *buf, + git_config_foreach_cb cb, void *payload) { int error = 0; const char *key = git_buf_cstr(buf); @@ -217,10 +278,13 @@ static int get_optional_config( return -1; if (cb != NULL) - error = git_config_get_multivar(config, key, NULL, cb, payload); + error = git_config_get_multivar_foreach(config, key, NULL, cb, payload); else error = git_config_get_string(payload, config, key); + if (found) + *found = !error; + if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; @@ -240,6 +304,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) int error = 0; git_config *config; struct refspec_cb_data data; + bool optional_setting_found = false, found; assert(out && repo && name); @@ -253,13 +318,16 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) GITERR_CHECK_ALLOC(remote); memset(remote, 0x0, sizeof(git_remote)); - remote->check_cert = 1; remote->update_fetchhead = 1; remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); + if ((error = get_check_cert(&remote->check_cert, repo)) < 0) + goto cleanup; + if ((git_vector_init(&remote->refs, 32, NULL) < 0) || - (git_vector_init(&remote->refspecs, 2, NULL))) { + (git_vector_init(&remote->refspecs, 2, NULL) < 0) || + (git_vector_init(&remote->active_refspecs, 2, NULL) < 0)) { error = -1; goto cleanup; } @@ -269,27 +337,33 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0) + if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0) goto cleanup; - if (strlen(val) == 0) { - giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name); - error = -1; - goto cleanup; - } + optional_setting_found |= found; remote->repo = repo; - remote->url = git__strdup(val); - GITERR_CHECK_ALLOC(remote->url); + + if (found && strlen(val) > 0) { + remote->url = git__strdup(val); + GITERR_CHECK_ALLOC(remote->url); + } val = NULL; git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.pushurl", name); - if ((error = get_optional_config(config, &buf, NULL, (void *)&val)) < 0) + if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0) goto cleanup; - if (val) { + optional_setting_found |= found; + + if (!optional_setting_found) { + error = GIT_ENOTFOUND; + goto cleanup; + } + + if (found && strlen(val) > 0) { remote->pushurl = git__strdup(val); GITERR_CHECK_ALLOC(remote->pushurl); } @@ -299,19 +373,23 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.fetch", name); - if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0) + if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0) goto cleanup; data.fetch = false; git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.push", name); - if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0) + if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0) goto cleanup; if (download_tags_value(remote, config) < 0) goto cleanup; + /* Move the data over to where the matching functions can find them */ + if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0) + goto cleanup; + *out = remote; cleanup: @@ -326,20 +404,22 @@ cleanup: static int update_config_refspec(const git_remote *remote, git_config *config, int direction) { git_buf name = GIT_BUF_INIT; - int push; + unsigned int push; const char *dir; size_t i; int error = 0; + const char *cname; push = direction == GIT_DIRECTION_PUSH; dir = push ? "push" : "fetch"; if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0) return -1; + cname = git_buf_cstr(&name); /* Clear out the existing config */ while (!error) - error = git_config_delete_entry(config, git_buf_cstr(&name)); + error = git_config_delete_multivar(config, cname, ".*"); if (error != GIT_ENOTFOUND) return error; @@ -350,8 +430,11 @@ static int update_config_refspec(const git_remote *remote, git_config *config, i if (spec->push != push) continue; + // "$^" is a unmatcheable regexp: it will not match anything at all, so + // all values will be considered new and we will not replace any + // present value. if ((error = git_config_set_multivar( - config, git_buf_cstr(&name), "", spec->string)) < 0) { + config, cname, "$^", spec->string)) < 0) { goto cleanup; } } @@ -467,6 +550,12 @@ const char *git_remote_name(const git_remote *remote) return remote->name; } +git_repository *git_remote_owner(const git_remote *remote) +{ + assert(remote); + return remote->repo; +} + const char *git_remote_url(const git_remote *remote) { assert(remote); @@ -509,6 +598,8 @@ const char* git_remote__urlfordirection(git_remote *remote, int direction) { assert(remote); + assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH); + if (direction == GIT_DIRECTION_FETCH) { return remote->url; } @@ -525,28 +616,32 @@ int git_remote_connect(git_remote *remote, git_direction direction) git_transport *t; const char *url; int flags = GIT_TRANSPORTFLAGS_NONE; + int error; assert(remote); t = remote->transport; url = git_remote__urlfordirection(remote, direction); - if (url == NULL ) + if (url == NULL) { + giterr_set(GITERR_INVALID, + "Malformed remote '%s' - missing URL", remote->name); return -1; + } /* A transport could have been supplied in advance with * git_remote_set_transport */ - if (!t && git_transport_new(&t, remote, url) < 0) - return -1; + if (!t && (error = git_transport_new(&t, remote, url)) < 0) + return error; if (t->set_callbacks && - t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload) < 0) + (error = t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload)) < 0) goto on_error; if (!remote->check_cert) flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT; - if (t->connect(t, url, remote->cred_acquire_cb, remote->cred_acquire_payload, direction, flags) < 0) + if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) < 0) goto on_error; remote->transport = t; @@ -559,20 +654,21 @@ on_error: if (t == remote->transport) remote->transport = NULL; - return -1; + return error; } -int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) +int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote) { assert(remote); - return remote->transport->ls(remote->transport, list_cb, payload); + return remote->transport->ls(out, size, remote->transport); } int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url) { git_config *cfg; const char *val; + int error; assert(remote); @@ -581,8 +677,8 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur *proxy_url = NULL; - if (git_repository_config__weakptr(&cfg, remote->repo) < 0) - return -1; + if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0) + return error; /* Go through the possible sources for proxy configuration, from most specific * to least specific. */ @@ -591,28 +687,33 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur if (remote->name && 0 != *(remote->name)) { git_buf buf = GIT_BUF_INIT; - if (git_buf_printf(&buf, "remote.%s.proxy", remote->name) < 0) - return -1; + if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0) + return error; - if (!git_config_get_string(&val, cfg, git_buf_cstr(&buf)) && + if ((error = git_config_get_string(&val, cfg, git_buf_cstr(&buf))) == 0 && val && ('\0' != *val)) { git_buf_free(&buf); *proxy_url = git__strdup(val); GITERR_CHECK_ALLOC(*proxy_url); return 0; - } + } else if (error != GIT_ENOTFOUND) + return error; + giterr_clear(); git_buf_free(&buf); } /* http.proxy config setting */ - if (!git_config_get_string(&val, cfg, "http.proxy") && + if ((error = git_config_get_string(&val, cfg, "http.proxy")) == 0 && val && ('\0' != *val)) { *proxy_url = git__strdup(val); GITERR_CHECK_ALLOC(*proxy_url); return 0; - } + } else if (error != GIT_ENOTFOUND) + return error; + + giterr_clear(); /* HTTP_PROXY / HTTPS_PROXY environment variables */ val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY"); @@ -626,67 +727,31 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur return 0; } -static int store_refs(git_remote_head *head, void *payload) +/* DWIM `refspecs` based on `refs` and append the output to `out` */ +static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs) { - git_vector *refs = (git_vector *)payload; - - return git_vector_insert(refs, head); -} - -static int dwim_refspecs(git_vector *refspecs, git_vector *refs) -{ - git_buf buf = GIT_BUF_INIT; + size_t i; git_refspec *spec; - size_t i, j, pos; - git_remote_head key; - - const char* formatters[] = { - GIT_REFS_DIR "%s", - GIT_REFS_TAGS_DIR "%s", - GIT_REFS_HEADS_DIR "%s", - NULL - }; git_vector_foreach(refspecs, i, spec) { - if (spec->dwim) - continue; - - /* shorthand on the lhs */ - if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { - for (j = 0; formatters[j]; j++) { - git_buf_clear(&buf); - if (git_buf_printf(&buf, formatters[j], spec->src) < 0) - return -1; - - key.name = (char *) git_buf_cstr(&buf); - if (!git_vector_search(&pos, refs, &key)) { - /* we found something to match the shorthand, set src to that */ - git__free(spec->src); - spec->src = git_buf_detach(&buf); - } - } - } - - if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { - /* if it starts with "remotes" then we just prepend "refs/" */ - if (!git__prefixcmp(spec->dst, "remotes/")) { - git_buf_puts(&buf, GIT_REFS_DIR); - } else { - git_buf_puts(&buf, GIT_REFS_HEADS_DIR); - } + if (git_refspec__dwim_one(out, spec, refs) < 0) + return -1; + } - if (git_buf_puts(&buf, spec->dst) < 0) - return -1; + return 0; +} - git__free(spec->dst); - spec->dst = git_buf_detach(&buf); - } +static void free_refspecs(git_vector *vec) +{ + size_t i; + git_refspec *spec; - spec->dwim = 1; + git_vector_foreach(vec, i, spec) { + git_refspec__free(spec); + git__free(spec); } - git_buf_free(&buf); - return 0; + git_vector_clear(vec); } static int remote_head_cmp(const void *_a, const void *_b) @@ -697,32 +762,65 @@ static int remote_head_cmp(const void *_a, const void *_b) return git__strcmp_cb(a->name, b->name); } -int git_remote_download( - git_remote *remote, - git_transfer_progress_callback progress_cb, - void *progress_payload) +static int ls_to_vector(git_vector *out, git_remote *remote) +{ + git_remote_head **heads; + size_t heads_len, i; + + if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0) + return -1; + + if (git_vector_init(out, heads_len, remote_head_cmp) < 0) + return -1; + + for (i = 0; i < heads_len; i++) { + if (git_vector_insert(out, heads[i]) < 0) + return -1; + } + + return 0; +} + +int git_remote_download(git_remote *remote) { int error; git_vector refs; assert(remote); - if (git_vector_init(&refs, 16, remote_head_cmp) < 0) + if (ls_to_vector(&refs, remote) < 0) return -1; - if (git_remote_ls(remote, store_refs, &refs) < 0) { - return -1; - } + free_refspecs(&remote->active_refspecs); - error = dwim_refspecs(&remote->refspecs, &refs); + error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &refs); git_vector_free(&refs); + if (error < 0) return -1; if ((error = git_fetch_negotiate(remote)) < 0) return error; - return git_fetch_download_pack(remote, progress_cb, progress_payload); + return git_fetch_download_pack(remote); +} + +int git_remote_fetch(git_remote *remote) +{ + int error; + + /* Connect and download everything */ + if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) < 0) + return error; + + if ((error = git_remote_download(remote)) < 0) + return error; + + /* We don't need to be connected anymore */ + git_remote_disconnect(remote); + + /* Create "remote/foo" branches for all remote branches */ + return git_remote_update_tips(remote); } static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src) @@ -759,7 +857,7 @@ static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vec (!git_reference_is_branch(resolved_ref)) || (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 || (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) { - /* Not an error if HEAD is orphaned or no tracking branch */ + /* Not an error if HEAD is unborn or no tracking branch */ if (error == GIT_ENOTFOUND) error = 0; @@ -947,10 +1045,8 @@ int git_remote_update_tips(git_remote *remote) if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; - if (git_vector_init(&refs, 16, NULL) < 0) - return -1; - if ((error = git_remote_ls(remote, store_refs, &refs)) < 0) + if ((error = ls_to_vector(&refs, remote)) < 0) goto out; if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { @@ -958,7 +1054,7 @@ int git_remote_update_tips(git_remote *remote) goto out; } - git_vector_foreach(&remote->refspecs, i, spec) { + git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; @@ -967,8 +1063,8 @@ int git_remote_update_tips(git_remote *remote) } out: - git_refspec__free(&tagspec); git_vector_free(&refs); + git_refspec__free(&tagspec); return error; } @@ -1001,9 +1097,6 @@ void git_remote_disconnect(git_remote *remote) void git_remote_free(git_remote *remote) { - git_refspec *spec; - size_t i; - if (remote == NULL) return; @@ -1016,67 +1109,55 @@ void git_remote_free(git_remote *remote) git_vector_free(&remote->refs); - git_vector_foreach(&remote->refspecs, i, spec) { - git_refspec__free(spec); - git__free(spec); - } + free_refspecs(&remote->refspecs); git_vector_free(&remote->refspecs); + free_refspecs(&remote->active_refspecs); + git_vector_free(&remote->active_refspecs); + git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); git__free(remote); } -struct cb_data { - git_vector *list; - regex_t *preg; -}; - -static int remote_list_cb(const git_config_entry *entry, void *data_) +static int remote_list_cb(const git_config_entry *entry, void *payload) { - struct cb_data *data = (struct cb_data *)data_; - size_t nmatch = 2; - regmatch_t pmatch[2]; - const char *name = entry->name; + git_vector *list = payload; + const char *name = entry->name + strlen("remote."); + size_t namelen = strlen(name); + char *remote_name; - if (!regexec(data->preg, name, nmatch, pmatch, 0)) { - char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); - GITERR_CHECK_ALLOC(remote_name); + /* we know name matches "remote.<stuff>.(push)?url" */ - if (git_vector_insert(data->list, remote_name) < 0) - return -1; - } + if (!strcmp(&name[namelen - 4], ".url")) + remote_name = git__strndup(name, namelen - 4); /* strip ".url" */ + else + remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */ + GITERR_CHECK_ALLOC(remote_name); - return 0; + return git_vector_insert(list, remote_name); } int git_remote_list(git_strarray *remotes_list, git_repository *repo) { git_config *cfg; git_vector list; - regex_t preg; - struct cb_data data; int error; if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; - if (git_vector_init(&list, 4, NULL) < 0) + if (git_vector_init(&list, 4, git__strcmp_cb) < 0) return -1; - if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) { - giterr_set(GITERR_OS, "Remote catch regex failed to compile"); - return -1; - } + error = git_config_foreach_match( + cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list); - data.list = &list; - data.preg = &preg; - error = git_config_foreach(cfg, remote_list_cb, &data); - regfree(&preg); if (error < 0) { size_t i; char *elem; + git_vector_foreach(&list, i, elem) { git__free(elem); } @@ -1090,6 +1171,8 @@ int git_remote_list(git_strarray *remotes_list, git_repository *repo) return error; } + git_vector_uniq(&list, git__free); + remotes_list->strings = (char **)list.contents; remotes_list->count = list.length; @@ -1103,7 +1186,7 @@ void git_remote_check_cert(git_remote *remote, int check) remote->check_cert = check; } -int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks) +int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks) { assert(remote && callbacks); @@ -1112,7 +1195,7 @@ int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks)); if (remote->transport && remote->transport->set_callbacks) - remote->transport->set_callbacks(remote->transport, + return remote->transport->set_callbacks(remote->transport, remote->callbacks.progress, NULL, remote->callbacks.payload); @@ -1120,17 +1203,6 @@ int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks return 0; } -void git_remote_set_cred_acquire_cb( - git_remote *remote, - git_cred_acquire_cb cred_acquire_cb, - void *payload) -{ - assert(remote); - - remote->cred_acquire_cb = cred_acquire_cb; - remote->cred_acquire_payload = payload; -} - int git_remote_set_transport(git_remote *remote, git_transport *transport) { assert(remote && transport); @@ -1418,12 +1490,12 @@ int git_remote_rename( int git_remote_update_fetchhead(git_remote *remote) { - return remote->update_fetchhead; + return (remote->update_fetchhead != 0); } void git_remote_set_update_fetchhead(git_remote *remote, int value) { - remote->update_fetchhead = value; + remote->update_fetchhead = (value != 0); } int git_remote_is_valid_name( @@ -1451,7 +1523,7 @@ git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refnam git_refspec *spec; size_t i; - git_vector_foreach(&remote->refspecs, i, spec) { + git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; @@ -1467,7 +1539,7 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re git_refspec *spec; size_t i; - git_vector_foreach(&remote->refspecs, i, spec) { + git_vector_foreach(&remote->active_refspecs, i, spec) { if (spec->push) continue; @@ -1490,17 +1562,71 @@ void git_remote_clear_refspecs(git_remote *remote) git_vector_clear(&remote->refspecs); } +static int add_and_dwim(git_remote *remote, const char *str, int push) +{ + git_refspec *spec; + git_vector *vec; + + if (add_refspec(remote, str, !push) < 0) + return -1; + + vec = &remote->refspecs; + spec = git_vector_get(vec, vec->length - 1); + return git_refspec__dwim_one(&remote->active_refspecs, spec, &remote->refs); +} + int git_remote_add_fetch(git_remote *remote, const char *refspec) { - return add_refspec(remote, refspec, true); + return add_and_dwim(remote, refspec, false); } int git_remote_add_push(git_remote *remote, const char *refspec) { - return add_refspec(remote, refspec, false); + return add_and_dwim(remote, refspec, true); } -static int copy_refspecs(git_strarray *array, git_remote *remote, int push) +static int set_refspecs(git_remote *remote, git_strarray *array, int push) +{ + git_vector *vec = &remote->refspecs; + git_refspec *spec; + size_t i; + + /* Start by removing any refspecs of the same type */ + for (i = 0; i < vec->length; i++) { + spec = git_vector_get(vec, i); + if (spec->push != push) + continue; + + git_refspec__free(spec); + git__free(spec); + git_vector_remove(vec, i); + i--; + } + + /* And now we add the new ones */ + + for (i = 0; i < array->count; i++) { + if (add_refspec(remote, array->strings[i], !push) < 0) + return -1; + } + + free_refspecs(&remote->active_refspecs); + git_vector_clear(&remote->active_refspecs); + + return dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs); +} + +int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array) +{ + return set_refspecs(remote, array, false); +} + +int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array) +{ + return set_refspecs(remote, array, true); +} + +static int copy_refspecs(git_strarray *array, git_remote *remote, unsigned int push) { size_t i; git_vector refspecs; @@ -1555,18 +1681,3 @@ const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n) { return git_vector_get(&remote->refspecs, n); } - -int git_remote_remove_refspec(git_remote *remote, size_t n) -{ - git_refspec *spec; - - assert(remote); - - spec = git_vector_get(&remote->refspecs, n); - if (spec) { - git_refspec__free(spec); - git__free(spec); - } - - return git_vector_remove(&remote->refspecs, n); -} |