]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Merge pull request #3097 from libgit2/cmn/submodule-config-state
[libgit2.git] / src / remote.c
CommitLineData
9c82357b 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
9c82357b 3 *
bb742ede
VM
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9c82357b
CMN
6 */
7
9c82357b
CMN
8#include "git2/config.h"
9#include "git2/types.h"
c07d9c95 10#include "git2/oid.h"
1ffd0806 11#include "git2/net.h"
9c82357b 12
157cef10 13#include "common.h"
9c82357b
CMN
14#include "config.h"
15#include "repository.h"
16#include "remote.h"
e1d88030 17#include "fetch.h"
441f57c2 18#include "refs.h"
b0f6e45d
ET
19#include "refspec.h"
20#include "fetchhead.h"
fe794b2e 21#include "push.h"
9c82357b 22
22261344
CMN
23#define CONFIG_URL_FMT "remote.%s.url"
24#define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
25#define CONFIG_FETCH_FMT "remote.%s.fetch"
77254990 26#define CONFIG_PUSH_FMT "remote.%s.push"
35a8a8c5 27#define CONFIG_TAGOPT_FMT "remote.%s.tagopt"
22261344 28
af613ecd 29static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
1ef3f0ce 30static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
ec0c4c40 31char *apply_insteadof(git_config *config, const char *url, int direction);
af613ecd 32
3f894205 33static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
9c82357b 34{
4330ab26 35 git_refspec *spec;
9c82357b 36
4330ab26
CMN
37 spec = git__calloc(1, sizeof(git_refspec));
38 GITERR_CHECK_ALLOC(spec);
39
1be680c4
CMN
40 if (git_refspec__parse(spec, string, is_fetch) < 0) {
41 git__free(spec);
42 return -1;
43 }
4330ab26
CMN
44
45 spec->push = !is_fetch;
3f894205 46 if (git_vector_insert(vector, spec) < 0) {
1be680c4
CMN
47 git_refspec__free(spec);
48 git__free(spec);
49 return -1;
50 }
9c82357b 51
4330ab26 52 return 0;
9c82357b
CMN
53}
54
3f894205
CMN
55static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
56{
57 return add_refspec_to(&remote->refspecs, string, is_fetch);
58}
59
24f2f94e
CMN
60static int download_tags_value(git_remote *remote, git_config *cfg)
61{
9a97f49e 62 git_config_entry *ce;
24f2f94e
CMN
63 git_buf buf = GIT_BUF_INIT;
64 int error;
65
24f2f94e
CMN
66 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
67 return -1;
68
9f77b3f6 69 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
24f2f94e 70 git_buf_free(&buf);
24f2f94e 71
9f77b3f6
RB
72 if (!error && ce && ce->value) {
73 if (!strcmp(ce->value, "--no-tags"))
74 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
75 else if (!strcmp(ce->value, "--tags"))
76 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
bf6bebe2 77 }
24f2f94e 78
9a97f49e 79 git_config_entry_free(ce);
24f2f94e
CMN
80 return error;
81}
82
032ba9e4 83static int ensure_remote_name_is_valid(const char *name)
84{
2bca5b67 85 int error = 0;
032ba9e4 86
2bca5b67 87 if (!git_remote_is_valid_name(name)) {
032ba9e4 88 giterr_set(
89 GITERR_CONFIG,
183aa4f8 90 "'%s' is not a valid remote name.", name ? name : "(null)");
032ba9e4 91 error = GIT_EINVALIDSPEC;
92 }
93
94 return error;
95}
96
77254990
CMN
97static int write_add_refspec(git_repository *repo, const char *name, const char *refspec, bool fetch)
98{
99 git_config *cfg;
100 git_buf var = GIT_BUF_INIT;
c6e942fb 101 git_refspec spec;
77254990
CMN
102 const char *fmt;
103 int error;
104
105 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
106 return error;
107
108 fmt = fetch ? CONFIG_FETCH_FMT : CONFIG_PUSH_FMT;
109
110 if ((error = ensure_remote_name_is_valid(name)) < 0)
111 return error;
112
c6e942fb
CMN
113 if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
114 if (giterr_last()->klass != GITERR_NOMEMORY)
115 error = GIT_EINVALIDSPEC;
116
117 return error;
118 }
119
120 git_refspec__free(&spec);
121
77254990
CMN
122 if ((error = git_buf_printf(&var, fmt, name)) < 0)
123 return error;
124
125 /*
126 * "$^" is a unmatcheable regexp: it will not match anything at all, so
127 * all values will be considered new and we will not replace any
128 * present value.
129 */
130 if ((error = git_config_set_multivar(cfg, var.ptr, "$^", refspec)) < 0) {
131 goto cleanup;
132 }
133
134cleanup:
135 git_buf_free(&var);
136 return 0;
137}
138
41698f22
CMN
139#if 0
140/* We could export this as a helper */
80fc7d6b 141static int get_check_cert(int *out, git_repository *repo)
af6dab7e
PK
142{
143 git_config *cfg;
144 const char *val;
80fc7d6b
ET
145 int error = 0;
146
147 assert(out && repo);
af6dab7e 148
80fc7d6b
ET
149 /* By default, we *DO* want to verify the certificate. */
150 *out = 1;
af6dab7e
PK
151
152 /* Go through the possible sources for SSL verification settings, from
153 * most specific to least specific. */
154
155 /* GIT_SSL_NO_VERIFY environment variable */
8f2a3d62 156 if ((val = getenv("GIT_SSL_NO_VERIFY")) != NULL)
80fc7d6b 157 return git_config_parse_bool(out, val);
af6dab7e
PK
158
159 /* http.sslVerify config setting */
80fc7d6b
ET
160 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
161 return error;
af6dab7e 162
9f77b3f6 163 *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
80fc7d6b 164 return 0;
af6dab7e 165}
41698f22 166#endif
af6dab7e 167
12f32d91
ET
168static int canonicalize_url(git_buf *out, const char *in)
169{
47a40d1d
CMN
170 if (in == NULL || strlen(in) == 0) {
171 giterr_set(GITERR_INVALID, "cannot set empty URL");
172 return GIT_EINVALIDSPEC;
173 }
12f32d91 174
47a40d1d 175#ifdef GIT_WIN32
12f32d91
ET
176 /* Given a UNC path like \\server\path, we need to convert this
177 * to //server/path for compatibility with core git.
178 */
179 if (in[0] == '\\' && in[1] == '\\' &&
180 (git__isalpha(in[2]) || git__isdigit(in[2]))) {
47a40d1d 181 const char *c;
12f32d91
ET
182 for (c = in; *c; c++)
183 git_buf_putc(out, *c == '\\' ? '/' : *c);
184
185 return git_buf_oom(out) ? -1 : 0;
186 }
187#endif
188
189 return git_buf_puts(out, in);
190}
191
874dcb25 192static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
193{
194 git_remote *remote;
a8846da7 195 git_config *config = NULL;
22261344
CMN
196 git_buf canonical_url = GIT_BUF_INIT;
197 git_buf var = GIT_BUF_INIT;
44f36f6e 198 int error = -1;
778e1c73 199
4bef3565 200 /* name is optional */
874dcb25 201 assert(out && repo && url);
617bfdf4 202
22261344
CMN
203 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
204 return error;
205
59bccf33 206 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 207 GITERR_CHECK_ALLOC(remote);
778e1c73 208
778e1c73 209 remote->repo = repo;
617bfdf4 210
12f32d91
ET
211 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
212 canonicalize_url(&canonical_url, url) < 0)
44f36f6e 213 goto on_error;
d88d4311 214
ec0c4c40 215 remote->url = apply_insteadof(repo->_config, canonical_url.ptr, GIT_DIRECTION_FETCH);
778e1c73 216
617bfdf4
CMN
217 if (name != NULL) {
218 remote->name = git__strdup(name);
4376f7f6 219 GITERR_CHECK_ALLOC(remote->name);
22261344
CMN
220
221 if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
222 goto on_error;
223
ec0c4c40 224 if ((error = git_config_set_string(config, var.ptr, canonical_url.ptr)) < 0)
22261344 225 goto on_error;
617bfdf4
CMN
226 }
227
baaa8a44 228 if (fetch != NULL) {
77254990
CMN
229 if ((error = add_refspec(remote, fetch, true)) < 0)
230 goto on_error;
231
232 /* only write for non-anonymous remotes */
233 if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0)
baaa8a44 234 goto on_error;
d3cd7da5 235
1ef3f0ce
DC
236 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
237 goto on_error;
238
69f0032b 239 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
1ef3f0ce
DC
240 goto on_error;
241
d3cd7da5 242 /* Move the data over to where the matching functions can find them */
69f0032b 243 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
d3cd7da5 244 goto on_error;
baaa8a44
CMN
245 }
246
35a8a8c5 247 /* A remote without a name doesn't download tags */
215af2cc 248 if (!name)
c648d4a8 249 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
35a8a8c5
CMN
250 else
251 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
252
c648d4a8 253
22261344
CMN
254 git_buf_free(&var);
255
778e1c73 256 *out = remote;
a8846da7 257 error = 0;
baaa8a44
CMN
258
259on_error:
a8846da7
ET
260 if (error)
261 git_remote_free(remote);
262
1ef3f0ce 263 git_config_free(config);
12f32d91 264 git_buf_free(&canonical_url);
22261344 265 git_buf_free(&var);
44f36f6e 266 return error;
778e1c73
CMN
267}
268
592f466c
BS
269static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
270{
271 int error;
272 git_remote *remote;
273
209425ce 274 error = git_remote_lookup(&remote, repo, name);
592f466c
BS
275
276 if (error == GIT_ENOTFOUND)
277 return 0;
278
279 if (error < 0)
280 return error;
281
282 git_remote_free(remote);
283
284 giterr_set(
285 GITERR_CONFIG,
286 "Remote '%s' already exists.", name);
287
288 return GIT_EEXISTS;
289}
290
f19304d2 291
874dcb25
BS
292int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
293{
294 git_buf buf = GIT_BUF_INIT;
295 int error;
296
874dcb25
BS
297 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
298 return -1;
299
a68e217f 300 error = git_remote_create_with_fetchspec(out, repo, name, url, git_buf_cstr(&buf));
874dcb25
BS
301 git_buf_free(&buf);
302
a68e217f 303 return error;
874dcb25
BS
304}
305
40b99d05
VG
306int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
307{
40b99d05
VG
308 git_remote *remote = NULL;
309 int error;
310
311 if ((error = ensure_remote_name_is_valid(name)) < 0)
312 return error;
313
314 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
315 return error;
874dcb25 316
0fe522d1 317 if (create_internal(&remote, repo, name, url, fetch) < 0)
874dcb25
BS
318 goto on_error;
319
c5193e3c 320 *out = remote;
321
874dcb25
BS
322 return 0;
323
324on_error:
c5193e3c 325 git_remote_free(remote);
874dcb25
BS
326 return -1;
327}
328
ae5b9362 329int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
874dcb25 330{
ae5b9362 331 return create_internal(out, repo, NULL, url, NULL);
874dcb25
BS
332}
333
991b2840 334int git_remote_dup(git_remote **dest, git_remote *source)
40ef47dd 335{
70f7484d 336 size_t i;
991b2840 337 int error = 0;
70f7484d 338 git_refspec *spec;
40ef47dd
AS
339 git_remote *remote = git__calloc(1, sizeof(git_remote));
340 GITERR_CHECK_ALLOC(remote);
341
40ef47dd
AS
342 if (source->name != NULL) {
343 remote->name = git__strdup(source->name);
344 GITERR_CHECK_ALLOC(remote->name);
345 }
346
347 if (source->url != NULL) {
348 remote->url = git__strdup(source->url);
ec0c4c40 349 GITERR_CHECK_ALLOC(remote->url);
40ef47dd
AS
350 }
351
352 if (source->pushurl != NULL) {
353 remote->pushurl = git__strdup(source->pushurl);
1697cd6f 354 GITERR_CHECK_ALLOC(remote->pushurl);
40ef47dd
AS
355 }
356
357 remote->repo = source->repo;
40ef47dd 358 remote->download_tags = source->download_tags;
5f473947 359 remote->prune_refs = source->prune_refs;
40ef47dd 360
991b2840
AS
361 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
362 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
363 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
364 error = -1;
365 goto cleanup;
40ef47dd
AS
366 }
367
70f7484d
CMN
368 git_vector_foreach(&source->refspecs, i, spec) {
369 if ((error = add_refspec(remote, spec->string, !spec->push)) < 0)
370 goto cleanup;
371 }
991b2840 372
40ef47dd
AS
373 *dest = remote;
374
991b2840
AS
375cleanup:
376
991b2840
AS
377 if (error < 0)
378 git__free(remote);
379
380 return error;
40ef47dd
AS
381}
382
4330ab26
CMN
383struct refspec_cb_data {
384 git_remote *remote;
385 int fetch;
386};
387
388static int refspec_cb(const git_config_entry *entry, void *payload)
389{
96869a4e 390 struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
25e0b157 391 return add_refspec(data->remote, entry->value, data->fetch);
4330ab26
CMN
392}
393
bf6bebe2 394static int get_optional_config(
c9ffa84b 395 bool *found, git_config *config, git_buf *buf,
396 git_config_foreach_cb cb, void *payload)
bf6bebe2
RB
397{
398 int error = 0;
399 const char *key = git_buf_cstr(buf);
400
401 if (git_buf_oom(buf))
402 return -1;
403
404 if (cb != NULL)
4efa3290 405 error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
bf6bebe2
RB
406 else
407 error = git_config_get_string(payload, config, key);
408
c9ffa84b 409 if (found)
410 *found = !error;
411
bf6bebe2
RB
412 if (error == GIT_ENOTFOUND) {
413 giterr_clear();
414 error = 0;
415 }
416
bf6bebe2
RB
417 return error;
418}
419
209425ce 420int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
421{
422 git_remote *remote;
f0f3a18a 423 git_buf buf = GIT_BUF_INIT;
9c82357b 424 const char *val;
4376f7f6 425 int error = 0;
9462c471 426 git_config *config;
96869a4e 427 struct refspec_cb_data data = { NULL };
c9ffa84b 428 bool optional_setting_found = false, found;
4330ab26 429
9462c471
VM
430 assert(out && repo && name);
431
032ba9e4 432 if ((error = ensure_remote_name_is_valid(name)) < 0)
433 return error;
434
ac99d86b 435 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
29c4cb09 436 return error;
4bef3565 437
392702ee 438 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 439 GITERR_CHECK_ALLOC(remote);
9c82357b 440
9c82357b 441 remote->name = git__strdup(name);
4376f7f6 442 GITERR_CHECK_ALLOC(remote->name);
9c82357b 443
25e0b157
RB
444 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
445 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
2cdd5c57 446 git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 ||
25e0b157 447 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
2fb9d6de 448 error = -1;
449 goto cleanup;
450 }
d88d4311 451
25e0b157 452 if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
2fb9d6de 453 goto cleanup;
9c82357b 454
c9ffa84b 455 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
9c82357b 456 goto cleanup;
bf6bebe2 457
c9ffa84b 458 optional_setting_found |= found;
459
9462c471 460 remote->repo = repo;
35a8a8c5 461 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
c9ffa84b 462
463 if (found && strlen(val) > 0) {
ec0c4c40 464 remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
c9ffa84b 465 GITERR_CHECK_ALLOC(remote->url);
466 }
9c82357b 467
bf6bebe2 468 val = NULL;
3ed4b501 469 git_buf_clear(&buf);
bf6bebe2 470 git_buf_printf(&buf, "remote.%s.pushurl", name);
3ed4b501 471
c9ffa84b 472 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
3ed4b501 473 goto cleanup;
3ed4b501 474
c9ffa84b 475 optional_setting_found |= found;
476
477 if (!optional_setting_found) {
478 error = GIT_ENOTFOUND;
d723dbed 479 giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name);
3ed4b501 480 goto cleanup;
c9ffa84b 481 }
3ed4b501 482
c9ffa84b 483 if (found && strlen(val) > 0) {
ec0c4c40 484 remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
3ed4b501
SC
485 GITERR_CHECK_ALLOC(remote->pushurl);
486 }
487
4330ab26
CMN
488 data.remote = remote;
489 data.fetch = true;
96869a4e 490
f0f3a18a 491 git_buf_clear(&buf);
bf6bebe2
RB
492 git_buf_printf(&buf, "remote.%s.fetch", name);
493
c9ffa84b 494 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
2fb9d6de 495 goto cleanup;
9c82357b 496
4330ab26 497 data.fetch = false;
bf6bebe2
RB
498 git_buf_clear(&buf);
499 git_buf_printf(&buf, "remote.%s.push", name);
9c82357b 500
c9ffa84b 501 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
9c82357b
CMN
502 goto cleanup;
503
24f2f94e
CMN
504 if (download_tags_value(remote, config) < 0)
505 goto cleanup;
506
1ef3f0ce
DC
507 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
508 goto cleanup;
509
510 /* Move the data over to where the matching functions can find them */
69f0032b 511 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1ef3f0ce
DC
512 goto cleanup;
513
514 *out = remote;
515
516cleanup:
517 git_config_free(config);
518 git_buf_free(&buf);
519
520 if (error < 0)
521 git_remote_free(remote);
522
523 return error;
524}
525
526static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
527{
528 git_buf buf = GIT_BUF_INIT;
529 int error = 0;
530
5f473947
L
531 git_buf_printf(&buf, "remote.%s.prune", name);
532
533 if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
534 if (error == GIT_ENOTFOUND) {
535 giterr_clear();
536
537 if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
538 if (error == GIT_ENOTFOUND) {
539 giterr_clear();
66b71ea5 540 error = 0;
5f473947
L
541 }
542 }
543 }
544 }
545
f0f3a18a 546 git_buf_free(&buf);
9c82357b
CMN
547 return error;
548}
549
4330ab26 550static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
4fe5520a 551{
4330ab26 552 git_buf name = GIT_BUF_INIT;
66566516 553 unsigned int push;
4330ab26
CMN
554 const char *dir;
555 size_t i;
bf6bebe2 556 int error = 0;
3793fa9b 557 const char *cname;
4fe5520a 558
4330ab26
CMN
559 push = direction == GIT_DIRECTION_PUSH;
560 dir = push ? "push" : "fetch";
4fe5520a 561
4330ab26
CMN
562 if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
563 return -1;
3793fa9b 564 cname = git_buf_cstr(&name);
4fe5520a 565
4330ab26 566 /* Clear out the existing config */
bf6bebe2 567 while (!error)
3793fa9b 568 error = git_config_delete_multivar(config, cname, ".*");
4fe5520a 569
4330ab26
CMN
570 if (error != GIT_ENOTFOUND)
571 return error;
572
1be680c4 573 for (i = 0; i < remote->refspecs.length; i++) {
4330ab26 574 git_refspec *spec = git_vector_get(&remote->refspecs, i);
4330ab26
CMN
575
576 if (spec->push != push)
577 continue;
578
376454d0
DRT
579 // "$^" is a unmatcheable regexp: it will not match anything at all, so
580 // all values will be considered new and we will not replace any
581 // present value.
bf6bebe2 582 if ((error = git_config_set_multivar(
376454d0 583 config, cname, "$^", spec->string)) < 0) {
4330ab26
CMN
584 goto cleanup;
585 }
586 }
587
588 giterr_clear();
589 error = 0;
4fe5520a 590
591cleanup:
592 git_buf_free(&name);
4fe5520a 593
594 return error;
595}
596
df705148 597const char *git_remote_name(const git_remote *remote)
9c82357b 598{
4bef3565 599 assert(remote);
9c82357b
CMN
600 return remote->name;
601}
602
85e1eded
ES
603git_repository *git_remote_owner(const git_remote *remote)
604{
605 assert(remote);
606 return remote->repo;
607}
608
df705148 609const char *git_remote_url(const git_remote *remote)
9c82357b 610{
4bef3565 611 assert(remote);
9c82357b
CMN
612 return remote->url;
613}
614
22261344 615static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
76501590 616{
22261344
CMN
617 git_config *cfg;
618 git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
619 int error;
76501590 620
22261344 621 assert(repo && remote);
76501590 622
22261344
CMN
623 if ((error = ensure_remote_name_is_valid(remote)) < 0)
624 return error;
625
626 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
627 return error;
628
629 if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
630 return error;
631
632 if (url) {
633 if ((error = canonicalize_url(&canonical_url, url)) < 0)
634 goto cleanup;
635
636 error = git_config_set_string(cfg, buf.ptr, url);
637 } else {
638 error = git_config_delete_entry(cfg, buf.ptr);
639 }
640
641cleanup:
642 git_buf_free(&canonical_url);
643 git_buf_free(&buf);
644
645 return error;
646}
647
648int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
649{
650 return set_url(repo, remote, CONFIG_URL_FMT, url);
76501590
SC
651}
652
df705148 653const char *git_remote_pushurl(const git_remote *remote)
76501590
SC
654{
655 assert(remote);
656 return remote->pushurl;
657}
658
22261344 659int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
76501590 660{
22261344 661 return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
76501590
SC
662}
663
eff5b499
SC
664const char* git_remote__urlfordirection(git_remote *remote, int direction)
665{
666 assert(remote);
667
b83c92dd 668 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
669
df705148 670 if (direction == GIT_DIRECTION_FETCH) {
eff5b499
SC
671 return remote->url;
672 }
673
df705148 674 if (direction == GIT_DIRECTION_PUSH) {
eff5b499
SC
675 return remote->pushurl ? remote->pushurl : remote->url;
676 }
677
678 return NULL;
679}
680
8f0104ec
CMN
681int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
682{
683 if (!t->set_callbacks || !cbs)
684 return 0;
685
686 return t->set_callbacks(t, cbs->sideband_progress, NULL,
687 cbs->certificate_check, cbs->payload);
688}
689
690int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks)
9ba49bb5 691{
9ba49bb5 692 git_transport *t;
c0c39025 693 const char *url;
41fb1ca0 694 int flags = GIT_TRANSPORTFLAGS_NONE;
80fc7d6b 695 int error;
8f0104ec 696 void *payload = NULL;
058b753c
CMN
697 git_cred_acquire_cb credentials = NULL;
698 git_transport_cb transport = NULL;
9ba49bb5 699
4bef3565
VM
700 assert(remote);
701
8f0104ec
CMN
702 if (callbacks) {
703 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
704 credentials = callbacks->credentials;
058b753c 705 transport = callbacks->transport;
8f0104ec
CMN
706 payload = callbacks->payload;
707 }
708
41fb1ca0
PK
709 t = remote->transport;
710
c0c39025 711 url = git_remote__urlfordirection(remote, direction);
80fc7d6b 712 if (url == NULL) {
44bc0c6a 713 giterr_set(GITERR_INVALID,
714 "Malformed remote '%s' - missing URL", remote->name);
eff5b499 715 return -1;
44bc0c6a 716 }
eff5b499 717
1697cd6f
PK
718 /* If we don't have a transport object yet, and the caller specified a
719 * custom transport factory, use that */
058b753c
CMN
720 if (!t && transport &&
721 (error = transport(&t, remote, payload)) < 0)
1697cd6f
PK
722 return error;
723
724 /* If we still don't have a transport, then use the global
725 * transport registrations which map URI schemes to transport factories */
80fc7d6b
ET
726 if (!t && (error = git_transport_new(&t, remote, url)) < 0)
727 return error;
9ba49bb5 728
8f0104ec
CMN
729 if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
730 (error = t->connect(t, url, credentials, payload, direction, flags)) != 0)
4376f7f6 731 goto on_error;
9ba49bb5
CMN
732
733 remote->transport = t;
734
4376f7f6 735 return 0;
9ba49bb5 736
4376f7f6
CMN
737on_error:
738 t->free(t);
613d5eb9
PK
739
740 if (t == remote->transport)
741 remote->transport = NULL;
742
80fc7d6b 743 return error;
9ba49bb5
CMN
744}
745
359dce72 746int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
9ba49bb5 747{
d88d4311
VM
748 assert(remote);
749
dc8adda4 750 if (!remote->transport) {
699dfcc3 751 giterr_set(GITERR_NET, "this remote has never connected");
dc8adda4
JG
752 return -1;
753 }
754
359dce72 755 return remote->transport->ls(out, size, remote->transport);
9ba49bb5
CMN
756}
757
613d5eb9
PK
758int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
759{
760 git_config *cfg;
9a97f49e 761 git_config_entry *ce = NULL;
9f77b3f6 762 const char *val = NULL;
80fc7d6b 763 int error;
613d5eb9
PK
764
765 assert(remote);
766
a71c27cc 767 if (!proxy_url || !remote->repo)
613d5eb9
PK
768 return -1;
769
770 *proxy_url = NULL;
771
80fc7d6b
ET
772 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
773 return error;
613d5eb9
PK
774
775 /* Go through the possible sources for proxy configuration, from most specific
776 * to least specific. */
777
778 /* remote.<name>.proxy config setting */
9f77b3f6 779 if (remote->name && remote->name[0]) {
613d5eb9
PK
780 git_buf buf = GIT_BUF_INIT;
781
80fc7d6b
ET
782 if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
783 return error;
613d5eb9 784
9f77b3f6
RB
785 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
786 git_buf_free(&buf);
613d5eb9 787
9f77b3f6 788 if (error < 0)
80fc7d6b 789 return error;
613d5eb9 790
9f77b3f6
RB
791 if (ce && ce->value) {
792 val = ce->value;
793 goto found;
794 }
613d5eb9
PK
795 }
796
797 /* http.proxy config setting */
9f77b3f6 798 if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
80fc7d6b 799 return error;
9f77b3f6
RB
800 if (ce && ce->value) {
801 val = ce->value;
802 goto found;
803 }
613d5eb9
PK
804
805 /* HTTP_PROXY / HTTPS_PROXY environment variables */
806 val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
807
9f77b3f6
RB
808found:
809 if (val && val[0]) {
613d5eb9
PK
810 *proxy_url = git__strdup(val);
811 GITERR_CHECK_ALLOC(*proxy_url);
613d5eb9 812 }
9a97f49e 813 git_config_entry_free(ce);
613d5eb9
PK
814
815 return 0;
816}
817
af613ecd
CMN
818/* DWIM `refspecs` based on `refs` and append the output to `out` */
819static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
d8488457 820{
af613ecd 821 size_t i;
d8488457 822 git_refspec *spec;
d8488457
CMN
823
824 git_vector_foreach(refspecs, i, spec) {
af613ecd
CMN
825 if (git_refspec__dwim_one(out, spec, refs) < 0)
826 return -1;
827 }
d8488457 828
af613ecd
CMN
829 return 0;
830}
d8488457 831
af613ecd
CMN
832static void free_refspecs(git_vector *vec)
833{
834 size_t i;
835 git_refspec *spec;
d8488457 836
af613ecd
CMN
837 git_vector_foreach(vec, i, spec) {
838 git_refspec__free(spec);
839 git__free(spec);
d8488457
CMN
840 }
841
af613ecd 842 git_vector_clear(vec);
d8488457
CMN
843}
844
845static int remote_head_cmp(const void *_a, const void *_b)
846{
847 const git_remote_head *a = (git_remote_head *) _a;
848 const git_remote_head *b = (git_remote_head *) _b;
849
850 return git__strcmp_cb(a->name, b->name);
851}
852
877cde76
CMN
853static int ls_to_vector(git_vector *out, git_remote *remote)
854{
855 git_remote_head **heads;
856 size_t heads_len, i;
857
858 if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
859 return -1;
860
861 if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
862 return -1;
863
864 for (i = 0; i < heads_len; i++) {
865 if (git_vector_insert(out, heads[i]) < 0)
866 return -1;
867 }
868
869 return 0;
870}
871
8f0104ec 872int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
48a65a07 873{
eecc1772 874 int error = -1;
3f894205 875 size_t i;
2785544f 876 git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
8f0104ec 877 const git_remote_callbacks *cbs = NULL;
95057b85 878
1e3b8ed5 879 assert(remote);
4bef3565 880
8f0104ec
CMN
881 if (opts) {
882 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
883 cbs = &opts->callbacks;
884 }
885
886 if (!git_remote_connected(remote) &&
887 (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0)
888 goto on_error;
889
877cde76 890 if (ls_to_vector(&refs, remote) < 0)
d8488457 891 return -1;
d8488457 892
3f894205
CMN
893 if ((git_vector_init(&specs, 0, NULL)) < 0)
894 goto on_error;
895
c5837cad 896 remote->passed_refspecs = 0;
8e398e4c 897 if (!refspecs || !refspecs->count) {
3f894205
CMN
898 to_active = &remote->refspecs;
899 } else {
900 for (i = 0; i < refspecs->count; i++) {
901 if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
902 goto on_error;
903 }
904
905 to_active = &specs;
c5837cad 906 remote->passed_refspecs = 1;
3f894205
CMN
907 }
908
2cdd5c57
CMN
909 free_refspecs(&remote->passive_refspecs);
910 if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
911 goto on_error;
af613ecd 912
2cdd5c57 913 free_refspecs(&remote->active_refspecs);
3f894205 914 error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
2cdd5c57 915
877cde76 916 git_vector_free(&refs);
3f894205
CMN
917 free_refspecs(&specs);
918 git_vector_free(&specs);
877cde76
CMN
919
920 if (error < 0)
25e0b157 921 return error;
d8488457 922
c070ac64
POL
923 if (remote->push) {
924 git_push_free(remote->push);
925 remote->push = NULL;
926 }
927
35a8a8c5 928 if ((error = git_fetch_negotiate(remote, opts)) < 0)
4376f7f6 929 return error;
95057b85 930
8f0104ec 931 return git_fetch_download_pack(remote, cbs);
3f894205
CMN
932
933on_error:
934 git_vector_free(&refs);
935 free_refspecs(&specs);
936 git_vector_free(&specs);
937 return error;
48a65a07
CMN
938}
939
c3ab1e5a
BS
940int git_remote_fetch(
941 git_remote *remote,
3f894205 942 const git_strarray *refspecs,
8f0104ec 943 const git_fetch_options *opts,
c3ab1e5a 944 const char *reflog_message)
fe3a40a4 945{
3eff2a57 946 int error, update_fetchhead = 1;
35a8a8c5 947 git_remote_autotag_option_t tagopt = remote->download_tags;
6fb373a0 948 bool prune = false;
db55bb73 949 git_buf reflog_msg_buf = GIT_BUF_INIT;
8f0104ec
CMN
950 const git_remote_callbacks *cbs = NULL;
951
952 if (opts) {
953 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
954 cbs = &opts->callbacks;
3eff2a57 955 update_fetchhead = opts->update_fetchhead;
35a8a8c5 956 tagopt = opts->download_tags;
8f0104ec 957 }
fe3a40a4
CMN
958
959 /* Connect and download everything */
8f0104ec 960 if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0)
fe3a40a4
CMN
961 return error;
962
8f0104ec 963 error = git_remote_download(remote, refspecs, opts);
fe3a40a4
CMN
964
965 /* We don't need to be connected anymore */
966 git_remote_disconnect(remote);
967
06a8f5c3
BL
968 /* If the download failed, return the error */
969 if (error != 0)
970 return error;
971
db55bb73
BS
972 /* Default reflog message */
973 if (reflog_message)
974 git_buf_sets(&reflog_msg_buf, reflog_message);
975 else {
976 git_buf_printf(&reflog_msg_buf, "fetch %s",
977 remote->name ? remote->name : remote->url);
978 }
979
fe3a40a4 980 /* Create "remote/foo" branches for all remote branches */
35a8a8c5 981 error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
db55bb73 982 git_buf_free(&reflog_msg_buf);
8c13eaed
CMN
983 if (error < 0)
984 return error;
985
6fb373a0
CMN
986 if (opts && opts->prune == GIT_FETCH_PRUNE)
987 prune = true;
988 else if (opts && opts->prune == GIT_FETCH_PRUNE_FALLBACK && remote->prune_refs)
989 prune = true;
990 else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
991 prune = false;
992 else
993 prune = remote->prune_refs;
994
995 if (prune)
8f0104ec 996 error = git_remote_prune(remote, cbs);
8c13eaed 997
db55bb73 998 return error;
fe3a40a4
CMN
999}
1000
b0f6e45d
ET
1001static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
1002{
1003 unsigned int i;
1004 git_remote_head *remote_ref;
1005
1006 assert(update_heads && fetchspec_src);
1007
1008 *out = NULL;
7d4b65f6 1009
1010 git_vector_foreach(update_heads, i, remote_ref) {
1011 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
1012 *out = remote_ref;
1013 break;
b0f6e45d
ET
1014 }
1015 }
1016
1017 return 0;
1018}
1019
2c9b9c8b
CMN
1020static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
1021{
1022 int error = 0;
1023 git_repository *repo;
1024 git_buf upstream_remote = GIT_BUF_INIT;
1025 git_buf upstream_name = GIT_BUF_INIT;
1026
1027 repo = git_remote_owner(remote);
1028
1029 if ((!git_reference__is_branch(ref_name)) ||
1030 !git_remote_name(remote) ||
1031 (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
1032 git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
1033 (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
1034 !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
1035 (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
1036 /* Not an error if there is no upstream */
1037 if (error == GIT_ENOTFOUND) {
1038 giterr_clear();
1039 error = 0;
1040 }
1041
1042 *update = 0;
1043 } else {
1044 *update = 1;
1045 }
1046
1047 git_buf_free(&upstream_remote);
1048 git_buf_free(&upstream_name);
1049 return error;
1050}
1051
f49819aa 1052static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
1053{
1054 git_reference *resolved_ref = NULL;
b0f6e45d 1055 git_buf remote_name = GIT_BUF_INIT;
f49819aa 1056 git_config *config = NULL;
e235db02 1057 const char *ref_name;
2c9b9c8b 1058 int error = 0, update;
b0f6e45d 1059
4330ab26 1060 assert(out && spec && ref);
b0f6e45d
ET
1061
1062 *out = NULL;
1063
67d4997a
CMN
1064 error = git_reference_resolve(&resolved_ref, ref);
1065
1066 /* If we're in an unborn branch, let's pretend nothing happened */
1067 if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1068 ref_name = git_reference_symbolic_target(ref);
1069 error = 0;
1070 } else {
1071 ref_name = git_reference_name(resolved_ref);
1072 }
1073
2c9b9c8b 1074 if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
b0f6e45d 1075 goto cleanup;
b0f6e45d 1076
2c9b9c8b
CMN
1077 if (update)
1078 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
b0f6e45d
ET
1079
1080cleanup:
f7fcb18f 1081 git_buf_free(&remote_name);
b0f6e45d 1082 git_reference_free(resolved_ref);
f49819aa 1083 git_config_free(config);
b0f6e45d
ET
1084 return error;
1085}
1086
4330ab26 1087static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 1088{
b0f6e45d
ET
1089 git_reference *head_ref = NULL;
1090 git_fetchhead_ref *fetchhead_ref;
1091 git_remote_head *remote_ref, *merge_remote_ref;
1092 git_vector fetchhead_refs;
1093 bool include_all_fetchheads;
1094 unsigned int i = 0;
1095 int error = 0;
1096
1097 assert(remote);
1098
404eadb0
CMN
1099 /* no heads, nothing to do */
1100 if (update_heads->length == 0)
1101 return 0;
1102
b0f6e45d
ET
1103 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
1104 return -1;
1105
1106 /* Iff refspec is * (but not subdir slash star), include tags */
1107 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
1108
1109 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
1110 if (git_refspec_is_wildcard(spec)) {
1111 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
f49819aa 1112 (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
1113 goto cleanup;
1114 } else {
1115 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
1116 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
1117 goto cleanup;
1118 }
1119
1120 /* Create the FETCH_HEAD file */
7d4b65f6 1121 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
1122 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
1123
1124 if (!include_all_fetchheads &&
1125 !git_refspec_src_matches(spec, remote_ref->name) &&
1126 !merge_this_fetchhead)
1127 continue;
1128
1129 if (git_fetchhead_ref_create(&fetchhead_ref,
1130 &remote_ref->oid,
1131 merge_this_fetchhead,
1132 remote_ref->name,
1133 git_remote_url(remote)) < 0)
1134 goto cleanup;
1135
1136 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
1137 goto cleanup;
1138 }
1139
1140 git_fetchhead_write(remote->repo, &fetchhead_refs);
1141
1142cleanup:
1143 for (i = 0; i < fetchhead_refs.length; ++i)
1144 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
1145
1146 git_vector_free(&fetchhead_refs);
1147 git_reference_free(head_ref);
1148
1149 return error;
1150}
1151
59ff8b67
CMN
1152/**
1153 * Generate a list of candidates for pruning by getting a list of
1154 * references which match the rhs of an active refspec.
1155 */
1156static int prune_candidates(git_vector *candidates, git_remote *remote)
5f473947
L
1157{
1158 git_strarray arr = { 0 };
59ff8b67 1159 size_t i;
5f473947
L
1160 int error;
1161
1162 if ((error = git_reference_list(&arr, remote->repo)) < 0)
1163 return error;
1164
59ff8b67
CMN
1165 for (i = 0; i < arr.count; i++) {
1166 const char *refname = arr.strings[i];
1167 char *refname_dup;
1168
1169 if (!git_remote__matching_dst_refspec(remote, refname))
1170 continue;
1171
1172 refname_dup = git__strdup(refname);
1173 GITERR_CHECK_ALLOC(refname_dup);
1174
1175 if ((error = git_vector_insert(candidates, refname_dup)) < 0)
1176 goto out;
1177 }
1178
1179out:
1180 git_strarray_free(&arr);
1181 return error;
1182}
1183
1184static int find_head(const void *_a, const void *_b)
1185{
1186 git_remote_head *a = (git_remote_head *) _a;
1187 git_remote_head *b = (git_remote_head *) _b;
1188
1189 return strcmp(a->name, b->name);
1190}
1191
8f0104ec 1192int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
59ff8b67
CMN
1193{
1194 size_t i, j;
1195 git_vector remote_refs = GIT_VECTOR_INIT;
1196 git_vector candidates = GIT_VECTOR_INIT;
1197 const git_refspec *spec;
1198 const char *refname;
1199 int error;
1200 git_oid zero_id = {{ 0 }};
1201
8f0104ec
CMN
1202 if (callbacks)
1203 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1204
5f473947
L
1205 if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1206 goto cleanup;
1207
59ff8b67 1208 git_vector_set_cmp(&remote_refs, find_head);
5f473947 1209
59ff8b67
CMN
1210 if ((error = prune_candidates(&candidates, remote)) < 0)
1211 goto cleanup;
5f473947 1212
59ff8b67
CMN
1213 /*
1214 * Remove those entries from the candidate list for which we
1215 * can find a remote reference in at least one refspec.
1216 */
1217 git_vector_foreach(&candidates, i, refname) {
1218 git_vector_foreach(&remote->active_refspecs, j, spec) {
1219 git_buf buf = GIT_BUF_INIT;
1220 size_t pos;
1221 char *src_name;
1222 git_remote_head key = {0};
1223
1224 if (!git_refspec_dst_matches(spec, refname))
5f473947
L
1225 continue;
1226
59ff8b67
CMN
1227 if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
1228 goto cleanup;
5f473947 1229
59ff8b67
CMN
1230 key.name = (char *) git_buf_cstr(&buf);
1231 error = git_vector_search(&pos, &remote_refs, &key);
1232 git_buf_free(&buf);
5f473947 1233
59ff8b67
CMN
1234 if (error < 0 && error != GIT_ENOTFOUND)
1235 goto cleanup;
5f473947 1236
59ff8b67 1237 if (error == GIT_ENOTFOUND)
5f473947
L
1238 continue;
1239
59ff8b67
CMN
1240 /* if we did find a source, remove it from the candiates */
1241 if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
1242 goto cleanup;
1243
1244 git__free(src_name);
1245 break;
5f473947
L
1246 }
1247 }
1248
59ff8b67
CMN
1249 /*
1250 * For those candidates still left in the list, we need to
1251 * remove them. We do not remove symrefs, as those are for
1252 * stuff like origin/HEAD which will never match, but we do
1253 * not want to remove them.
1254 */
1255 git_vector_foreach(&candidates, i, refname) {
1256 git_reference *ref;
1257 git_oid id;
1258
1259 if (refname == NULL)
1260 continue;
1261
1262 error = git_reference_lookup(&ref, remote->repo, refname);
1263 /* as we want it gone, let's not consider this an error */
1264 if (error == GIT_ENOTFOUND)
1265 continue;
1266
1267 if (error < 0)
1268 goto cleanup;
1269
1270 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1271 git_reference_free(ref);
1272 continue;
1273 }
1274
1275 git_oid_cpy(&id, git_reference_target(ref));
1276 error = git_reference_delete(ref);
1277 git_reference_free(ref);
1278 if (error < 0)
1279 goto cleanup;
1280
8f0104ec
CMN
1281 if (callbacks && callbacks->update_tips)
1282 error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
59ff8b67
CMN
1283
1284 if (error < 0)
1285 goto cleanup;
1286 }
1287
5f473947 1288cleanup:
5f473947 1289 git_vector_free(&remote_refs);
59ff8b67 1290 git_vector_free_deep(&candidates);
5f473947
L
1291 return error;
1292}
1293
c3ab1e5a
BS
1294static int update_tips_for_spec(
1295 git_remote *remote,
8f0104ec 1296 const git_remote_callbacks *callbacks,
3eff2a57 1297 int update_fetchhead,
35a8a8c5 1298 git_remote_autotag_option_t tagopt,
c3ab1e5a
BS
1299 git_refspec *spec,
1300 git_vector *refs,
c3ab1e5a 1301 const char *log_message)
441f57c2 1302{
a37ddf7e 1303 int error = 0, autotag;
517bda19 1304 unsigned int i = 0;
97769280 1305 git_buf refname = GIT_BUF_INIT;
f184836b 1306 git_oid old;
a37ddf7e 1307 git_odb *odb;
441f57c2
CMN
1308 git_remote_head *head;
1309 git_reference *ref;
a37ddf7e 1310 git_refspec tagspec;
4330ab26 1311 git_vector update_heads;
441f57c2 1312
4bef3565
VM
1313 assert(remote);
1314
acd17006 1315 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
1316 return -1;
1317
3230a44f 1318 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
1319 return -1;
1320
41fb1ca0 1321 /* Make a copy of the transport's refs */
4330ab26 1322 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 1323 return -1;
585a2eb7 1324
4330ab26
CMN
1325 for (; i < refs->length; ++i) {
1326 head = git_vector_get(refs, i);
9063be1f 1327 autotag = 0;
517bda19 1328
a37ddf7e
CMN
1329 /* Ignore malformed ref names (which also saves us from tag^{} */
1330 if (!git_reference_is_valid_name(head->name))
1331 continue;
1332
e284c451 1333 if (git_refspec_src_matches(&tagspec, head->name)) {
35a8a8c5 1334 if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f 1335
35a8a8c5 1336 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
e284c451 1337 autotag = 1;
a37ddf7e 1338
e284c451
POL
1339 git_buf_clear(&refname);
1340 if (git_buf_puts(&refname, head->name) < 0)
1341 goto on_error;
1342 } else {
a37ddf7e 1343 continue;
e284c451
POL
1344 }
1345 } else if (git_refspec_src_matches(spec, head->name) && spec->dst) {
1346 if (git_refspec_transform(&refname, spec, head->name) < 0)
a37ddf7e
CMN
1347 goto on_error;
1348 } else {
1349 continue;
1350 }
1351
e284c451 1352 /* In autotag mode, only create tags for objects already in db */
a37ddf7e
CMN
1353 if (autotag && !git_odb_exists(odb, &head->oid))
1354 continue;
f184836b 1355
d908351a 1356 if (!autotag && git_vector_insert(&update_heads, head) < 0)
b0f6e45d
ET
1357 goto on_error;
1358
2508cc66 1359 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 1360 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
1361 goto on_error;
1362
d908351a 1363 if (error == GIT_ENOTFOUND) {
f184836b
CMN
1364 memset(&old, 0, GIT_OID_RAWSZ);
1365
d908351a
L
1366 if (autotag && git_vector_insert(&update_heads, head) < 0)
1367 goto on_error;
1368 }
1369
b7f167da 1370 if (!git_oid__cmp(&old, &head->oid))
f184836b 1371 continue;
441f57c2 1372
a37ddf7e 1373 /* In autotag mode, don't overwrite any locally-existing tags */
c3ab1e5a 1374 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
659cf202 1375 log_message);
a37ddf7e 1376 if (error < 0 && error != GIT_EEXISTS)
944d250f 1377 goto on_error;
39157563
CMN
1378
1379 git_reference_free(ref);
f184836b 1380
8f0104ec
CMN
1381 if (callbacks && callbacks->update_tips != NULL) {
1382 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
f184836b
CMN
1383 goto on_error;
1384 }
441f57c2
CMN
1385 }
1386
3eff2a57 1387 if (update_fetchhead &&
4330ab26 1388 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
1389 goto on_error;
1390
b0f6e45d 1391 git_vector_free(&update_heads);
a37ddf7e 1392 git_refspec__free(&tagspec);
97769280 1393 git_buf_free(&refname);
f184836b
CMN
1394 return 0;
1395
1396on_error:
b0f6e45d 1397 git_vector_free(&update_heads);
a37ddf7e 1398 git_refspec__free(&tagspec);
f184836b
CMN
1399 git_buf_free(&refname);
1400 return -1;
97769280 1401
441f57c2
CMN
1402}
1403
c5837cad
CMN
1404/**
1405 * Iteration over the three vectors, with a pause whenever we find a match
1406 *
1407 * On each stop, we store the iteration stat in the inout i,j,k
1408 * parameters, and return the currently matching passive refspec as
1409 * well as the head which we matched.
1410 */
1411static int next_head(const git_remote *remote, git_vector *refs,
1412 git_refspec **out_spec, git_remote_head **out_head,
1413 size_t *out_i, size_t *out_j, size_t *out_k)
1414{
1415 const git_vector *active, *passive;
1416 git_remote_head *head;
1417 git_refspec *spec, *passive_spec;
1418 size_t i, j, k;
1419
1420 active = &remote->active_refspecs;
1421 passive = &remote->passive_refspecs;
1422
1423 i = *out_i;
1424 j = *out_j;
1425 k = *out_k;
1426
1427 for (; i < refs->length; i++) {
1428 head = git_vector_get(refs, i);
1429
1430 if (!git_reference_is_valid_name(head->name))
1431 continue;
1432
1433 for (; j < active->length; j++) {
1434 spec = git_vector_get(active, j);
1435
1436 if (!git_refspec_src_matches(spec, head->name))
1437 continue;
1438
1439 for (; k < passive->length; k++) {
1440 passive_spec = git_vector_get(passive, k);
1441
1442 if (!git_refspec_src_matches(passive_spec, head->name))
1443 continue;
1444
1445 *out_spec = passive_spec;
1446 *out_head = head;
1447 *out_i = i;
1448 *out_j = j;
1449 *out_k = k + 1;
1450 return 0;
1451
1452 }
1453 k = 0;
1454 }
1455 j = 0;
1456 }
1457
1458 return GIT_ITEROVER;
1459}
1460
9566ce43
CMN
1461static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
1462 git_vector *refs, const char *msg)
c5837cad
CMN
1463{
1464 size_t i, j, k;
1465 git_refspec *spec;
1466 git_remote_head *head;
1467 git_reference *ref;
1468 git_buf refname = GIT_BUF_INIT;
9566ce43 1469 int error = 0;
c5837cad
CMN
1470
1471 i = j = k = 0;
1472
1473 while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
9566ce43 1474 git_oid old = {{ 0 }};
c5837cad
CMN
1475 /*
1476 * If we got here, there is a refspec which was used
1477 * for fetching which matches the source of one of the
1478 * passive refspecs, so we should update that
1479 * remote-tracking branch, but not add it to
1480 * FETCH_HEAD
1481 */
1482
9566ce43 1483 git_buf_clear(&refname);
c5837cad 1484 if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
9566ce43 1485 goto cleanup;
c5837cad 1486
9566ce43
CMN
1487 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1488 if (error < 0 && error != GIT_ENOTFOUND)
1489 goto cleanup;
1490
1491 if (!git_oid_cmp(&old, &head->oid))
1492 continue;
c5837cad 1493
9566ce43
CMN
1494 /* If we did find a current reference, make sure we haven't lost a race */
1495 if (error)
1496 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1497 else
1498 error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
1499 git_reference_free(ref);
c5837cad 1500 if (error < 0)
9566ce43
CMN
1501 goto cleanup;
1502
1503 if (callbacks && callbacks->update_tips != NULL) {
1504 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1505 goto cleanup;
1506 }
c5837cad
CMN
1507 }
1508
9566ce43
CMN
1509 if (error == GIT_ITEROVER)
1510 error = 0;
1511
1512cleanup:
1513 git_buf_free(&refname);
1514 return error;
c5837cad
CMN
1515}
1516
c3ab1e5a
BS
1517int git_remote_update_tips(
1518 git_remote *remote,
8f0104ec 1519 const git_remote_callbacks *callbacks,
3eff2a57 1520 int update_fetchhead,
35a8a8c5 1521 git_remote_autotag_option_t download_tags,
c3ab1e5a 1522 const char *reflog_message)
4330ab26 1523{
505b5d0c 1524 git_refspec *spec, tagspec;
cdedef40 1525 git_vector refs = GIT_VECTOR_INIT;
35a8a8c5 1526 git_remote_autotag_option_t tagopt;
505b5d0c 1527 int error;
4330ab26
CMN
1528 size_t i;
1529
fe794b2e
CMN
1530 /* push has its own logic hidden away in the push object */
1531 if (remote->push) {
8f0104ec 1532 return git_push_update_tips(remote->push, callbacks);
fe794b2e
CMN
1533 }
1534
505b5d0c
CMN
1535 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1536 return -1;
1537
877cde76
CMN
1538
1539 if ((error = ls_to_vector(&refs, remote)) < 0)
505b5d0c
CMN
1540 goto out;
1541
35a8a8c5
CMN
1542 if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_FALLBACK)
1543 tagopt = remote->download_tags;
1544 else
1545 tagopt = download_tags;
1546
1547 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1548 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
e284c451 1549 goto out;
505b5d0c 1550 }
4330ab26 1551
af613ecd 1552 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1553 if (spec->push)
1554 continue;
1555
35a8a8c5 1556 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
505b5d0c 1557 goto out;
4330ab26
CMN
1558 }
1559
c5837cad
CMN
1560 /* only try to do opportunisitic updates if the refpec lists differ */
1561 if (remote->passed_refspecs)
9566ce43 1562 error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
c5837cad 1563
505b5d0c 1564out:
877cde76 1565 git_vector_free(&refs);
505b5d0c 1566 git_refspec__free(&tagspec);
505b5d0c 1567 return error;
4330ab26
CMN
1568}
1569
11f6ad5f 1570int git_remote_connected(const git_remote *remote)
6ac3b707 1571{
4bef3565 1572 assert(remote);
41fb1ca0
PK
1573
1574 if (!remote->transport || !remote->transport->is_connected)
1575 return 0;
1576
1577 /* Ask the transport if it's connected. */
613d5eb9 1578 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
1579}
1580
f0d2ddbb
CMN
1581void git_remote_stop(git_remote *remote)
1582{
613d5eb9
PK
1583 assert(remote);
1584
1585 if (remote->transport && remote->transport->cancel)
41fb1ca0 1586 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
1587}
1588
4cf01e9a
CMN
1589void git_remote_disconnect(git_remote *remote)
1590{
4bef3565
VM
1591 assert(remote);
1592
41fb1ca0
PK
1593 if (git_remote_connected(remote))
1594 remote->transport->close(remote->transport);
4cf01e9a
CMN
1595}
1596
9c82357b
CMN
1597void git_remote_free(git_remote *remote)
1598{
2aae2188
CMN
1599 if (remote == NULL)
1600 return;
1601
42ea35c0
MS
1602 if (remote->transport != NULL) {
1603 git_remote_disconnect(remote);
1604
1605 remote->transport->free(remote->transport);
1606 remote->transport = NULL;
1607 }
1608
1609 git_vector_free(&remote->refs);
1610
af613ecd 1611 free_refspecs(&remote->refspecs);
4330ab26
CMN
1612 git_vector_free(&remote->refspecs);
1613
af613ecd
CMN
1614 free_refspecs(&remote->active_refspecs);
1615 git_vector_free(&remote->active_refspecs);
1616
2cdd5c57
CMN
1617 free_refspecs(&remote->passive_refspecs);
1618 git_vector_free(&remote->passive_refspecs);
1619
fe794b2e 1620 git_push_free(remote->push);
3286c408 1621 git__free(remote->url);
3ed4b501 1622 git__free(remote->pushurl);
3286c408 1623 git__free(remote->name);
3286c408 1624 git__free(remote);
9c82357b 1625}
8171998f 1626
106c12f1 1627static int remote_list_cb(const git_config_entry *entry, void *payload)
8171998f 1628{
25e0b157 1629 git_vector *list = payload;
106c12f1
RB
1630 const char *name = entry->name + strlen("remote.");
1631 size_t namelen = strlen(name);
1632 char *remote_name;
8171998f 1633
106c12f1 1634 /* we know name matches "remote.<stuff>.(push)?url" */
8171998f 1635
106c12f1
RB
1636 if (!strcmp(&name[namelen - 4], ".url"))
1637 remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1638 else
1639 remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
25e0b157 1640 GITERR_CHECK_ALLOC(remote_name);
8171998f 1641
25e0b157 1642 return git_vector_insert(list, remote_name);
8171998f
CMN
1643}
1644
1645int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1646{
8171998f 1647 int error;
96869a4e 1648 git_config *cfg;
25e0b157 1649 git_vector list = GIT_VECTOR_INIT;
8171998f 1650
96869a4e
RB
1651 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1652 return error;
8171998f 1653
25e0b157 1654 if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
96869a4e 1655 return error;
8171998f 1656
106c12f1 1657 error = git_config_foreach_match(
25e0b157 1658 cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
8171998f 1659
4376f7f6 1660 if (error < 0) {
9cfce273 1661 git_vector_free_deep(&list);
8171998f
CMN
1662 return error;
1663 }
1664
25e0b157 1665 git_vector_uniq(&list, git__free);
aec87f71 1666
25e0b157
RB
1667 remotes_list->strings =
1668 (char **)git_vector_detach(&remotes_list->count, NULL, &list);
8171998f 1669
4376f7f6 1670 return 0;
8171998f 1671}
a209a025 1672
67dad09b 1673const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1674{
1675 assert(remote);
1676 return &remote->stats;
1677}
1678
11f6ad5f 1679git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
f70e466f
CMN
1680{
1681 return remote->download_tags;
1682}
1683
35a8a8c5 1684int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
f70e466f 1685{
35a8a8c5
CMN
1686 git_buf var = GIT_BUF_INIT;
1687 git_config *config;
1688 int error;
1689
1690 assert(repo && remote);
1691
1692 if ((error = ensure_remote_name_is_valid(remote)) < 0)
1693 return error;
1694
1695 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1696 return error;
1697
1698 if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
1699 return error;
1700
1701 switch (value) {
1702 case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
1703 error = git_config_set_string(config, var.ptr, "--no-tags");
1704 break;
1705 case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
1706 error = git_config_set_string(config, var.ptr, "--tags");
1707 break;
1708 case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
1709 error = git_config_delete_entry(config, var.ptr);
1710 if (error == GIT_ENOTFOUND)
1711 error = 0;
1712 break;
1713 default:
1714 giterr_set(GITERR_INVALID, "Invalid value for the tagopt setting");
1715 error = -1;
1716 }
1717
1718 git_buf_free(&var);
1719 return error;
f70e466f 1720}
fcccf304 1721
5f473947
L
1722int git_remote_prune_refs(const git_remote *remote)
1723{
1724 return remote->prune_refs;
1725}
1726
fcccf304 1727static int rename_remote_config_section(
1728 git_repository *repo,
1729 const char *old_name,
1730 const char *new_name)
1731{
1732 git_buf old_section_name = GIT_BUF_INIT,
1733 new_section_name = GIT_BUF_INIT;
1734 int error = -1;
1735
1736 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1737 goto cleanup;
1738
40e48ea4 1739 if (new_name &&
1740 (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1741 goto cleanup;
fcccf304 1742
1743 error = git_config_rename_section(
1744 repo,
1745 git_buf_cstr(&old_section_name),
40e48ea4 1746 new_name ? git_buf_cstr(&new_section_name) : NULL);
fcccf304 1747
1748cleanup:
1749 git_buf_free(&old_section_name);
1750 git_buf_free(&new_section_name);
1751
1752 return error;
1753}
1754
96869a4e 1755struct update_data {
fcccf304 1756 git_config *config;
1757 const char *old_remote_name;
1758 const char *new_remote_name;
1759};
1760
1761static int update_config_entries_cb(
1762 const git_config_entry *entry,
1763 void *payload)
1764{
1765 struct update_data *data = (struct update_data *)payload;
1766
1767 if (strcmp(entry->value, data->old_remote_name))
1768 return 0;
1769
25e0b157
RB
1770 return git_config_set_string(
1771 data->config, entry->name, data->new_remote_name);
fcccf304 1772}
1773
1774static int update_branch_remote_config_entry(
1775 git_repository *repo,
1776 const char *old_name,
1777 const char *new_name)
1778{
96869a4e
RB
1779 int error;
1780 struct update_data data = { NULL };
fcccf304 1781
96869a4e
RB
1782 if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1783 return error;
fcccf304 1784
fcccf304 1785 data.old_remote_name = old_name;
1786 data.new_remote_name = new_name;
1787
25e0b157 1788 return git_config_foreach_match(
96869a4e 1789 data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
fcccf304 1790}
1791
fcccf304 1792static int rename_one_remote_reference(
d1544564 1793 git_reference *reference_in,
fcccf304 1794 const char *old_remote_name,
1795 const char *new_remote_name)
1796{
96869a4e 1797 int error;
d1544564
CMN
1798 git_reference *ref = NULL, *dummy = NULL;
1799 git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
fcccf304 1800 git_buf new_name = GIT_BUF_INIT;
ccf6ce5c 1801 git_buf log_message = GIT_BUF_INIT;
d1544564
CMN
1802 size_t pfx_len;
1803 const char *target;
fcccf304 1804
d1544564
CMN
1805 if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1806 return error;
1807
1808 pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1809 git_buf_puts(&new_name, namespace.ptr);
1810 if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
ccf6ce5c 1811 goto cleanup;
fcccf304 1812
ccf6ce5c
BS
1813 if ((error = git_buf_printf(&log_message,
1814 "renamed remote %s to %s",
1815 old_remote_name, new_remote_name)) < 0)
1816 goto cleanup;
fcccf304 1817
d1544564 1818 if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
659cf202 1819 git_buf_cstr(&log_message))) < 0)
d1544564
CMN
1820 goto cleanup;
1821
1822 if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1823 goto cleanup;
1824
1825 /* Handle refs like origin/HEAD -> origin/master */
1826 target = git_reference_symbolic_target(ref);
1827 if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1828 goto cleanup;
1829
1830 if (git__prefixcmp(target, old_namespace.ptr))
1831 goto cleanup;
1832
1833 git_buf_clear(&new_name);
1834 git_buf_puts(&new_name, namespace.ptr);
1835 if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1836 goto cleanup;
1837
1838 error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
659cf202 1839 git_buf_cstr(&log_message));
d1544564
CMN
1840
1841 git_reference_free(dummy);
ccf6ce5c
BS
1842
1843cleanup:
d1544564
CMN
1844 git_reference_free(reference_in);
1845 git_reference_free(ref);
1846 git_buf_free(&namespace);
1847 git_buf_free(&old_namespace);
fcccf304 1848 git_buf_free(&new_name);
ccf6ce5c 1849 git_buf_free(&log_message);
fcccf304 1850 return error;
1851}
1852
1853static int rename_remote_references(
1854 git_repository *repo,
1855 const char *old_name,
1856 const char *new_name)
1857{
96869a4e 1858 int error;
a52ab4b8 1859 git_buf buf = GIT_BUF_INIT;
56960b83 1860 git_reference *ref;
9bd89d96 1861 git_reference_iterator *iter;
fcccf304 1862
a52ab4b8 1863 if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
96869a4e 1864 return error;
fcccf304 1865
a52ab4b8
CMN
1866 error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1867 git_buf_free(&buf);
9bd89d96 1868
a52ab4b8
CMN
1869 if (error < 0)
1870 return error;
1871
1872 while ((error = git_reference_next(&ref, iter)) == 0) {
96869a4e
RB
1873 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1874 break;
9bd89d96
CMN
1875 }
1876
1877 git_reference_iterator_free(iter);
fcccf304 1878
96869a4e 1879 return (error == GIT_ITEROVER) ? 0 : error;
fcccf304 1880}
1881
72bca13e 1882static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
fcccf304 1883{
1884 git_config *config;
4330ab26 1885 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1886 const git_refspec *spec;
4330ab26 1887 size_t i;
25e0b157 1888 int error = 0;
fcccf304 1889
dab89f9b 1890 if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
25e0b157
RB
1891 return error;
1892
72bca13e
CMN
1893 if ((error = git_vector_init(problems, 1, NULL)) < 0)
1894 return error;
1895
25e0b157
RB
1896 if ((error = git_buf_printf(
1897 &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
1898 return error;
dab89f9b 1899
1be680c4 1900 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1901 if (spec->push)
1902 continue;
fcccf304 1903
dab89f9b 1904 /* Does the dst part of the refspec follow the expected format? */
5a49ff9f 1905 if (strcmp(git_buf_cstr(&base), spec->string)) {
72bca13e 1906 char *dup;
fcccf304 1907
72bca13e
CMN
1908 dup = git__strdup(spec->string);
1909 GITERR_CHECK_ALLOC(dup);
1910
1911 if ((error = git_vector_insert(problems, dup)) < 0)
25e0b157 1912 break;
c7b3e1b3 1913
4330ab26
CMN
1914 continue;
1915 }
fcccf304 1916
4330ab26 1917 /* If we do want to move it to the new section */
fcccf304 1918
dab89f9b
RB
1919 git_buf_clear(&val);
1920 git_buf_clear(&var);
fcccf304 1921
dab89f9b
RB
1922 if (git_buf_printf(
1923 &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
1924 git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1925 {
1926 error = -1;
25e0b157 1927 break;
dab89f9b 1928 }
fcccf304 1929
dab89f9b
RB
1930 if ((error = git_config_set_string(
1931 config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
25e0b157 1932 break;
4330ab26 1933 }
fcccf304 1934
4330ab26
CMN
1935 git_buf_free(&base);
1936 git_buf_free(&var);
1937 git_buf_free(&val);
72bca13e
CMN
1938
1939 if (error < 0) {
1940 char *str;
1941 git_vector_foreach(problems, i, str)
1942 git__free(str);
1943
1944 git_vector_free(problems);
1945 }
1946
fcccf304 1947 return error;
1948}
1949
46c8f7f8 1950int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
fcccf304 1951{
1952 int error;
46c8f7f8 1953 git_vector problem_refspecs = GIT_VECTOR_INIT;
64bcf567 1954 git_remote *remote = NULL;
fcccf304 1955
46c8f7f8 1956 assert(out && repo && name && new_name);
fcccf304 1957
209425ce 1958 if ((error = git_remote_lookup(&remote, repo, name)) < 0)
cce27d82 1959 return error;
79000951 1960
fcccf304 1961 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
46c8f7f8 1962 goto cleanup;
fcccf304 1963
46c8f7f8
CMN
1964 if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
1965 goto cleanup;
fcccf304 1966
46c8f7f8
CMN
1967 if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
1968 goto cleanup;
fcccf304 1969
46c8f7f8
CMN
1970 if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
1971 goto cleanup;
fcccf304 1972
46c8f7f8
CMN
1973 if ((error = rename_remote_references(repo, name, new_name)) < 0)
1974 goto cleanup;
fcccf304 1975
72bca13e 1976 if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
46c8f7f8 1977 goto cleanup;
fcccf304 1978
72bca13e
CMN
1979 out->count = problem_refspecs.length;
1980 out->strings = (char **) problem_refspecs.contents;
1981
46c8f7f8
CMN
1982cleanup:
1983 if (error < 0)
1984 git_vector_free(&problem_refspecs);
fcccf304 1985
46c8f7f8
CMN
1986 git_remote_free(remote);
1987 return error;
fcccf304 1988}
b0f6e45d 1989
2bca5b67 1990int git_remote_is_valid_name(
1991 const char *remote_name)
1992{
1993 git_buf buf = GIT_BUF_INIT;
1994 git_refspec refspec;
1995 int error = -1;
1996
1997 if (!remote_name || *remote_name == '\0')
1998 return 0;
1999
2000 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
2001 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
2002
2003 git_buf_free(&buf);
2004 git_refspec__free(&refspec);
2005
2006 giterr_clear();
2007 return error == 0;
2008}
4330ab26
CMN
2009
2010git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
2011{
2012 git_refspec *spec;
2013 size_t i;
2014
af613ecd 2015 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2016 if (spec->push)
2017 continue;
2018
2019 if (git_refspec_src_matches(spec, refname))
2020 return spec;
2021 }
2022
2023 return NULL;
2024}
2025
2026git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
2027{
2028 git_refspec *spec;
2029 size_t i;
2030
af613ecd 2031 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2032 if (spec->push)
2033 continue;
2034
2035 if (git_refspec_dst_matches(spec, refname))
2036 return spec;
2037 }
2038
2039 return NULL;
2040}
2041
77254990 2042int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
4330ab26 2043{
77254990 2044 return write_add_refspec(repo, remote, refspec, true);
4330ab26
CMN
2045}
2046
77254990 2047int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
4330ab26 2048{
77254990 2049 return write_add_refspec(repo, remote, refspec, false);
266af6d8
CMN
2050}
2051
2052static int set_refspecs(git_remote *remote, git_strarray *array, int push)
2053{
2054 git_vector *vec = &remote->refspecs;
2055 git_refspec *spec;
2056 size_t i;
2057
2058 /* Start by removing any refspecs of the same type */
2059 for (i = 0; i < vec->length; i++) {
2060 spec = git_vector_get(vec, i);
2061 if (spec->push != push)
2062 continue;
2063
2064 git_refspec__free(spec);
2065 git__free(spec);
2066 git_vector_remove(vec, i);
2067 i--;
2068 }
2069
2070 /* And now we add the new ones */
2071
2072 for (i = 0; i < array->count; i++) {
2073 if (add_refspec(remote, array->strings[i], !push) < 0)
2074 return -1;
2075 }
2076
c300d84a 2077 return 0;
266af6d8
CMN
2078}
2079
11f6ad5f 2080static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
bc6374ea
CMN
2081{
2082 size_t i;
2083 git_vector refspecs;
2084 git_refspec *spec;
2085 char *dup;
2086
2087 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
2088 return -1;
2089
2090 git_vector_foreach(&remote->refspecs, i, spec) {
2091 if (spec->push != push)
2092 continue;
2093
1be680c4 2094 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 2095 goto on_error;
bc6374ea
CMN
2096
2097 if (git_vector_insert(&refspecs, dup) < 0) {
2098 git__free(dup);
2099 goto on_error;
2100 }
2101 }
2102
2103 array->strings = (char **)refspecs.contents;
2104 array->count = refspecs.length;
2105
2106 return 0;
2107
2108on_error:
9cfce273 2109 git_vector_free_deep(&refspecs);
bc6374ea
CMN
2110
2111 return -1;
2112}
2113
11f6ad5f 2114int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2115{
2116 return copy_refspecs(array, remote, false);
2117}
2118
11f6ad5f 2119int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2120{
2121 return copy_refspecs(array, remote, true);
2122}
1ffd0806 2123
11f6ad5f 2124size_t git_remote_refspec_count(const git_remote *remote)
1ffd0806
CMN
2125{
2126 return remote->refspecs.length;
2127}
2128
11f6ad5f 2129const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1ffd0806
CMN
2130{
2131 return git_vector_get(&remote->refspecs, n);
2132}
b9f81997 2133
bc91347b 2134int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
b9f81997 2135{
bc91347b
RB
2136 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2137 opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
2138 return 0;
b9f81997 2139}
40e48ea4 2140
5cdac19c
CMN
2141/* asserts a branch.<foo>.remote format */
2142static const char *name_offset(size_t *len_out, const char *name)
40e48ea4 2143{
5cdac19c
CMN
2144 size_t prefix_len;
2145 const char *dot;
40e48ea4 2146
5cdac19c
CMN
2147 prefix_len = strlen("remote.");
2148 dot = strchr(name + prefix_len, '.');
40e48ea4 2149
5cdac19c 2150 assert(dot);
40e48ea4 2151
5cdac19c
CMN
2152 *len_out = dot - name - prefix_len;
2153 return name + prefix_len;
40e48ea4 2154}
2155
2156static int remove_branch_config_related_entries(
2157 git_repository *repo,
2158 const char *remote_name)
2159{
2160 int error;
2161 git_config *config;
5cdac19c
CMN
2162 git_config_entry *entry;
2163 git_config_iterator *iter;
2164 git_buf buf = GIT_BUF_INIT;
40e48ea4 2165
2166 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2167 return error;
2168
5cdac19c 2169 if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
40e48ea4 2170 return error;
2171
5cdac19c
CMN
2172 /* find any branches with us as upstream and remove that config */
2173 while ((error = git_config_next(&entry, iter)) == 0) {
2174 const char *branch;
2175 size_t branch_len;
40e48ea4 2176
5cdac19c
CMN
2177 if (strcmp(remote_name, entry->value))
2178 continue;
40e48ea4 2179
5cdac19c 2180 branch = name_offset(&branch_len, entry->name);
40e48ea4 2181
5cdac19c
CMN
2182 git_buf_clear(&buf);
2183 if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
2184 break;
2185
2186 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2187 break;
2188
2189 git_buf_clear(&buf);
2190 if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
2191 break;
2192
2193 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2194 break;
40e48ea4 2195 }
2196
5cdac19c
CMN
2197 if (error == GIT_ITEROVER)
2198 error = 0;
2199
2200 git_buf_free(&buf);
2201 git_config_iterator_free(iter);
40e48ea4 2202 return error;
2203}
2204
8a9419aa 2205static int remove_refs(git_repository *repo, const git_refspec *spec)
ec8a949a 2206{
8a9419aa
CMN
2207 git_reference_iterator *iter = NULL;
2208 git_vector refs;
ec8a949a 2209 const char *name;
8a9419aa 2210 char *dup;
ec8a949a 2211 int error;
8a9419aa 2212 size_t i;
ec8a949a 2213
8a9419aa 2214 if ((error = git_vector_init(&refs, 8, NULL)) < 0)
ec8a949a
CMN
2215 return error;
2216
8a9419aa
CMN
2217 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2218 goto cleanup;
2219
ec8a949a 2220 while ((error = git_reference_next_name(&name, iter)) == 0) {
8a9419aa
CMN
2221 if (!git_refspec_dst_matches(spec, name))
2222 continue;
2223
2224 dup = git__strdup(name);
2225 if (!dup) {
2226 error = -1;
2227 goto cleanup;
2228 }
ec8a949a 2229
8a9419aa
CMN
2230 if ((error = git_vector_insert(&refs, dup)) < 0)
2231 goto cleanup;
2232 }
ec8a949a
CMN
2233 if (error == GIT_ITEROVER)
2234 error = 0;
8a9419aa
CMN
2235 if (error < 0)
2236 goto cleanup;
2237
2238 git_vector_foreach(&refs, i, name) {
2239 if ((error = git_reference_remove(repo, name)) < 0)
2240 break;
2241 }
ec8a949a 2242
8a9419aa
CMN
2243cleanup:
2244 git_reference_iterator_free(iter);
2245 git_vector_foreach(&refs, i, dup) {
2246 git__free(dup);
2247 }
2248 git_vector_free(&refs);
ec8a949a
CMN
2249 return error;
2250}
2251
2252static int remove_remote_tracking(git_repository *repo, const char *remote_name)
2253{
2254 git_remote *remote;
2255 int error;
2256 size_t i, count;
2257
2258 /* we want to use what's on the config, regardless of changes to the instance in memory */
209425ce 2259 if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
ec8a949a
CMN
2260 return error;
2261
2262 count = git_remote_refspec_count(remote);
2263 for (i = 0; i < count; i++) {
2264 const git_refspec *refspec = git_remote_get_refspec(remote, i);
2265
2266 /* shouldn't ever actually happen */
2267 if (refspec == NULL)
2268 continue;
2269
8a9419aa 2270 if ((error = remove_refs(repo, refspec)) < 0)
ec8a949a
CMN
2271 break;
2272 }
2273
2274 git_remote_free(remote);
2275 return error;
2276}
2277
262eec23 2278int git_remote_delete(git_repository *repo, const char *name)
40e48ea4 2279{
2280 int error;
40e48ea4 2281
262eec23 2282 assert(repo && name);
ec8a949a 2283
262eec23
CMN
2284 if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
2285 (error = remove_remote_tracking(repo, name)) < 0 ||
2286 (error = rename_remote_config_section(repo, name, NULL)) < 0)
ec8a949a
CMN
2287 return error;
2288
40e48ea4 2289 return 0;
2290}
d22db24f
CMN
2291
2292int git_remote_default_branch(git_buf *out, git_remote *remote)
2293{
2294 const git_remote_head **heads;
2295 const git_remote_head *guess = NULL;
2296 const git_oid *head_id;
2297 size_t heads_len, i;
2298 int error;
2299
dc8adda4
JG
2300 assert(out);
2301
d22db24f
CMN
2302 if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2303 return error;
2304
2305 if (heads_len == 0)
2306 return GIT_ENOTFOUND;
2307
0cdaa376
CMN
2308 if (strcmp(heads[0]->name, GIT_HEAD_FILE))
2309 return GIT_ENOTFOUND;
2310
d22db24f
CMN
2311 git_buf_sanitize(out);
2312 /* the first one must be HEAD so if that has the symref info, we're done */
2313 if (heads[0]->symref_target)
2314 return git_buf_puts(out, heads[0]->symref_target);
2315
2316 /*
2317 * If there's no symref information, we have to look over them
2318 * and guess. We return the first match unless the master
2319 * branch is a candidate. Then we return the master branch.
2320 */
2321 head_id = &heads[0]->oid;
2322
2323 for (i = 1; i < heads_len; i++) {
2324 if (git_oid_cmp(head_id, &heads[i]->oid))
2325 continue;
2326
38952604
CMN
2327 if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
2328 continue;
2329
d22db24f
CMN
2330 if (!guess) {
2331 guess = heads[i];
2332 continue;
2333 }
2334
2335 if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
2336 guess = heads[i];
2337 break;
2338 }
2339 }
2340
2341 if (!guess)
2342 return GIT_ENOTFOUND;
2343
2344 return git_buf_puts(out, guess->name);
2345}
3149547b 2346
fe794b2e 2347int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
3149547b 2348{
3149547b 2349 size_t i;
fe794b2e
CMN
2350 int error;
2351 git_push *push;
64e3e6d4 2352 git_refspec *spec;
8f0104ec 2353 const git_remote_callbacks *cbs = NULL;
3149547b 2354
fe794b2e 2355 assert(remote);
3149547b 2356
8f0104ec
CMN
2357 if (opts)
2358 cbs = &opts->callbacks;
2359
fe794b2e 2360 if (!git_remote_connected(remote) &&
8f0104ec 2361 (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2362 goto cleanup;
2363
1034f1b5 2364 free_refspecs(&remote->active_refspecs);
69f0032b 2365 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1034f1b5
POL
2366 goto cleanup;
2367
fe794b2e
CMN
2368 if (remote->push) {
2369 git_push_free(remote->push);
2370 remote->push = NULL;
2371 }
2372
2373 if ((error = git_push_new(&remote->push, remote)) < 0)
3149547b
CMN
2374 return error;
2375
fe794b2e 2376 push = remote->push;
3149547b
CMN
2377
2378 if (opts && (error = git_push_set_options(push, opts)) < 0)
2379 goto cleanup;
2380
64e3e6d4
CMN
2381 if (refspecs && refspecs->count > 0) {
2382 for (i = 0; i < refspecs->count; i++) {
2383 if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
2384 goto cleanup;
2385 }
2386 } else {
2387 git_vector_foreach(&remote->refspecs, i, spec) {
2388 if (!spec->push)
2389 continue;
2390 if ((error = git_push_add_refspec(push, spec->string)) < 0)
2391 goto cleanup;
2392 }
3149547b
CMN
2393 }
2394
8f0104ec 2395 if ((error = git_push_finish(push, cbs)) < 0)
3149547b
CMN
2396 goto cleanup;
2397
8f0104ec 2398 if (cbs && cbs->push_update_reference &&
52ee0e8e 2399 (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
3149547b
CMN
2400 goto cleanup;
2401
3149547b 2402cleanup:
fe794b2e
CMN
2403 return error;
2404}
2405
412a3808 2406int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
fe794b2e
CMN
2407{
2408 int error;
8f0104ec
CMN
2409 const git_remote_callbacks *cbs = NULL;
2410
2411 if (opts) {
2412 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2413 cbs = &opts->callbacks;
2414 }
fe794b2e
CMN
2415
2416 assert(remote && refspecs);
2417
8f0104ec 2418 if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2419 return error;
2420
2421 if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2422 return error;
2423
35a8a8c5 2424 error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
fe794b2e 2425
3149547b 2426 git_remote_disconnect(remote);
3149547b
CMN
2427 return error;
2428}
ec0c4c40
PS
2429
2430#define PREFIX "url"
2431#define SUFFIX_FETCH "insteadof"
2432#define SUFFIX_PUSH "pushinsteadof"
2433
2434char *apply_insteadof(git_config *config, const char *url, int direction)
2435{
2436 size_t match_length, prefix_length, suffix_length;
2437 char *replacement = NULL;
2438 const char *regexp;
2439
2440 git_buf result = GIT_BUF_INIT;
2441 git_config_entry *entry;
2442 git_config_iterator *iter;
2443
2444 assert(config);
2445 assert(url);
2446 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
2447
2448 /* Add 1 to prefix/suffix length due to the additional escaped dot */
2449 prefix_length = strlen(PREFIX) + 1;
2450 if (direction == GIT_DIRECTION_FETCH) {
2451 regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
2452 suffix_length = strlen(SUFFIX_FETCH) + 1;
2453 } else {
2454 regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
2455 suffix_length = strlen(SUFFIX_PUSH) + 1;
2456 }
2457
2785544f
CMN
2458 if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
2459 return NULL;
ec0c4c40
PS
2460
2461 match_length = 0;
2462 while (git_config_next(&entry, iter) == 0) {
2463 size_t n, replacement_length;
2464
2465 /* Check if entry value is a prefix of URL */
2466 if (git__prefixcmp(url, entry->value))
2467 continue;
2468 /* Check if entry value is longer than previous
2469 * prefixes */
2470 if ((n = strlen(entry->value)) <= match_length)
2471 continue;
2472
2473 git__free(replacement);
2474 match_length = n;
2475
2476 /* Cut off prefix and suffix of the value */
2477 replacement_length =
2478 strlen(entry->name) - (prefix_length + suffix_length);
2479 replacement = git__strndup(entry->name + prefix_length,
2480 replacement_length);
2481 }
2482
2483 git_config_iterator_free(iter);
2484
2485 if (match_length == 0)
2486 return git__strdup(url);
2487
2488 git_buf_printf(&result, "%s%s", replacement, url + match_length);
2489
2490 git__free(replacement);
2491
2492 return result.ptr;
2493}