]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
remote: add failing test for a mirror refspec
[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 */
e069c621 156 if ((val = p_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;
e069c621 762 git_buf val = GIT_BUF_INIT;
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 791 if (ce && ce->value) {
e069c621 792 *proxy_url = git__strdup(ce->value);
9f77b3f6
RB
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;
e069c621 800
9f77b3f6 801 if (ce && ce->value) {
e069c621 802 *proxy_url = git__strdup(ce->value);
9f77b3f6
RB
803 goto found;
804 }
613d5eb9
PK
805
806 /* HTTP_PROXY / HTTPS_PROXY environment variables */
e069c621 807 error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
613d5eb9 808
e069c621
ET
809 if (error < 0) {
810 if (error == GIT_ENOTFOUND) {
811 giterr_clear();
812 error = 0;
813 }
814
815 return error;
613d5eb9 816 }
e069c621
ET
817
818 *proxy_url = git_buf_detach(&val);
819
820found:
821 GITERR_CHECK_ALLOC(*proxy_url);
9a97f49e 822 git_config_entry_free(ce);
613d5eb9
PK
823
824 return 0;
825}
826
af613ecd
CMN
827/* DWIM `refspecs` based on `refs` and append the output to `out` */
828static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
d8488457 829{
af613ecd 830 size_t i;
d8488457 831 git_refspec *spec;
d8488457
CMN
832
833 git_vector_foreach(refspecs, i, spec) {
af613ecd
CMN
834 if (git_refspec__dwim_one(out, spec, refs) < 0)
835 return -1;
836 }
d8488457 837
af613ecd
CMN
838 return 0;
839}
d8488457 840
af613ecd
CMN
841static void free_refspecs(git_vector *vec)
842{
843 size_t i;
844 git_refspec *spec;
d8488457 845
af613ecd
CMN
846 git_vector_foreach(vec, i, spec) {
847 git_refspec__free(spec);
848 git__free(spec);
d8488457
CMN
849 }
850
af613ecd 851 git_vector_clear(vec);
d8488457
CMN
852}
853
854static int remote_head_cmp(const void *_a, const void *_b)
855{
856 const git_remote_head *a = (git_remote_head *) _a;
857 const git_remote_head *b = (git_remote_head *) _b;
858
859 return git__strcmp_cb(a->name, b->name);
860}
861
877cde76
CMN
862static int ls_to_vector(git_vector *out, git_remote *remote)
863{
864 git_remote_head **heads;
865 size_t heads_len, i;
866
867 if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
868 return -1;
869
870 if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
871 return -1;
872
873 for (i = 0; i < heads_len; i++) {
874 if (git_vector_insert(out, heads[i]) < 0)
875 return -1;
876 }
877
878 return 0;
879}
880
8f0104ec 881int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
48a65a07 882{
eecc1772 883 int error = -1;
3f894205 884 size_t i;
2785544f 885 git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
8f0104ec 886 const git_remote_callbacks *cbs = NULL;
95057b85 887
1e3b8ed5 888 assert(remote);
4bef3565 889
8f0104ec
CMN
890 if (opts) {
891 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
892 cbs = &opts->callbacks;
893 }
894
895 if (!git_remote_connected(remote) &&
896 (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0)
897 goto on_error;
898
877cde76 899 if (ls_to_vector(&refs, remote) < 0)
d8488457 900 return -1;
d8488457 901
3f894205
CMN
902 if ((git_vector_init(&specs, 0, NULL)) < 0)
903 goto on_error;
904
c5837cad 905 remote->passed_refspecs = 0;
8e398e4c 906 if (!refspecs || !refspecs->count) {
3f894205
CMN
907 to_active = &remote->refspecs;
908 } else {
909 for (i = 0; i < refspecs->count; i++) {
910 if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
911 goto on_error;
912 }
913
914 to_active = &specs;
c5837cad 915 remote->passed_refspecs = 1;
3f894205
CMN
916 }
917
2cdd5c57
CMN
918 free_refspecs(&remote->passive_refspecs);
919 if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
920 goto on_error;
af613ecd 921
2cdd5c57 922 free_refspecs(&remote->active_refspecs);
3f894205 923 error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
2cdd5c57 924
877cde76 925 git_vector_free(&refs);
3f894205
CMN
926 free_refspecs(&specs);
927 git_vector_free(&specs);
877cde76
CMN
928
929 if (error < 0)
25e0b157 930 return error;
d8488457 931
c070ac64
POL
932 if (remote->push) {
933 git_push_free(remote->push);
934 remote->push = NULL;
935 }
936
35a8a8c5 937 if ((error = git_fetch_negotiate(remote, opts)) < 0)
4376f7f6 938 return error;
95057b85 939
8f0104ec 940 return git_fetch_download_pack(remote, cbs);
3f894205
CMN
941
942on_error:
943 git_vector_free(&refs);
944 free_refspecs(&specs);
945 git_vector_free(&specs);
946 return error;
48a65a07
CMN
947}
948
c3ab1e5a
BS
949int git_remote_fetch(
950 git_remote *remote,
3f894205 951 const git_strarray *refspecs,
8f0104ec 952 const git_fetch_options *opts,
c3ab1e5a 953 const char *reflog_message)
fe3a40a4 954{
3eff2a57 955 int error, update_fetchhead = 1;
35a8a8c5 956 git_remote_autotag_option_t tagopt = remote->download_tags;
6fb373a0 957 bool prune = false;
db55bb73 958 git_buf reflog_msg_buf = GIT_BUF_INIT;
8f0104ec
CMN
959 const git_remote_callbacks *cbs = NULL;
960
961 if (opts) {
962 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
963 cbs = &opts->callbacks;
3eff2a57 964 update_fetchhead = opts->update_fetchhead;
35a8a8c5 965 tagopt = opts->download_tags;
8f0104ec 966 }
fe3a40a4
CMN
967
968 /* Connect and download everything */
8f0104ec 969 if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0)
fe3a40a4
CMN
970 return error;
971
8f0104ec 972 error = git_remote_download(remote, refspecs, opts);
fe3a40a4
CMN
973
974 /* We don't need to be connected anymore */
975 git_remote_disconnect(remote);
976
06a8f5c3
BL
977 /* If the download failed, return the error */
978 if (error != 0)
979 return error;
980
db55bb73
BS
981 /* Default reflog message */
982 if (reflog_message)
983 git_buf_sets(&reflog_msg_buf, reflog_message);
984 else {
985 git_buf_printf(&reflog_msg_buf, "fetch %s",
986 remote->name ? remote->name : remote->url);
987 }
988
fe3a40a4 989 /* Create "remote/foo" branches for all remote branches */
35a8a8c5 990 error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
db55bb73 991 git_buf_free(&reflog_msg_buf);
8c13eaed
CMN
992 if (error < 0)
993 return error;
994
6fb373a0
CMN
995 if (opts && opts->prune == GIT_FETCH_PRUNE)
996 prune = true;
c2418f46 997 else if (opts && opts->prune == GIT_FETCH_PRUNE_UNSPECIFIED && remote->prune_refs)
6fb373a0
CMN
998 prune = true;
999 else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
1000 prune = false;
1001 else
1002 prune = remote->prune_refs;
1003
1004 if (prune)
8f0104ec 1005 error = git_remote_prune(remote, cbs);
8c13eaed 1006
db55bb73 1007 return error;
fe3a40a4
CMN
1008}
1009
b0f6e45d
ET
1010static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
1011{
1012 unsigned int i;
1013 git_remote_head *remote_ref;
1014
1015 assert(update_heads && fetchspec_src);
1016
1017 *out = NULL;
7d4b65f6 1018
1019 git_vector_foreach(update_heads, i, remote_ref) {
1020 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
1021 *out = remote_ref;
1022 break;
b0f6e45d
ET
1023 }
1024 }
1025
1026 return 0;
1027}
1028
2c9b9c8b
CMN
1029static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
1030{
1031 int error = 0;
1032 git_repository *repo;
1033 git_buf upstream_remote = GIT_BUF_INIT;
1034 git_buf upstream_name = GIT_BUF_INIT;
1035
1036 repo = git_remote_owner(remote);
1037
1038 if ((!git_reference__is_branch(ref_name)) ||
1039 !git_remote_name(remote) ||
1040 (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
1041 git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
1042 (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
1043 !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
1044 (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
1045 /* Not an error if there is no upstream */
1046 if (error == GIT_ENOTFOUND) {
1047 giterr_clear();
1048 error = 0;
1049 }
1050
1051 *update = 0;
1052 } else {
1053 *update = 1;
1054 }
1055
1056 git_buf_free(&upstream_remote);
1057 git_buf_free(&upstream_name);
1058 return error;
1059}
1060
f49819aa 1061static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
1062{
1063 git_reference *resolved_ref = NULL;
b0f6e45d 1064 git_buf remote_name = GIT_BUF_INIT;
f49819aa 1065 git_config *config = NULL;
e235db02 1066 const char *ref_name;
2c9b9c8b 1067 int error = 0, update;
b0f6e45d 1068
4330ab26 1069 assert(out && spec && ref);
b0f6e45d
ET
1070
1071 *out = NULL;
1072
67d4997a
CMN
1073 error = git_reference_resolve(&resolved_ref, ref);
1074
1075 /* If we're in an unborn branch, let's pretend nothing happened */
1076 if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1077 ref_name = git_reference_symbolic_target(ref);
1078 error = 0;
1079 } else {
1080 ref_name = git_reference_name(resolved_ref);
1081 }
1082
2c9b9c8b 1083 if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
b0f6e45d 1084 goto cleanup;
b0f6e45d 1085
2c9b9c8b
CMN
1086 if (update)
1087 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
b0f6e45d
ET
1088
1089cleanup:
f7fcb18f 1090 git_buf_free(&remote_name);
b0f6e45d 1091 git_reference_free(resolved_ref);
f49819aa 1092 git_config_free(config);
b0f6e45d
ET
1093 return error;
1094}
1095
4330ab26 1096static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 1097{
b0f6e45d
ET
1098 git_reference *head_ref = NULL;
1099 git_fetchhead_ref *fetchhead_ref;
1100 git_remote_head *remote_ref, *merge_remote_ref;
1101 git_vector fetchhead_refs;
1102 bool include_all_fetchheads;
1103 unsigned int i = 0;
1104 int error = 0;
1105
1106 assert(remote);
1107
404eadb0
CMN
1108 /* no heads, nothing to do */
1109 if (update_heads->length == 0)
1110 return 0;
1111
b0f6e45d
ET
1112 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
1113 return -1;
1114
1115 /* Iff refspec is * (but not subdir slash star), include tags */
1116 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
1117
1118 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
1119 if (git_refspec_is_wildcard(spec)) {
1120 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
f49819aa 1121 (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
1122 goto cleanup;
1123 } else {
1124 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
1125 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
1126 goto cleanup;
1127 }
1128
1129 /* Create the FETCH_HEAD file */
7d4b65f6 1130 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
1131 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
1132
1133 if (!include_all_fetchheads &&
1134 !git_refspec_src_matches(spec, remote_ref->name) &&
1135 !merge_this_fetchhead)
1136 continue;
1137
1138 if (git_fetchhead_ref_create(&fetchhead_ref,
1139 &remote_ref->oid,
1140 merge_this_fetchhead,
1141 remote_ref->name,
1142 git_remote_url(remote)) < 0)
1143 goto cleanup;
1144
1145 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
1146 goto cleanup;
1147 }
1148
1149 git_fetchhead_write(remote->repo, &fetchhead_refs);
1150
1151cleanup:
1152 for (i = 0; i < fetchhead_refs.length; ++i)
1153 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
1154
1155 git_vector_free(&fetchhead_refs);
1156 git_reference_free(head_ref);
1157
1158 return error;
1159}
1160
59ff8b67
CMN
1161/**
1162 * Generate a list of candidates for pruning by getting a list of
1163 * references which match the rhs of an active refspec.
1164 */
1165static int prune_candidates(git_vector *candidates, git_remote *remote)
5f473947
L
1166{
1167 git_strarray arr = { 0 };
59ff8b67 1168 size_t i;
5f473947
L
1169 int error;
1170
1171 if ((error = git_reference_list(&arr, remote->repo)) < 0)
1172 return error;
1173
59ff8b67
CMN
1174 for (i = 0; i < arr.count; i++) {
1175 const char *refname = arr.strings[i];
1176 char *refname_dup;
1177
1178 if (!git_remote__matching_dst_refspec(remote, refname))
1179 continue;
1180
1181 refname_dup = git__strdup(refname);
1182 GITERR_CHECK_ALLOC(refname_dup);
1183
1184 if ((error = git_vector_insert(candidates, refname_dup)) < 0)
1185 goto out;
1186 }
1187
1188out:
1189 git_strarray_free(&arr);
1190 return error;
1191}
1192
1193static int find_head(const void *_a, const void *_b)
1194{
1195 git_remote_head *a = (git_remote_head *) _a;
1196 git_remote_head *b = (git_remote_head *) _b;
1197
1198 return strcmp(a->name, b->name);
1199}
1200
8f0104ec 1201int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
59ff8b67
CMN
1202{
1203 size_t i, j;
1204 git_vector remote_refs = GIT_VECTOR_INIT;
1205 git_vector candidates = GIT_VECTOR_INIT;
1206 const git_refspec *spec;
1207 const char *refname;
1208 int error;
1209 git_oid zero_id = {{ 0 }};
1210
8f0104ec
CMN
1211 if (callbacks)
1212 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1213
5f473947
L
1214 if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1215 goto cleanup;
1216
59ff8b67 1217 git_vector_set_cmp(&remote_refs, find_head);
5f473947 1218
59ff8b67
CMN
1219 if ((error = prune_candidates(&candidates, remote)) < 0)
1220 goto cleanup;
5f473947 1221
59ff8b67
CMN
1222 /*
1223 * Remove those entries from the candidate list for which we
1224 * can find a remote reference in at least one refspec.
1225 */
1226 git_vector_foreach(&candidates, i, refname) {
1227 git_vector_foreach(&remote->active_refspecs, j, spec) {
1228 git_buf buf = GIT_BUF_INIT;
1229 size_t pos;
1230 char *src_name;
1231 git_remote_head key = {0};
1232
1233 if (!git_refspec_dst_matches(spec, refname))
5f473947
L
1234 continue;
1235
59ff8b67
CMN
1236 if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
1237 goto cleanup;
5f473947 1238
59ff8b67
CMN
1239 key.name = (char *) git_buf_cstr(&buf);
1240 error = git_vector_search(&pos, &remote_refs, &key);
1241 git_buf_free(&buf);
5f473947 1242
59ff8b67
CMN
1243 if (error < 0 && error != GIT_ENOTFOUND)
1244 goto cleanup;
5f473947 1245
59ff8b67 1246 if (error == GIT_ENOTFOUND)
5f473947
L
1247 continue;
1248
59ff8b67
CMN
1249 /* if we did find a source, remove it from the candiates */
1250 if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
1251 goto cleanup;
1252
1253 git__free(src_name);
1254 break;
5f473947
L
1255 }
1256 }
1257
59ff8b67
CMN
1258 /*
1259 * For those candidates still left in the list, we need to
1260 * remove them. We do not remove symrefs, as those are for
1261 * stuff like origin/HEAD which will never match, but we do
1262 * not want to remove them.
1263 */
1264 git_vector_foreach(&candidates, i, refname) {
1265 git_reference *ref;
1266 git_oid id;
1267
1268 if (refname == NULL)
1269 continue;
1270
1271 error = git_reference_lookup(&ref, remote->repo, refname);
1272 /* as we want it gone, let's not consider this an error */
1273 if (error == GIT_ENOTFOUND)
1274 continue;
1275
1276 if (error < 0)
1277 goto cleanup;
1278
1279 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1280 git_reference_free(ref);
1281 continue;
1282 }
1283
1284 git_oid_cpy(&id, git_reference_target(ref));
1285 error = git_reference_delete(ref);
1286 git_reference_free(ref);
1287 if (error < 0)
1288 goto cleanup;
1289
8f0104ec
CMN
1290 if (callbacks && callbacks->update_tips)
1291 error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
59ff8b67
CMN
1292
1293 if (error < 0)
1294 goto cleanup;
1295 }
1296
5f473947 1297cleanup:
5f473947 1298 git_vector_free(&remote_refs);
59ff8b67 1299 git_vector_free_deep(&candidates);
5f473947
L
1300 return error;
1301}
1302
c3ab1e5a
BS
1303static int update_tips_for_spec(
1304 git_remote *remote,
8f0104ec 1305 const git_remote_callbacks *callbacks,
3eff2a57 1306 int update_fetchhead,
35a8a8c5 1307 git_remote_autotag_option_t tagopt,
c3ab1e5a
BS
1308 git_refspec *spec,
1309 git_vector *refs,
c3ab1e5a 1310 const char *log_message)
441f57c2 1311{
a37ddf7e 1312 int error = 0, autotag;
517bda19 1313 unsigned int i = 0;
97769280 1314 git_buf refname = GIT_BUF_INIT;
f184836b 1315 git_oid old;
a37ddf7e 1316 git_odb *odb;
441f57c2
CMN
1317 git_remote_head *head;
1318 git_reference *ref;
a37ddf7e 1319 git_refspec tagspec;
4330ab26 1320 git_vector update_heads;
441f57c2 1321
4bef3565
VM
1322 assert(remote);
1323
acd17006 1324 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
1325 return -1;
1326
3230a44f 1327 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
1328 return -1;
1329
41fb1ca0 1330 /* Make a copy of the transport's refs */
4330ab26 1331 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 1332 return -1;
585a2eb7 1333
4330ab26
CMN
1334 for (; i < refs->length; ++i) {
1335 head = git_vector_get(refs, i);
9063be1f 1336 autotag = 0;
517bda19 1337
a37ddf7e
CMN
1338 /* Ignore malformed ref names (which also saves us from tag^{} */
1339 if (!git_reference_is_valid_name(head->name))
1340 continue;
1341
e284c451 1342 if (git_refspec_src_matches(&tagspec, head->name)) {
35a8a8c5 1343 if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f 1344
35a8a8c5 1345 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
e284c451 1346 autotag = 1;
a37ddf7e 1347
e284c451
POL
1348 git_buf_clear(&refname);
1349 if (git_buf_puts(&refname, head->name) < 0)
1350 goto on_error;
1351 } else {
a37ddf7e 1352 continue;
e284c451 1353 }
23aa7c90
CMN
1354 } else if (git_refspec_src_matches(spec, head->name)) {
1355 if (spec->dst) {
1356 if (git_refspec_transform(&refname, spec, head->name) < 0)
1357 goto on_error;
1358 } else {
1359 /*
1360 * no rhs mans store it in FETCH_HEAD, even if we don't
1361 update anything else.
1362 */
1363 if ((error = git_vector_insert(&update_heads, head)) < 0)
1364 goto on_error;
1365
1366 continue;
1367 }
a37ddf7e
CMN
1368 } else {
1369 continue;
1370 }
1371
e284c451 1372 /* In autotag mode, only create tags for objects already in db */
a37ddf7e
CMN
1373 if (autotag && !git_odb_exists(odb, &head->oid))
1374 continue;
f184836b 1375
d908351a 1376 if (!autotag && git_vector_insert(&update_heads, head) < 0)
b0f6e45d
ET
1377 goto on_error;
1378
2508cc66 1379 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 1380 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
1381 goto on_error;
1382
d908351a 1383 if (error == GIT_ENOTFOUND) {
f184836b
CMN
1384 memset(&old, 0, GIT_OID_RAWSZ);
1385
d908351a
L
1386 if (autotag && git_vector_insert(&update_heads, head) < 0)
1387 goto on_error;
1388 }
1389
b7f167da 1390 if (!git_oid__cmp(&old, &head->oid))
f184836b 1391 continue;
441f57c2 1392
a37ddf7e 1393 /* In autotag mode, don't overwrite any locally-existing tags */
c3ab1e5a 1394 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
659cf202 1395 log_message);
a37ddf7e 1396 if (error < 0 && error != GIT_EEXISTS)
944d250f 1397 goto on_error;
39157563
CMN
1398
1399 git_reference_free(ref);
f184836b 1400
8f0104ec
CMN
1401 if (callbacks && callbacks->update_tips != NULL) {
1402 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
f184836b
CMN
1403 goto on_error;
1404 }
441f57c2
CMN
1405 }
1406
3eff2a57 1407 if (update_fetchhead &&
4330ab26 1408 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
1409 goto on_error;
1410
b0f6e45d 1411 git_vector_free(&update_heads);
a37ddf7e 1412 git_refspec__free(&tagspec);
97769280 1413 git_buf_free(&refname);
f184836b
CMN
1414 return 0;
1415
1416on_error:
b0f6e45d 1417 git_vector_free(&update_heads);
a37ddf7e 1418 git_refspec__free(&tagspec);
f184836b
CMN
1419 git_buf_free(&refname);
1420 return -1;
97769280 1421
441f57c2
CMN
1422}
1423
c5837cad
CMN
1424/**
1425 * Iteration over the three vectors, with a pause whenever we find a match
1426 *
1427 * On each stop, we store the iteration stat in the inout i,j,k
1428 * parameters, and return the currently matching passive refspec as
1429 * well as the head which we matched.
1430 */
1431static int next_head(const git_remote *remote, git_vector *refs,
1432 git_refspec **out_spec, git_remote_head **out_head,
1433 size_t *out_i, size_t *out_j, size_t *out_k)
1434{
1435 const git_vector *active, *passive;
1436 git_remote_head *head;
1437 git_refspec *spec, *passive_spec;
1438 size_t i, j, k;
1439
1440 active = &remote->active_refspecs;
1441 passive = &remote->passive_refspecs;
1442
1443 i = *out_i;
1444 j = *out_j;
1445 k = *out_k;
1446
1447 for (; i < refs->length; i++) {
1448 head = git_vector_get(refs, i);
1449
1450 if (!git_reference_is_valid_name(head->name))
1451 continue;
1452
1453 for (; j < active->length; j++) {
1454 spec = git_vector_get(active, j);
1455
1456 if (!git_refspec_src_matches(spec, head->name))
1457 continue;
1458
1459 for (; k < passive->length; k++) {
1460 passive_spec = git_vector_get(passive, k);
1461
1462 if (!git_refspec_src_matches(passive_spec, head->name))
1463 continue;
1464
1465 *out_spec = passive_spec;
1466 *out_head = head;
1467 *out_i = i;
1468 *out_j = j;
1469 *out_k = k + 1;
1470 return 0;
1471
1472 }
1473 k = 0;
1474 }
1475 j = 0;
1476 }
1477
1478 return GIT_ITEROVER;
1479}
1480
9566ce43
CMN
1481static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
1482 git_vector *refs, const char *msg)
c5837cad
CMN
1483{
1484 size_t i, j, k;
1485 git_refspec *spec;
1486 git_remote_head *head;
1487 git_reference *ref;
1488 git_buf refname = GIT_BUF_INIT;
9566ce43 1489 int error = 0;
c5837cad
CMN
1490
1491 i = j = k = 0;
1492
1493 while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
9566ce43 1494 git_oid old = {{ 0 }};
c5837cad
CMN
1495 /*
1496 * If we got here, there is a refspec which was used
1497 * for fetching which matches the source of one of the
1498 * passive refspecs, so we should update that
1499 * remote-tracking branch, but not add it to
1500 * FETCH_HEAD
1501 */
1502
9566ce43 1503 git_buf_clear(&refname);
c5837cad 1504 if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
9566ce43 1505 goto cleanup;
c5837cad 1506
9566ce43
CMN
1507 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1508 if (error < 0 && error != GIT_ENOTFOUND)
1509 goto cleanup;
1510
1511 if (!git_oid_cmp(&old, &head->oid))
1512 continue;
c5837cad 1513
9566ce43
CMN
1514 /* If we did find a current reference, make sure we haven't lost a race */
1515 if (error)
1516 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1517 else
1518 error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
1519 git_reference_free(ref);
c5837cad 1520 if (error < 0)
9566ce43
CMN
1521 goto cleanup;
1522
1523 if (callbacks && callbacks->update_tips != NULL) {
1524 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1525 goto cleanup;
1526 }
c5837cad
CMN
1527 }
1528
9566ce43
CMN
1529 if (error == GIT_ITEROVER)
1530 error = 0;
1531
1532cleanup:
1533 git_buf_free(&refname);
1534 return error;
c5837cad
CMN
1535}
1536
c3ab1e5a
BS
1537int git_remote_update_tips(
1538 git_remote *remote,
8f0104ec 1539 const git_remote_callbacks *callbacks,
3eff2a57 1540 int update_fetchhead,
35a8a8c5 1541 git_remote_autotag_option_t download_tags,
c3ab1e5a 1542 const char *reflog_message)
4330ab26 1543{
505b5d0c 1544 git_refspec *spec, tagspec;
cdedef40 1545 git_vector refs = GIT_VECTOR_INIT;
35a8a8c5 1546 git_remote_autotag_option_t tagopt;
505b5d0c 1547 int error;
4330ab26
CMN
1548 size_t i;
1549
fe794b2e
CMN
1550 /* push has its own logic hidden away in the push object */
1551 if (remote->push) {
8f0104ec 1552 return git_push_update_tips(remote->push, callbacks);
fe794b2e
CMN
1553 }
1554
505b5d0c
CMN
1555 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1556 return -1;
1557
877cde76
CMN
1558
1559 if ((error = ls_to_vector(&refs, remote)) < 0)
505b5d0c
CMN
1560 goto out;
1561
c2418f46 1562 if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
35a8a8c5
CMN
1563 tagopt = remote->download_tags;
1564 else
1565 tagopt = download_tags;
1566
1567 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1568 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
e284c451 1569 goto out;
505b5d0c 1570 }
4330ab26 1571
af613ecd 1572 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1573 if (spec->push)
1574 continue;
1575
35a8a8c5 1576 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
505b5d0c 1577 goto out;
4330ab26
CMN
1578 }
1579
c5837cad
CMN
1580 /* only try to do opportunisitic updates if the refpec lists differ */
1581 if (remote->passed_refspecs)
9566ce43 1582 error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
c5837cad 1583
505b5d0c 1584out:
877cde76 1585 git_vector_free(&refs);
505b5d0c 1586 git_refspec__free(&tagspec);
505b5d0c 1587 return error;
4330ab26
CMN
1588}
1589
11f6ad5f 1590int git_remote_connected(const git_remote *remote)
6ac3b707 1591{
4bef3565 1592 assert(remote);
41fb1ca0
PK
1593
1594 if (!remote->transport || !remote->transport->is_connected)
1595 return 0;
1596
1597 /* Ask the transport if it's connected. */
613d5eb9 1598 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
1599}
1600
f0d2ddbb
CMN
1601void git_remote_stop(git_remote *remote)
1602{
613d5eb9
PK
1603 assert(remote);
1604
1605 if (remote->transport && remote->transport->cancel)
41fb1ca0 1606 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
1607}
1608
4cf01e9a
CMN
1609void git_remote_disconnect(git_remote *remote)
1610{
4bef3565
VM
1611 assert(remote);
1612
41fb1ca0
PK
1613 if (git_remote_connected(remote))
1614 remote->transport->close(remote->transport);
4cf01e9a
CMN
1615}
1616
9c82357b
CMN
1617void git_remote_free(git_remote *remote)
1618{
2aae2188
CMN
1619 if (remote == NULL)
1620 return;
1621
42ea35c0
MS
1622 if (remote->transport != NULL) {
1623 git_remote_disconnect(remote);
1624
1625 remote->transport->free(remote->transport);
1626 remote->transport = NULL;
1627 }
1628
1629 git_vector_free(&remote->refs);
1630
af613ecd 1631 free_refspecs(&remote->refspecs);
4330ab26
CMN
1632 git_vector_free(&remote->refspecs);
1633
af613ecd
CMN
1634 free_refspecs(&remote->active_refspecs);
1635 git_vector_free(&remote->active_refspecs);
1636
2cdd5c57
CMN
1637 free_refspecs(&remote->passive_refspecs);
1638 git_vector_free(&remote->passive_refspecs);
1639
fe794b2e 1640 git_push_free(remote->push);
3286c408 1641 git__free(remote->url);
3ed4b501 1642 git__free(remote->pushurl);
3286c408 1643 git__free(remote->name);
3286c408 1644 git__free(remote);
9c82357b 1645}
8171998f 1646
106c12f1 1647static int remote_list_cb(const git_config_entry *entry, void *payload)
8171998f 1648{
25e0b157 1649 git_vector *list = payload;
106c12f1
RB
1650 const char *name = entry->name + strlen("remote.");
1651 size_t namelen = strlen(name);
1652 char *remote_name;
8171998f 1653
106c12f1 1654 /* we know name matches "remote.<stuff>.(push)?url" */
8171998f 1655
106c12f1
RB
1656 if (!strcmp(&name[namelen - 4], ".url"))
1657 remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1658 else
1659 remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
25e0b157 1660 GITERR_CHECK_ALLOC(remote_name);
8171998f 1661
25e0b157 1662 return git_vector_insert(list, remote_name);
8171998f
CMN
1663}
1664
1665int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1666{
8171998f 1667 int error;
96869a4e 1668 git_config *cfg;
25e0b157 1669 git_vector list = GIT_VECTOR_INIT;
8171998f 1670
96869a4e
RB
1671 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1672 return error;
8171998f 1673
25e0b157 1674 if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
96869a4e 1675 return error;
8171998f 1676
106c12f1 1677 error = git_config_foreach_match(
25e0b157 1678 cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
8171998f 1679
4376f7f6 1680 if (error < 0) {
9cfce273 1681 git_vector_free_deep(&list);
8171998f
CMN
1682 return error;
1683 }
1684
25e0b157 1685 git_vector_uniq(&list, git__free);
aec87f71 1686
25e0b157
RB
1687 remotes_list->strings =
1688 (char **)git_vector_detach(&remotes_list->count, NULL, &list);
8171998f 1689
4376f7f6 1690 return 0;
8171998f 1691}
a209a025 1692
67dad09b 1693const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1694{
1695 assert(remote);
1696 return &remote->stats;
1697}
1698
11f6ad5f 1699git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
f70e466f
CMN
1700{
1701 return remote->download_tags;
1702}
1703
35a8a8c5 1704int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
f70e466f 1705{
35a8a8c5
CMN
1706 git_buf var = GIT_BUF_INIT;
1707 git_config *config;
1708 int error;
1709
1710 assert(repo && remote);
1711
1712 if ((error = ensure_remote_name_is_valid(remote)) < 0)
1713 return error;
1714
1715 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1716 return error;
1717
1718 if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
1719 return error;
1720
1721 switch (value) {
1722 case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
1723 error = git_config_set_string(config, var.ptr, "--no-tags");
1724 break;
1725 case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
1726 error = git_config_set_string(config, var.ptr, "--tags");
1727 break;
1728 case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
1729 error = git_config_delete_entry(config, var.ptr);
1730 if (error == GIT_ENOTFOUND)
1731 error = 0;
1732 break;
1733 default:
1734 giterr_set(GITERR_INVALID, "Invalid value for the tagopt setting");
1735 error = -1;
1736 }
1737
1738 git_buf_free(&var);
1739 return error;
f70e466f 1740}
fcccf304 1741
5f473947
L
1742int git_remote_prune_refs(const git_remote *remote)
1743{
1744 return remote->prune_refs;
1745}
1746
fcccf304 1747static int rename_remote_config_section(
1748 git_repository *repo,
1749 const char *old_name,
1750 const char *new_name)
1751{
1752 git_buf old_section_name = GIT_BUF_INIT,
1753 new_section_name = GIT_BUF_INIT;
1754 int error = -1;
1755
1756 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1757 goto cleanup;
1758
40e48ea4 1759 if (new_name &&
1760 (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1761 goto cleanup;
fcccf304 1762
1763 error = git_config_rename_section(
1764 repo,
1765 git_buf_cstr(&old_section_name),
40e48ea4 1766 new_name ? git_buf_cstr(&new_section_name) : NULL);
fcccf304 1767
1768cleanup:
1769 git_buf_free(&old_section_name);
1770 git_buf_free(&new_section_name);
1771
1772 return error;
1773}
1774
96869a4e 1775struct update_data {
fcccf304 1776 git_config *config;
1777 const char *old_remote_name;
1778 const char *new_remote_name;
1779};
1780
1781static int update_config_entries_cb(
1782 const git_config_entry *entry,
1783 void *payload)
1784{
1785 struct update_data *data = (struct update_data *)payload;
1786
1787 if (strcmp(entry->value, data->old_remote_name))
1788 return 0;
1789
25e0b157
RB
1790 return git_config_set_string(
1791 data->config, entry->name, data->new_remote_name);
fcccf304 1792}
1793
1794static int update_branch_remote_config_entry(
1795 git_repository *repo,
1796 const char *old_name,
1797 const char *new_name)
1798{
96869a4e
RB
1799 int error;
1800 struct update_data data = { NULL };
fcccf304 1801
96869a4e
RB
1802 if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1803 return error;
fcccf304 1804
fcccf304 1805 data.old_remote_name = old_name;
1806 data.new_remote_name = new_name;
1807
25e0b157 1808 return git_config_foreach_match(
96869a4e 1809 data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
fcccf304 1810}
1811
fcccf304 1812static int rename_one_remote_reference(
d1544564 1813 git_reference *reference_in,
fcccf304 1814 const char *old_remote_name,
1815 const char *new_remote_name)
1816{
96869a4e 1817 int error;
d1544564
CMN
1818 git_reference *ref = NULL, *dummy = NULL;
1819 git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
fcccf304 1820 git_buf new_name = GIT_BUF_INIT;
ccf6ce5c 1821 git_buf log_message = GIT_BUF_INIT;
d1544564
CMN
1822 size_t pfx_len;
1823 const char *target;
fcccf304 1824
d1544564
CMN
1825 if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1826 return error;
1827
1828 pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1829 git_buf_puts(&new_name, namespace.ptr);
1830 if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
ccf6ce5c 1831 goto cleanup;
fcccf304 1832
ccf6ce5c
BS
1833 if ((error = git_buf_printf(&log_message,
1834 "renamed remote %s to %s",
1835 old_remote_name, new_remote_name)) < 0)
1836 goto cleanup;
fcccf304 1837
d1544564 1838 if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
659cf202 1839 git_buf_cstr(&log_message))) < 0)
d1544564
CMN
1840 goto cleanup;
1841
1842 if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1843 goto cleanup;
1844
1845 /* Handle refs like origin/HEAD -> origin/master */
1846 target = git_reference_symbolic_target(ref);
1847 if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1848 goto cleanup;
1849
1850 if (git__prefixcmp(target, old_namespace.ptr))
1851 goto cleanup;
1852
1853 git_buf_clear(&new_name);
1854 git_buf_puts(&new_name, namespace.ptr);
1855 if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1856 goto cleanup;
1857
1858 error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
659cf202 1859 git_buf_cstr(&log_message));
d1544564
CMN
1860
1861 git_reference_free(dummy);
ccf6ce5c
BS
1862
1863cleanup:
d1544564
CMN
1864 git_reference_free(reference_in);
1865 git_reference_free(ref);
1866 git_buf_free(&namespace);
1867 git_buf_free(&old_namespace);
fcccf304 1868 git_buf_free(&new_name);
ccf6ce5c 1869 git_buf_free(&log_message);
fcccf304 1870 return error;
1871}
1872
1873static int rename_remote_references(
1874 git_repository *repo,
1875 const char *old_name,
1876 const char *new_name)
1877{
96869a4e 1878 int error;
a52ab4b8 1879 git_buf buf = GIT_BUF_INIT;
56960b83 1880 git_reference *ref;
9bd89d96 1881 git_reference_iterator *iter;
fcccf304 1882
a52ab4b8 1883 if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
96869a4e 1884 return error;
fcccf304 1885
a52ab4b8
CMN
1886 error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1887 git_buf_free(&buf);
9bd89d96 1888
a52ab4b8
CMN
1889 if (error < 0)
1890 return error;
1891
1892 while ((error = git_reference_next(&ref, iter)) == 0) {
96869a4e
RB
1893 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1894 break;
9bd89d96
CMN
1895 }
1896
1897 git_reference_iterator_free(iter);
fcccf304 1898
96869a4e 1899 return (error == GIT_ITEROVER) ? 0 : error;
fcccf304 1900}
1901
72bca13e 1902static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
fcccf304 1903{
1904 git_config *config;
4330ab26 1905 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1906 const git_refspec *spec;
4330ab26 1907 size_t i;
25e0b157 1908 int error = 0;
fcccf304 1909
dab89f9b 1910 if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
25e0b157
RB
1911 return error;
1912
72bca13e
CMN
1913 if ((error = git_vector_init(problems, 1, NULL)) < 0)
1914 return error;
1915
25e0b157
RB
1916 if ((error = git_buf_printf(
1917 &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
1918 return error;
dab89f9b 1919
1be680c4 1920 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1921 if (spec->push)
1922 continue;
fcccf304 1923
dab89f9b 1924 /* Does the dst part of the refspec follow the expected format? */
5a49ff9f 1925 if (strcmp(git_buf_cstr(&base), spec->string)) {
72bca13e 1926 char *dup;
fcccf304 1927
72bca13e
CMN
1928 dup = git__strdup(spec->string);
1929 GITERR_CHECK_ALLOC(dup);
1930
1931 if ((error = git_vector_insert(problems, dup)) < 0)
25e0b157 1932 break;
c7b3e1b3 1933
4330ab26
CMN
1934 continue;
1935 }
fcccf304 1936
4330ab26 1937 /* If we do want to move it to the new section */
fcccf304 1938
dab89f9b
RB
1939 git_buf_clear(&val);
1940 git_buf_clear(&var);
fcccf304 1941
dab89f9b
RB
1942 if (git_buf_printf(
1943 &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
1944 git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1945 {
1946 error = -1;
25e0b157 1947 break;
dab89f9b 1948 }
fcccf304 1949
dab89f9b
RB
1950 if ((error = git_config_set_string(
1951 config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
25e0b157 1952 break;
4330ab26 1953 }
fcccf304 1954
4330ab26
CMN
1955 git_buf_free(&base);
1956 git_buf_free(&var);
1957 git_buf_free(&val);
72bca13e
CMN
1958
1959 if (error < 0) {
1960 char *str;
1961 git_vector_foreach(problems, i, str)
1962 git__free(str);
1963
1964 git_vector_free(problems);
1965 }
1966
fcccf304 1967 return error;
1968}
1969
46c8f7f8 1970int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
fcccf304 1971{
1972 int error;
46c8f7f8 1973 git_vector problem_refspecs = GIT_VECTOR_INIT;
64bcf567 1974 git_remote *remote = NULL;
fcccf304 1975
46c8f7f8 1976 assert(out && repo && name && new_name);
fcccf304 1977
209425ce 1978 if ((error = git_remote_lookup(&remote, repo, name)) < 0)
cce27d82 1979 return error;
79000951 1980
fcccf304 1981 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
46c8f7f8 1982 goto cleanup;
fcccf304 1983
46c8f7f8
CMN
1984 if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
1985 goto cleanup;
fcccf304 1986
46c8f7f8
CMN
1987 if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
1988 goto cleanup;
fcccf304 1989
46c8f7f8
CMN
1990 if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
1991 goto cleanup;
fcccf304 1992
46c8f7f8
CMN
1993 if ((error = rename_remote_references(repo, name, new_name)) < 0)
1994 goto cleanup;
fcccf304 1995
72bca13e 1996 if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
46c8f7f8 1997 goto cleanup;
fcccf304 1998
72bca13e
CMN
1999 out->count = problem_refspecs.length;
2000 out->strings = (char **) problem_refspecs.contents;
2001
46c8f7f8
CMN
2002cleanup:
2003 if (error < 0)
2004 git_vector_free(&problem_refspecs);
fcccf304 2005
46c8f7f8
CMN
2006 git_remote_free(remote);
2007 return error;
fcccf304 2008}
b0f6e45d 2009
2bca5b67 2010int git_remote_is_valid_name(
2011 const char *remote_name)
2012{
2013 git_buf buf = GIT_BUF_INIT;
2014 git_refspec refspec;
2015 int error = -1;
2016
2017 if (!remote_name || *remote_name == '\0')
2018 return 0;
2019
2020 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
2021 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
2022
2023 git_buf_free(&buf);
2024 git_refspec__free(&refspec);
2025
2026 giterr_clear();
2027 return error == 0;
2028}
4330ab26
CMN
2029
2030git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
2031{
2032 git_refspec *spec;
2033 size_t i;
2034
af613ecd 2035 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2036 if (spec->push)
2037 continue;
2038
2039 if (git_refspec_src_matches(spec, refname))
2040 return spec;
2041 }
2042
2043 return NULL;
2044}
2045
2046git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
2047{
2048 git_refspec *spec;
2049 size_t i;
2050
af613ecd 2051 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2052 if (spec->push)
2053 continue;
2054
2055 if (git_refspec_dst_matches(spec, refname))
2056 return spec;
2057 }
2058
2059 return NULL;
2060}
2061
77254990 2062int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
4330ab26 2063{
77254990 2064 return write_add_refspec(repo, remote, refspec, true);
4330ab26
CMN
2065}
2066
77254990 2067int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
4330ab26 2068{
77254990 2069 return write_add_refspec(repo, remote, refspec, false);
266af6d8
CMN
2070}
2071
2072static int set_refspecs(git_remote *remote, git_strarray *array, int push)
2073{
2074 git_vector *vec = &remote->refspecs;
2075 git_refspec *spec;
2076 size_t i;
2077
2078 /* Start by removing any refspecs of the same type */
2079 for (i = 0; i < vec->length; i++) {
2080 spec = git_vector_get(vec, i);
2081 if (spec->push != push)
2082 continue;
2083
2084 git_refspec__free(spec);
2085 git__free(spec);
2086 git_vector_remove(vec, i);
2087 i--;
2088 }
2089
2090 /* And now we add the new ones */
2091
2092 for (i = 0; i < array->count; i++) {
2093 if (add_refspec(remote, array->strings[i], !push) < 0)
2094 return -1;
2095 }
2096
c300d84a 2097 return 0;
266af6d8
CMN
2098}
2099
11f6ad5f 2100static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
bc6374ea
CMN
2101{
2102 size_t i;
2103 git_vector refspecs;
2104 git_refspec *spec;
2105 char *dup;
2106
2107 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
2108 return -1;
2109
2110 git_vector_foreach(&remote->refspecs, i, spec) {
2111 if (spec->push != push)
2112 continue;
2113
1be680c4 2114 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 2115 goto on_error;
bc6374ea
CMN
2116
2117 if (git_vector_insert(&refspecs, dup) < 0) {
2118 git__free(dup);
2119 goto on_error;
2120 }
2121 }
2122
2123 array->strings = (char **)refspecs.contents;
2124 array->count = refspecs.length;
2125
2126 return 0;
2127
2128on_error:
9cfce273 2129 git_vector_free_deep(&refspecs);
bc6374ea
CMN
2130
2131 return -1;
2132}
2133
11f6ad5f 2134int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2135{
2136 return copy_refspecs(array, remote, false);
2137}
2138
11f6ad5f 2139int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2140{
2141 return copy_refspecs(array, remote, true);
2142}
1ffd0806 2143
11f6ad5f 2144size_t git_remote_refspec_count(const git_remote *remote)
1ffd0806
CMN
2145{
2146 return remote->refspecs.length;
2147}
2148
11f6ad5f 2149const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1ffd0806
CMN
2150{
2151 return git_vector_get(&remote->refspecs, n);
2152}
b9f81997 2153
bc91347b 2154int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
b9f81997 2155{
bc91347b
RB
2156 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2157 opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
2158 return 0;
b9f81997 2159}
40e48ea4 2160
5cdac19c
CMN
2161/* asserts a branch.<foo>.remote format */
2162static const char *name_offset(size_t *len_out, const char *name)
40e48ea4 2163{
5cdac19c
CMN
2164 size_t prefix_len;
2165 const char *dot;
40e48ea4 2166
5cdac19c
CMN
2167 prefix_len = strlen("remote.");
2168 dot = strchr(name + prefix_len, '.');
40e48ea4 2169
5cdac19c 2170 assert(dot);
40e48ea4 2171
5cdac19c
CMN
2172 *len_out = dot - name - prefix_len;
2173 return name + prefix_len;
40e48ea4 2174}
2175
2176static int remove_branch_config_related_entries(
2177 git_repository *repo,
2178 const char *remote_name)
2179{
2180 int error;
2181 git_config *config;
5cdac19c
CMN
2182 git_config_entry *entry;
2183 git_config_iterator *iter;
2184 git_buf buf = GIT_BUF_INIT;
40e48ea4 2185
2186 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2187 return error;
2188
5cdac19c 2189 if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
40e48ea4 2190 return error;
2191
5cdac19c
CMN
2192 /* find any branches with us as upstream and remove that config */
2193 while ((error = git_config_next(&entry, iter)) == 0) {
2194 const char *branch;
2195 size_t branch_len;
40e48ea4 2196
5cdac19c
CMN
2197 if (strcmp(remote_name, entry->value))
2198 continue;
40e48ea4 2199
5cdac19c 2200 branch = name_offset(&branch_len, entry->name);
40e48ea4 2201
5cdac19c
CMN
2202 git_buf_clear(&buf);
2203 if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
2204 break;
2205
2206 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2207 break;
2208
2209 git_buf_clear(&buf);
2210 if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
2211 break;
2212
2213 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2214 break;
40e48ea4 2215 }
2216
5cdac19c
CMN
2217 if (error == GIT_ITEROVER)
2218 error = 0;
2219
2220 git_buf_free(&buf);
2221 git_config_iterator_free(iter);
40e48ea4 2222 return error;
2223}
2224
8a9419aa 2225static int remove_refs(git_repository *repo, const git_refspec *spec)
ec8a949a 2226{
8a9419aa
CMN
2227 git_reference_iterator *iter = NULL;
2228 git_vector refs;
ec8a949a 2229 const char *name;
8a9419aa 2230 char *dup;
ec8a949a 2231 int error;
8a9419aa 2232 size_t i;
ec8a949a 2233
8a9419aa 2234 if ((error = git_vector_init(&refs, 8, NULL)) < 0)
ec8a949a
CMN
2235 return error;
2236
8a9419aa
CMN
2237 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2238 goto cleanup;
2239
ec8a949a 2240 while ((error = git_reference_next_name(&name, iter)) == 0) {
8a9419aa
CMN
2241 if (!git_refspec_dst_matches(spec, name))
2242 continue;
2243
2244 dup = git__strdup(name);
2245 if (!dup) {
2246 error = -1;
2247 goto cleanup;
2248 }
ec8a949a 2249
8a9419aa
CMN
2250 if ((error = git_vector_insert(&refs, dup)) < 0)
2251 goto cleanup;
2252 }
ec8a949a
CMN
2253 if (error == GIT_ITEROVER)
2254 error = 0;
8a9419aa
CMN
2255 if (error < 0)
2256 goto cleanup;
2257
2258 git_vector_foreach(&refs, i, name) {
2259 if ((error = git_reference_remove(repo, name)) < 0)
2260 break;
2261 }
ec8a949a 2262
8a9419aa
CMN
2263cleanup:
2264 git_reference_iterator_free(iter);
2265 git_vector_foreach(&refs, i, dup) {
2266 git__free(dup);
2267 }
2268 git_vector_free(&refs);
ec8a949a
CMN
2269 return error;
2270}
2271
2272static int remove_remote_tracking(git_repository *repo, const char *remote_name)
2273{
2274 git_remote *remote;
2275 int error;
2276 size_t i, count;
2277
2278 /* we want to use what's on the config, regardless of changes to the instance in memory */
209425ce 2279 if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
ec8a949a
CMN
2280 return error;
2281
2282 count = git_remote_refspec_count(remote);
2283 for (i = 0; i < count; i++) {
2284 const git_refspec *refspec = git_remote_get_refspec(remote, i);
2285
2286 /* shouldn't ever actually happen */
2287 if (refspec == NULL)
2288 continue;
2289
8a9419aa 2290 if ((error = remove_refs(repo, refspec)) < 0)
ec8a949a
CMN
2291 break;
2292 }
2293
2294 git_remote_free(remote);
2295 return error;
2296}
2297
262eec23 2298int git_remote_delete(git_repository *repo, const char *name)
40e48ea4 2299{
2300 int error;
40e48ea4 2301
262eec23 2302 assert(repo && name);
ec8a949a 2303
262eec23
CMN
2304 if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
2305 (error = remove_remote_tracking(repo, name)) < 0 ||
2306 (error = rename_remote_config_section(repo, name, NULL)) < 0)
ec8a949a
CMN
2307 return error;
2308
40e48ea4 2309 return 0;
2310}
d22db24f
CMN
2311
2312int git_remote_default_branch(git_buf *out, git_remote *remote)
2313{
2314 const git_remote_head **heads;
2315 const git_remote_head *guess = NULL;
2316 const git_oid *head_id;
2317 size_t heads_len, i;
2318 int error;
2319
dc8adda4
JG
2320 assert(out);
2321
d22db24f
CMN
2322 if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2323 return error;
2324
2325 if (heads_len == 0)
2326 return GIT_ENOTFOUND;
2327
0cdaa376
CMN
2328 if (strcmp(heads[0]->name, GIT_HEAD_FILE))
2329 return GIT_ENOTFOUND;
2330
d22db24f
CMN
2331 git_buf_sanitize(out);
2332 /* the first one must be HEAD so if that has the symref info, we're done */
2333 if (heads[0]->symref_target)
2334 return git_buf_puts(out, heads[0]->symref_target);
2335
2336 /*
2337 * If there's no symref information, we have to look over them
2338 * and guess. We return the first match unless the master
2339 * branch is a candidate. Then we return the master branch.
2340 */
2341 head_id = &heads[0]->oid;
2342
2343 for (i = 1; i < heads_len; i++) {
2344 if (git_oid_cmp(head_id, &heads[i]->oid))
2345 continue;
2346
38952604
CMN
2347 if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
2348 continue;
2349
d22db24f
CMN
2350 if (!guess) {
2351 guess = heads[i];
2352 continue;
2353 }
2354
2355 if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
2356 guess = heads[i];
2357 break;
2358 }
2359 }
2360
2361 if (!guess)
2362 return GIT_ENOTFOUND;
2363
2364 return git_buf_puts(out, guess->name);
2365}
3149547b 2366
fe794b2e 2367int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
3149547b 2368{
3149547b 2369 size_t i;
fe794b2e
CMN
2370 int error;
2371 git_push *push;
64e3e6d4 2372 git_refspec *spec;
8f0104ec 2373 const git_remote_callbacks *cbs = NULL;
3149547b 2374
fe794b2e 2375 assert(remote);
3149547b 2376
8f0104ec
CMN
2377 if (opts)
2378 cbs = &opts->callbacks;
2379
fe794b2e 2380 if (!git_remote_connected(remote) &&
8f0104ec 2381 (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2382 goto cleanup;
2383
1034f1b5 2384 free_refspecs(&remote->active_refspecs);
69f0032b 2385 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1034f1b5
POL
2386 goto cleanup;
2387
fe794b2e
CMN
2388 if (remote->push) {
2389 git_push_free(remote->push);
2390 remote->push = NULL;
2391 }
2392
2393 if ((error = git_push_new(&remote->push, remote)) < 0)
3149547b
CMN
2394 return error;
2395
fe794b2e 2396 push = remote->push;
3149547b
CMN
2397
2398 if (opts && (error = git_push_set_options(push, opts)) < 0)
2399 goto cleanup;
2400
64e3e6d4
CMN
2401 if (refspecs && refspecs->count > 0) {
2402 for (i = 0; i < refspecs->count; i++) {
2403 if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
2404 goto cleanup;
2405 }
2406 } else {
2407 git_vector_foreach(&remote->refspecs, i, spec) {
2408 if (!spec->push)
2409 continue;
2410 if ((error = git_push_add_refspec(push, spec->string)) < 0)
2411 goto cleanup;
2412 }
3149547b
CMN
2413 }
2414
8f0104ec 2415 if ((error = git_push_finish(push, cbs)) < 0)
3149547b
CMN
2416 goto cleanup;
2417
8f0104ec 2418 if (cbs && cbs->push_update_reference &&
52ee0e8e 2419 (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
3149547b
CMN
2420 goto cleanup;
2421
3149547b 2422cleanup:
fe794b2e
CMN
2423 return error;
2424}
2425
412a3808 2426int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
fe794b2e
CMN
2427{
2428 int error;
8f0104ec
CMN
2429 const git_remote_callbacks *cbs = NULL;
2430
2431 if (opts) {
2432 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2433 cbs = &opts->callbacks;
2434 }
fe794b2e
CMN
2435
2436 assert(remote && refspecs);
2437
8f0104ec 2438 if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2439 return error;
2440
2441 if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2442 return error;
2443
35a8a8c5 2444 error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
fe794b2e 2445
3149547b 2446 git_remote_disconnect(remote);
3149547b
CMN
2447 return error;
2448}
ec0c4c40
PS
2449
2450#define PREFIX "url"
2451#define SUFFIX_FETCH "insteadof"
2452#define SUFFIX_PUSH "pushinsteadof"
2453
2454char *apply_insteadof(git_config *config, const char *url, int direction)
2455{
2456 size_t match_length, prefix_length, suffix_length;
2457 char *replacement = NULL;
2458 const char *regexp;
2459
2460 git_buf result = GIT_BUF_INIT;
2461 git_config_entry *entry;
2462 git_config_iterator *iter;
2463
2464 assert(config);
2465 assert(url);
2466 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
2467
2468 /* Add 1 to prefix/suffix length due to the additional escaped dot */
2469 prefix_length = strlen(PREFIX) + 1;
2470 if (direction == GIT_DIRECTION_FETCH) {
2471 regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
2472 suffix_length = strlen(SUFFIX_FETCH) + 1;
2473 } else {
2474 regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
2475 suffix_length = strlen(SUFFIX_PUSH) + 1;
2476 }
2477
2785544f
CMN
2478 if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
2479 return NULL;
ec0c4c40
PS
2480
2481 match_length = 0;
2482 while (git_config_next(&entry, iter) == 0) {
2483 size_t n, replacement_length;
2484
2485 /* Check if entry value is a prefix of URL */
2486 if (git__prefixcmp(url, entry->value))
2487 continue;
2488 /* Check if entry value is longer than previous
2489 * prefixes */
2490 if ((n = strlen(entry->value)) <= match_length)
2491 continue;
2492
2493 git__free(replacement);
2494 match_length = n;
2495
2496 /* Cut off prefix and suffix of the value */
2497 replacement_length =
2498 strlen(entry->name) - (prefix_length + suffix_length);
2499 replacement = git__strndup(entry->name + prefix_length,
2500 replacement_length);
2501 }
2502
2503 git_config_iterator_free(iter);
2504
2505 if (match_length == 0)
2506 return git__strdup(url);
2507
2508 git_buf_printf(&result, "%s%s", replacement, url + match_length);
2509
2510 git__free(replacement);
2511
2512 return result.ptr;
2513}