]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
remote: don't DWIM refspecs unnecessarily
[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"
9c82357b 21
af613ecd
CMN
22static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
23
3f894205 24static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
9c82357b 25{
4330ab26 26 git_refspec *spec;
9c82357b 27
4330ab26
CMN
28 spec = git__calloc(1, sizeof(git_refspec));
29 GITERR_CHECK_ALLOC(spec);
30
1be680c4
CMN
31 if (git_refspec__parse(spec, string, is_fetch) < 0) {
32 git__free(spec);
33 return -1;
34 }
4330ab26
CMN
35
36 spec->push = !is_fetch;
3f894205 37 if (git_vector_insert(vector, spec) < 0) {
1be680c4
CMN
38 git_refspec__free(spec);
39 git__free(spec);
40 return -1;
41 }
9c82357b 42
4330ab26 43 return 0;
9c82357b
CMN
44}
45
3f894205
CMN
46static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
47{
48 return add_refspec_to(&remote->refspecs, string, is_fetch);
49}
50
24f2f94e
CMN
51static int download_tags_value(git_remote *remote, git_config *cfg)
52{
9f77b3f6 53 const git_config_entry *ce;
24f2f94e
CMN
54 git_buf buf = GIT_BUF_INIT;
55 int error;
56
df50512a 57 /* The 0 value is the default (auto), let's see if we need to change it */
24f2f94e
CMN
58 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
59 return -1;
60
9f77b3f6 61 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
24f2f94e 62 git_buf_free(&buf);
24f2f94e 63
9f77b3f6
RB
64 if (!error && ce && ce->value) {
65 if (!strcmp(ce->value, "--no-tags"))
66 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
67 else if (!strcmp(ce->value, "--tags"))
68 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
bf6bebe2 69 }
24f2f94e
CMN
70
71 return error;
72}
73
032ba9e4 74static int ensure_remote_name_is_valid(const char *name)
75{
2bca5b67 76 int error = 0;
032ba9e4 77
2bca5b67 78 if (!git_remote_is_valid_name(name)) {
032ba9e4 79 giterr_set(
80 GITERR_CONFIG,
183aa4f8 81 "'%s' is not a valid remote name.", name ? name : "(null)");
032ba9e4 82 error = GIT_EINVALIDSPEC;
83 }
84
85 return error;
86}
87
41698f22
CMN
88#if 0
89/* We could export this as a helper */
80fc7d6b 90static int get_check_cert(int *out, git_repository *repo)
af6dab7e
PK
91{
92 git_config *cfg;
93 const char *val;
80fc7d6b
ET
94 int error = 0;
95
96 assert(out && repo);
af6dab7e 97
80fc7d6b
ET
98 /* By default, we *DO* want to verify the certificate. */
99 *out = 1;
af6dab7e
PK
100
101 /* Go through the possible sources for SSL verification settings, from
102 * most specific to least specific. */
103
104 /* GIT_SSL_NO_VERIFY environment variable */
8f2a3d62 105 if ((val = getenv("GIT_SSL_NO_VERIFY")) != NULL)
80fc7d6b 106 return git_config_parse_bool(out, val);
af6dab7e
PK
107
108 /* http.sslVerify config setting */
80fc7d6b
ET
109 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
110 return error;
af6dab7e 111
9f77b3f6 112 *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
80fc7d6b 113 return 0;
af6dab7e 114}
41698f22 115#endif
af6dab7e 116
874dcb25 117static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
118{
119 git_remote *remote;
44f36f6e
BS
120 git_buf fetchbuf = GIT_BUF_INIT;
121 int error = -1;
778e1c73 122
4bef3565 123 /* name is optional */
874dcb25 124 assert(out && repo && url);
617bfdf4 125
59bccf33 126 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 127 GITERR_CHECK_ALLOC(remote);
778e1c73 128
778e1c73 129 remote->repo = repo;
b0f6e45d 130 remote->update_fetchhead = 1;
617bfdf4 131
4376f7f6 132 if (git_vector_init(&remote->refs, 32, NULL) < 0)
44f36f6e 133 goto on_error;
d88d4311 134
778e1c73 135 remote->url = git__strdup(url);
4376f7f6 136 GITERR_CHECK_ALLOC(remote->url);
778e1c73 137
617bfdf4
CMN
138 if (name != NULL) {
139 remote->name = git__strdup(name);
4376f7f6 140 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
141 }
142
baaa8a44 143 if (fetch != NULL) {
4330ab26 144 if (add_refspec(remote, fetch, true) < 0)
baaa8a44
CMN
145 goto on_error;
146 }
147
215af2cc 148 if (!name)
149 /* A remote without a name doesn't download tags */
c648d4a8 150 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
c648d4a8 151
778e1c73 152 *out = remote;
44f36f6e 153 git_buf_free(&fetchbuf);
4376f7f6 154 return 0;
baaa8a44
CMN
155
156on_error:
157 git_remote_free(remote);
44f36f6e
BS
158 git_buf_free(&fetchbuf);
159 return error;
778e1c73
CMN
160}
161
592f466c
BS
162static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
163{
164 int error;
165 git_remote *remote;
166
167 error = git_remote_load(&remote, repo, name);
168
169 if (error == GIT_ENOTFOUND)
170 return 0;
171
172 if (error < 0)
173 return error;
174
175 git_remote_free(remote);
176
177 giterr_set(
178 GITERR_CONFIG,
179 "Remote '%s' already exists.", name);
180
181 return GIT_EEXISTS;
182}
183
f19304d2 184
874dcb25
BS
185int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
186{
187 git_buf buf = GIT_BUF_INIT;
c5193e3c 188 git_remote *remote = NULL;
874dcb25
BS
189 int error;
190
191 if ((error = ensure_remote_name_is_valid(name)) < 0)
192 return error;
193
f19304d2 194 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
195 return error;
196
874dcb25
BS
197 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
198 return -1;
199
c5193e3c 200 if (create_internal(&remote, repo, name, url, git_buf_cstr(&buf)) < 0)
874dcb25
BS
201 goto on_error;
202
203 git_buf_free(&buf);
204
c5193e3c 205 if (git_remote_save(remote) < 0)
874dcb25
BS
206 goto on_error;
207
c5193e3c 208 *out = remote;
209
874dcb25
BS
210 return 0;
211
212on_error:
213 git_buf_free(&buf);
c5193e3c 214 git_remote_free(remote);
874dcb25
BS
215 return -1;
216}
217
40b99d05
VG
218int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
219{
40b99d05
VG
220 git_remote *remote = NULL;
221 int error;
222
223 if ((error = ensure_remote_name_is_valid(name)) < 0)
224 return error;
225
226 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
227 return error;
874dcb25 228
0fe522d1 229 if (create_internal(&remote, repo, name, url, fetch) < 0)
874dcb25
BS
230 goto on_error;
231
c5193e3c 232 if (git_remote_save(remote) < 0)
874dcb25
BS
233 goto on_error;
234
c5193e3c 235 *out = remote;
236
874dcb25
BS
237 return 0;
238
239on_error:
c5193e3c 240 git_remote_free(remote);
874dcb25
BS
241 return -1;
242}
243
fd536d29 244int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url, const char *fetch)
874dcb25
BS
245{
246 int error;
247 git_remote *remote;
248
79000951 249 if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0)
874dcb25
BS
250 return error;
251
874dcb25
BS
252 *out = remote;
253 return 0;
254}
255
991b2840 256int git_remote_dup(git_remote **dest, git_remote *source)
40ef47dd 257{
991b2840
AS
258 int error = 0;
259 git_strarray refspecs = { 0 };
40ef47dd
AS
260 git_remote *remote = git__calloc(1, sizeof(git_remote));
261 GITERR_CHECK_ALLOC(remote);
262
40ef47dd
AS
263 if (source->name != NULL) {
264 remote->name = git__strdup(source->name);
265 GITERR_CHECK_ALLOC(remote->name);
266 }
267
268 if (source->url != NULL) {
269 remote->url = git__strdup(source->url);
270 GITERR_CHECK_ALLOC(remote->url);
271 }
272
273 if (source->pushurl != NULL) {
274 remote->pushurl = git__strdup(source->pushurl);
1697cd6f 275 GITERR_CHECK_ALLOC(remote->pushurl);
40ef47dd
AS
276 }
277
1697cd6f
PK
278 remote->transport_cb = source->transport_cb;
279 remote->transport_cb_payload = source->transport_cb_payload;
40ef47dd 280 remote->repo = source->repo;
40ef47dd 281 remote->download_tags = source->download_tags;
40ef47dd
AS
282 remote->update_fetchhead = source->update_fetchhead;
283
991b2840
AS
284 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
285 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
286 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
287 error = -1;
288 goto cleanup;
40ef47dd
AS
289 }
290
991b2840
AS
291 if ((error = git_remote_get_fetch_refspecs(&refspecs, source)) < 0 ||
292 (error = git_remote_set_fetch_refspecs(remote, &refspecs)) < 0)
293 goto cleanup;
294
295 git_strarray_free(&refspecs);
296
297 if ((error = git_remote_get_push_refspecs(&refspecs, source)) < 0 ||
298 (error = git_remote_set_push_refspecs(remote, &refspecs)) < 0)
299 goto cleanup;
300
40ef47dd
AS
301 *dest = remote;
302
991b2840
AS
303cleanup:
304
305 git_strarray_free(&refspecs);
306
307 if (error < 0)
308 git__free(remote);
309
310 return error;
40ef47dd
AS
311}
312
4330ab26
CMN
313struct refspec_cb_data {
314 git_remote *remote;
315 int fetch;
316};
317
318static int refspec_cb(const git_config_entry *entry, void *payload)
319{
96869a4e 320 struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
25e0b157 321 return add_refspec(data->remote, entry->value, data->fetch);
4330ab26
CMN
322}
323
bf6bebe2 324static int get_optional_config(
c9ffa84b 325 bool *found, git_config *config, git_buf *buf,
326 git_config_foreach_cb cb, void *payload)
bf6bebe2
RB
327{
328 int error = 0;
329 const char *key = git_buf_cstr(buf);
330
331 if (git_buf_oom(buf))
332 return -1;
333
334 if (cb != NULL)
4efa3290 335 error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
bf6bebe2
RB
336 else
337 error = git_config_get_string(payload, config, key);
338
c9ffa84b 339 if (found)
340 *found = !error;
341
bf6bebe2
RB
342 if (error == GIT_ENOTFOUND) {
343 giterr_clear();
344 error = 0;
345 }
346
bf6bebe2
RB
347 return error;
348}
349
9462c471 350int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
351{
352 git_remote *remote;
f0f3a18a 353 git_buf buf = GIT_BUF_INIT;
9c82357b 354 const char *val;
4376f7f6 355 int error = 0;
9462c471 356 git_config *config;
96869a4e 357 struct refspec_cb_data data = { NULL };
c9ffa84b 358 bool optional_setting_found = false, found;
4330ab26 359
9462c471
VM
360 assert(out && repo && name);
361
032ba9e4 362 if ((error = ensure_remote_name_is_valid(name)) < 0)
363 return error;
364
ac99d86b 365 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
29c4cb09 366 return error;
4bef3565 367
9c82357b 368 remote = git__malloc(sizeof(git_remote));
4376f7f6 369 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
370
371 memset(remote, 0x0, sizeof(git_remote));
b0f6e45d 372 remote->update_fetchhead = 1;
9c82357b 373 remote->name = git__strdup(name);
4376f7f6 374 GITERR_CHECK_ALLOC(remote->name);
9c82357b 375
25e0b157
RB
376 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
377 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
378 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
2fb9d6de 379 error = -1;
380 goto cleanup;
381 }
d88d4311 382
25e0b157 383 if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
2fb9d6de 384 goto cleanup;
9c82357b 385
c9ffa84b 386 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
9c82357b 387 goto cleanup;
bf6bebe2 388
c9ffa84b 389 optional_setting_found |= found;
390
9462c471 391 remote->repo = repo;
c9ffa84b 392
393 if (found && strlen(val) > 0) {
394 remote->url = git__strdup(val);
395 GITERR_CHECK_ALLOC(remote->url);
396 }
9c82357b 397
bf6bebe2 398 val = NULL;
3ed4b501 399 git_buf_clear(&buf);
bf6bebe2 400 git_buf_printf(&buf, "remote.%s.pushurl", name);
3ed4b501 401
c9ffa84b 402 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
3ed4b501 403 goto cleanup;
3ed4b501 404
c9ffa84b 405 optional_setting_found |= found;
406
407 if (!optional_setting_found) {
408 error = GIT_ENOTFOUND;
d723dbed 409 giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name);
3ed4b501 410 goto cleanup;
c9ffa84b 411 }
3ed4b501 412
c9ffa84b 413 if (found && strlen(val) > 0) {
3ed4b501
SC
414 remote->pushurl = git__strdup(val);
415 GITERR_CHECK_ALLOC(remote->pushurl);
416 }
417
4330ab26
CMN
418 data.remote = remote;
419 data.fetch = true;
96869a4e 420
f0f3a18a 421 git_buf_clear(&buf);
bf6bebe2
RB
422 git_buf_printf(&buf, "remote.%s.fetch", name);
423
c9ffa84b 424 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
2fb9d6de 425 goto cleanup;
9c82357b 426
4330ab26 427 data.fetch = false;
bf6bebe2
RB
428 git_buf_clear(&buf);
429 git_buf_printf(&buf, "remote.%s.push", name);
9c82357b 430
c9ffa84b 431 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
9c82357b
CMN
432 goto cleanup;
433
24f2f94e
CMN
434 if (download_tags_value(remote, config) < 0)
435 goto cleanup;
436
af613ecd
CMN
437 /* Move the data over to where the matching functions can find them */
438 if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
439 goto cleanup;
440
9c82357b
CMN
441 *out = remote;
442
443cleanup:
29c4cb09 444 git_config_free(config);
f0f3a18a 445 git_buf_free(&buf);
9462c471 446
4376f7f6 447 if (error < 0)
9c82357b
CMN
448 git_remote_free(remote);
449
450 return error;
451}
452
4330ab26 453static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
4fe5520a 454{
4330ab26 455 git_buf name = GIT_BUF_INIT;
66566516 456 unsigned int push;
4330ab26
CMN
457 const char *dir;
458 size_t i;
bf6bebe2 459 int error = 0;
3793fa9b 460 const char *cname;
4fe5520a 461
4330ab26
CMN
462 push = direction == GIT_DIRECTION_PUSH;
463 dir = push ? "push" : "fetch";
4fe5520a 464
4330ab26
CMN
465 if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
466 return -1;
3793fa9b 467 cname = git_buf_cstr(&name);
4fe5520a 468
4330ab26 469 /* Clear out the existing config */
bf6bebe2 470 while (!error)
3793fa9b 471 error = git_config_delete_multivar(config, cname, ".*");
4fe5520a 472
4330ab26
CMN
473 if (error != GIT_ENOTFOUND)
474 return error;
475
1be680c4 476 for (i = 0; i < remote->refspecs.length; i++) {
4330ab26 477 git_refspec *spec = git_vector_get(&remote->refspecs, i);
4330ab26
CMN
478
479 if (spec->push != push)
480 continue;
481
376454d0
DRT
482 // "$^" is a unmatcheable regexp: it will not match anything at all, so
483 // all values will be considered new and we will not replace any
484 // present value.
bf6bebe2 485 if ((error = git_config_set_multivar(
376454d0 486 config, cname, "$^", spec->string)) < 0) {
4330ab26
CMN
487 goto cleanup;
488 }
489 }
490
491 giterr_clear();
492 error = 0;
4fe5520a 493
494cleanup:
495 git_buf_free(&name);
4fe5520a 496
497 return error;
498}
499
89e5ed98
CMN
500int git_remote_save(const git_remote *remote)
501{
218c88a9 502 int error;
8286300a 503 git_config *cfg;
218c88a9 504 const char *tagopt = NULL;
4fe5520a 505 git_buf buf = GIT_BUF_INIT;
8286300a 506 const git_config_entry *existing;
89e5ed98 507
e497b16c 508 assert(remote);
509
c07b52df 510 if (!remote->name) {
fd536d29 511 giterr_set(GITERR_INVALID, "Can't save an anonymous remote.");
874dcb25 512 return GIT_EINVALIDSPEC;
a71c27cc
BS
513 }
514
032ba9e4 515 if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
516 return error;
89e5ed98 517
8286300a
RB
518 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
519 return error;
89e5ed98 520
8286300a
RB
521 if ((error = git_buf_printf(&buf, "remote.%s.url", remote->name)) < 0)
522 return error;
89e5ed98 523
8286300a
RB
524 /* after this point, buffer is allocated so end with cleanup */
525
526 if ((error = git_config_set_string(
527 cfg, git_buf_cstr(&buf), remote->url)) < 0)
528 goto cleanup;
89e5ed98 529
413d5563 530 git_buf_clear(&buf);
8286300a
RB
531 if ((error = git_buf_printf(&buf, "remote.%s.pushurl", remote->name)) < 0)
532 goto cleanup;
3ed4b501 533
8286300a
RB
534 if ((error = git_config__update_entry(
535 cfg, git_buf_cstr(&buf), remote->pushurl, true, false)) < 0)
536 goto cleanup;
3ed4b501 537
8286300a
RB
538 if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
539 goto cleanup;
89e5ed98 540
8286300a
RB
541 if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
542 goto cleanup;
89e5ed98 543
218c88a9
CMN
544 /*
545 * What action to take depends on the old and new values. This
546 * is describes by the table below. tagopt means whether the
547 * is already a value set in the config
548 *
549 * AUTO ALL or NONE
550 * +-----------------------+
551 * tagopt | remove | set |
552 * +---------+-------------|
553 * !tagopt | nothing | set |
554 * +---------+-------------+
555 */
556
557 git_buf_clear(&buf);
8286300a
RB
558 if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
559 goto cleanup;
218c88a9 560
8286300a
RB
561 if ((error = git_config__lookup_entry(
562 &existing, cfg, git_buf_cstr(&buf), false)) < 0)
563 goto cleanup;
218c88a9 564
8286300a
RB
565 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL)
566 tagopt = "--tags";
567 else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE)
568 tagopt = "--no-tags";
569 else if (existing != NULL)
570 tagopt = NULL;
4376f7f6 571
8286300a
RB
572 error = git_config__update_entry(
573 cfg, git_buf_cstr(&buf), tagopt, true, false);
4376f7f6 574
8286300a 575cleanup:
4376f7f6 576 git_buf_free(&buf);
8286300a 577 return error;
89e5ed98
CMN
578}
579
df705148 580const char *git_remote_name(const git_remote *remote)
9c82357b 581{
4bef3565 582 assert(remote);
9c82357b
CMN
583 return remote->name;
584}
585
85e1eded
ES
586git_repository *git_remote_owner(const git_remote *remote)
587{
588 assert(remote);
589 return remote->repo;
590}
591
df705148 592const char *git_remote_url(const git_remote *remote)
9c82357b 593{
4bef3565 594 assert(remote);
9c82357b
CMN
595 return remote->url;
596}
597
76501590
SC
598int git_remote_set_url(git_remote *remote, const char* url)
599{
600 assert(remote);
601 assert(url);
602
603 git__free(remote->url);
604 remote->url = git__strdup(url);
605 GITERR_CHECK_ALLOC(remote->url);
606
607 return 0;
608}
609
df705148 610const char *git_remote_pushurl(const git_remote *remote)
76501590
SC
611{
612 assert(remote);
613 return remote->pushurl;
614}
615
616int git_remote_set_pushurl(git_remote *remote, const char* url)
617{
618 assert(remote);
619
620 git__free(remote->pushurl);
621 if (url) {
622 remote->pushurl = git__strdup(url);
623 GITERR_CHECK_ALLOC(remote->pushurl);
624 } else {
625 remote->pushurl = NULL;
626 }
627 return 0;
628}
629
eff5b499
SC
630const char* git_remote__urlfordirection(git_remote *remote, int direction)
631{
632 assert(remote);
633
b83c92dd 634 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
635
df705148 636 if (direction == GIT_DIRECTION_FETCH) {
eff5b499
SC
637 return remote->url;
638 }
639
df705148 640 if (direction == GIT_DIRECTION_PUSH) {
eff5b499
SC
641 return remote->pushurl ? remote->pushurl : remote->url;
642 }
643
644 return NULL;
645}
646
df705148 647int git_remote_connect(git_remote *remote, git_direction direction)
9ba49bb5 648{
9ba49bb5 649 git_transport *t;
c0c39025 650 const char *url;
41fb1ca0 651 int flags = GIT_TRANSPORTFLAGS_NONE;
80fc7d6b 652 int error;
9ba49bb5 653
4bef3565
VM
654 assert(remote);
655
41fb1ca0
PK
656 t = remote->transport;
657
c0c39025 658 url = git_remote__urlfordirection(remote, direction);
80fc7d6b 659 if (url == NULL) {
44bc0c6a 660 giterr_set(GITERR_INVALID,
661 "Malformed remote '%s' - missing URL", remote->name);
eff5b499 662 return -1;
44bc0c6a 663 }
eff5b499 664
1697cd6f
PK
665 /* If we don't have a transport object yet, and the caller specified a
666 * custom transport factory, use that */
667 if (!t && remote->transport_cb &&
668 (error = remote->transport_cb(&t, remote, remote->transport_cb_payload)) < 0)
669 return error;
670
671 /* If we still don't have a transport, then use the global
672 * transport registrations which map URI schemes to transport factories */
80fc7d6b
ET
673 if (!t && (error = git_transport_new(&t, remote, url)) < 0)
674 return error;
9ba49bb5 675
41fb1ca0 676 if (t->set_callbacks &&
9b940586 677 (error = t->set_callbacks(t, remote->callbacks.sideband_progress, NULL, remote->callbacks.certificate_check, remote->callbacks.payload)) < 0)
41fb1ca0 678 goto on_error;
613d5eb9 679
25e0b157 680 if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) != 0)
4376f7f6 681 goto on_error;
9ba49bb5
CMN
682
683 remote->transport = t;
684
4376f7f6 685 return 0;
9ba49bb5 686
4376f7f6
CMN
687on_error:
688 t->free(t);
613d5eb9
PK
689
690 if (t == remote->transport)
691 remote->transport = NULL;
692
80fc7d6b 693 return error;
9ba49bb5
CMN
694}
695
359dce72 696int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
9ba49bb5 697{
d88d4311
VM
698 assert(remote);
699
dc8adda4
JG
700 if (!remote->transport) {
701 giterr_set(GITERR_NET, "No transport bound to this remote");
702 return -1;
703 }
704
359dce72 705 return remote->transport->ls(out, size, remote->transport);
9ba49bb5
CMN
706}
707
613d5eb9
PK
708int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
709{
710 git_config *cfg;
9f77b3f6
RB
711 const git_config_entry *ce;
712 const char *val = NULL;
80fc7d6b 713 int error;
613d5eb9
PK
714
715 assert(remote);
716
a71c27cc 717 if (!proxy_url || !remote->repo)
613d5eb9
PK
718 return -1;
719
720 *proxy_url = NULL;
721
80fc7d6b
ET
722 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
723 return error;
613d5eb9
PK
724
725 /* Go through the possible sources for proxy configuration, from most specific
726 * to least specific. */
727
728 /* remote.<name>.proxy config setting */
9f77b3f6 729 if (remote->name && remote->name[0]) {
613d5eb9
PK
730 git_buf buf = GIT_BUF_INIT;
731
80fc7d6b
ET
732 if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
733 return error;
613d5eb9 734
9f77b3f6
RB
735 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
736 git_buf_free(&buf);
613d5eb9 737
9f77b3f6 738 if (error < 0)
80fc7d6b 739 return error;
613d5eb9 740
9f77b3f6
RB
741 if (ce && ce->value) {
742 val = ce->value;
743 goto found;
744 }
613d5eb9
PK
745 }
746
747 /* http.proxy config setting */
9f77b3f6 748 if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
80fc7d6b 749 return error;
9f77b3f6
RB
750 if (ce && ce->value) {
751 val = ce->value;
752 goto found;
753 }
613d5eb9
PK
754
755 /* HTTP_PROXY / HTTPS_PROXY environment variables */
756 val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
757
9f77b3f6
RB
758found:
759 if (val && val[0]) {
613d5eb9
PK
760 *proxy_url = git__strdup(val);
761 GITERR_CHECK_ALLOC(*proxy_url);
613d5eb9
PK
762 }
763
764 return 0;
765}
766
af613ecd
CMN
767/* DWIM `refspecs` based on `refs` and append the output to `out` */
768static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
d8488457 769{
af613ecd 770 size_t i;
d8488457 771 git_refspec *spec;
d8488457
CMN
772
773 git_vector_foreach(refspecs, i, spec) {
af613ecd
CMN
774 if (git_refspec__dwim_one(out, spec, refs) < 0)
775 return -1;
776 }
d8488457 777
af613ecd
CMN
778 return 0;
779}
d8488457 780
af613ecd
CMN
781static void free_refspecs(git_vector *vec)
782{
783 size_t i;
784 git_refspec *spec;
d8488457 785
af613ecd
CMN
786 git_vector_foreach(vec, i, spec) {
787 git_refspec__free(spec);
788 git__free(spec);
d8488457
CMN
789 }
790
af613ecd 791 git_vector_clear(vec);
d8488457
CMN
792}
793
794static int remote_head_cmp(const void *_a, const void *_b)
795{
796 const git_remote_head *a = (git_remote_head *) _a;
797 const git_remote_head *b = (git_remote_head *) _b;
798
799 return git__strcmp_cb(a->name, b->name);
800}
801
877cde76
CMN
802static int ls_to_vector(git_vector *out, git_remote *remote)
803{
804 git_remote_head **heads;
805 size_t heads_len, i;
806
807 if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
808 return -1;
809
810 if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
811 return -1;
812
813 for (i = 0; i < heads_len; i++) {
814 if (git_vector_insert(out, heads[i]) < 0)
815 return -1;
816 }
817
818 return 0;
819}
820
3f894205 821int git_remote_download(git_remote *remote, const git_strarray *refspecs)
48a65a07 822{
95057b85 823 int error;
3f894205
CMN
824 size_t i;
825 git_vector refs, specs, *to_active;
95057b85 826
1e3b8ed5 827 assert(remote);
4bef3565 828
877cde76 829 if (ls_to_vector(&refs, remote) < 0)
d8488457 830 return -1;
d8488457 831
3f894205
CMN
832 if ((git_vector_init(&specs, 0, NULL)) < 0)
833 goto on_error;
834
835 if (!refspecs) {
836 to_active = &remote->refspecs;
837 } else {
838 for (i = 0; i < refspecs->count; i++) {
839 if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
840 goto on_error;
841 }
842
843 to_active = &specs;
844 }
845
af613ecd
CMN
846 free_refspecs(&remote->active_refspecs);
847
3f894205 848 error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
877cde76 849 git_vector_free(&refs);
3f894205
CMN
850 free_refspecs(&specs);
851 git_vector_free(&specs);
877cde76
CMN
852
853 if (error < 0)
25e0b157 854 return error;
d8488457 855
95057b85 856 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 857 return error;
95057b85 858
d31402a3 859 return git_fetch_download_pack(remote);
3f894205
CMN
860
861on_error:
862 git_vector_free(&refs);
863 free_refspecs(&specs);
864 git_vector_free(&specs);
865 return error;
48a65a07
CMN
866}
867
c3ab1e5a
BS
868int git_remote_fetch(
869 git_remote *remote,
3f894205 870 const git_strarray *refspecs,
c3ab1e5a
BS
871 const git_signature *signature,
872 const char *reflog_message)
fe3a40a4
CMN
873{
874 int error;
db55bb73 875 git_buf reflog_msg_buf = GIT_BUF_INIT;
fe3a40a4
CMN
876
877 /* Connect and download everything */
25e0b157 878 if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) != 0)
fe3a40a4
CMN
879 return error;
880
3f894205 881 error = git_remote_download(remote, refspecs);
fe3a40a4
CMN
882
883 /* We don't need to be connected anymore */
884 git_remote_disconnect(remote);
885
06a8f5c3
BL
886 /* If the download failed, return the error */
887 if (error != 0)
888 return error;
889
db55bb73
BS
890 /* Default reflog message */
891 if (reflog_message)
892 git_buf_sets(&reflog_msg_buf, reflog_message);
893 else {
894 git_buf_printf(&reflog_msg_buf, "fetch %s",
895 remote->name ? remote->name : remote->url);
896 }
897
fe3a40a4 898 /* Create "remote/foo" branches for all remote branches */
db55bb73
BS
899 error = git_remote_update_tips(remote, signature, git_buf_cstr(&reflog_msg_buf));
900 git_buf_free(&reflog_msg_buf);
901 return error;
fe3a40a4
CMN
902}
903
b0f6e45d
ET
904static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
905{
906 unsigned int i;
907 git_remote_head *remote_ref;
908
909 assert(update_heads && fetchspec_src);
910
911 *out = NULL;
7d4b65f6 912
913 git_vector_foreach(update_heads, i, remote_ref) {
914 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
915 *out = remote_ref;
916 break;
b0f6e45d
ET
917 }
918 }
919
920 return 0;
921}
922
4330ab26 923static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
924{
925 git_reference *resolved_ref = NULL;
b0f6e45d 926 git_buf remote_name = GIT_BUF_INIT;
67d4997a
CMN
927 git_buf upstream_name = GIT_BUF_INIT;
928 git_repository *repo;
929 const char *ref_name;
b0f6e45d
ET
930 int error = 0;
931
4330ab26 932 assert(out && spec && ref);
b0f6e45d
ET
933
934 *out = NULL;
935
67d4997a
CMN
936 repo = git_reference_owner(ref);
937
938 error = git_reference_resolve(&resolved_ref, ref);
939
940 /* If we're in an unborn branch, let's pretend nothing happened */
941 if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REF_SYMBOLIC) {
942 ref_name = git_reference_symbolic_target(ref);
943 error = 0;
944 } else {
945 ref_name = git_reference_name(resolved_ref);
946 }
947
948 if ((!git_reference__is_branch(ref_name)) ||
949 (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
950 (error = git_refspec_rtransform(&remote_name, spec, upstream_name.ptr)) < 0) {
951 /* Not an error if there is no upstream */
b0f6e45d
ET
952 if (error == GIT_ENOTFOUND)
953 error = 0;
954
955 goto cleanup;
956 }
957
958 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
959
960cleanup:
b0f6e45d
ET
961 git_reference_free(resolved_ref);
962 git_buf_free(&remote_name);
67d4997a 963 git_buf_free(&upstream_name);
b0f6e45d
ET
964 return error;
965}
966
4330ab26 967static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 968{
b0f6e45d
ET
969 git_reference *head_ref = NULL;
970 git_fetchhead_ref *fetchhead_ref;
971 git_remote_head *remote_ref, *merge_remote_ref;
972 git_vector fetchhead_refs;
973 bool include_all_fetchheads;
974 unsigned int i = 0;
975 int error = 0;
976
977 assert(remote);
978
404eadb0
CMN
979 /* no heads, nothing to do */
980 if (update_heads->length == 0)
981 return 0;
982
b0f6e45d
ET
983 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
984 return -1;
985
986 /* Iff refspec is * (but not subdir slash star), include tags */
987 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
988
989 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
990 if (git_refspec_is_wildcard(spec)) {
991 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
4330ab26 992 (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
993 goto cleanup;
994 } else {
995 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
996 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
997 goto cleanup;
998 }
999
1000 /* Create the FETCH_HEAD file */
7d4b65f6 1001 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
1002 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
1003
1004 if (!include_all_fetchheads &&
1005 !git_refspec_src_matches(spec, remote_ref->name) &&
1006 !merge_this_fetchhead)
1007 continue;
1008
1009 if (git_fetchhead_ref_create(&fetchhead_ref,
1010 &remote_ref->oid,
1011 merge_this_fetchhead,
1012 remote_ref->name,
1013 git_remote_url(remote)) < 0)
1014 goto cleanup;
1015
1016 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
1017 goto cleanup;
1018 }
1019
1020 git_fetchhead_write(remote->repo, &fetchhead_refs);
1021
1022cleanup:
1023 for (i = 0; i < fetchhead_refs.length; ++i)
1024 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
1025
1026 git_vector_free(&fetchhead_refs);
1027 git_reference_free(head_ref);
1028
1029 return error;
1030}
1031
c3ab1e5a
BS
1032static int update_tips_for_spec(
1033 git_remote *remote,
1034 git_refspec *spec,
1035 git_vector *refs,
1036 const git_signature *signature,
1037 const char *log_message)
441f57c2 1038{
a37ddf7e 1039 int error = 0, autotag;
517bda19 1040 unsigned int i = 0;
97769280 1041 git_buf refname = GIT_BUF_INIT;
f184836b 1042 git_oid old;
a37ddf7e 1043 git_odb *odb;
441f57c2
CMN
1044 git_remote_head *head;
1045 git_reference *ref;
a37ddf7e 1046 git_refspec tagspec;
4330ab26 1047 git_vector update_heads;
441f57c2 1048
4bef3565
VM
1049 assert(remote);
1050
acd17006 1051 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
1052 return -1;
1053
3230a44f 1054 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
1055 return -1;
1056
41fb1ca0 1057 /* Make a copy of the transport's refs */
4330ab26 1058 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 1059 return -1;
585a2eb7 1060
4330ab26
CMN
1061 for (; i < refs->length; ++i) {
1062 head = git_vector_get(refs, i);
9063be1f 1063 autotag = 0;
517bda19 1064
a37ddf7e
CMN
1065 /* Ignore malformed ref names (which also saves us from tag^{} */
1066 if (!git_reference_is_valid_name(head->name))
1067 continue;
1068
d8488457 1069 if (git_refspec_src_matches(spec, head->name) && spec->dst) {
bf522e08 1070 if (git_refspec_transform(&refname, spec, head->name) < 0)
a37ddf7e
CMN
1071 goto on_error;
1072 } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f
CMN
1073
1074 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL)
1075 autotag = 1;
a37ddf7e
CMN
1076
1077 if (!git_refspec_src_matches(&tagspec, head->name))
1078 continue;
1079
1080 git_buf_clear(&refname);
1081 if (git_buf_puts(&refname, head->name) < 0)
1082 goto on_error;
1083 } else {
1084 continue;
1085 }
1086
1087 if (autotag && !git_odb_exists(odb, &head->oid))
1088 continue;
f184836b 1089
d908351a 1090 if (!autotag && git_vector_insert(&update_heads, head) < 0)
b0f6e45d
ET
1091 goto on_error;
1092
2508cc66 1093 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 1094 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
1095 goto on_error;
1096
d908351a 1097 if (error == GIT_ENOTFOUND) {
f184836b
CMN
1098 memset(&old, 0, GIT_OID_RAWSZ);
1099
d908351a
L
1100 if (autotag && git_vector_insert(&update_heads, head) < 0)
1101 goto on_error;
1102 }
1103
b7f167da 1104 if (!git_oid__cmp(&old, &head->oid))
f184836b 1105 continue;
441f57c2 1106
a37ddf7e 1107 /* In autotag mode, don't overwrite any locally-existing tags */
c3ab1e5a
BS
1108 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
1109 signature, log_message);
a37ddf7e 1110 if (error < 0 && error != GIT_EEXISTS)
944d250f 1111 goto on_error;
39157563
CMN
1112
1113 git_reference_free(ref);
f184836b 1114
b3aaa7a7 1115 if (remote->callbacks.update_tips != NULL) {
df705148 1116 if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.payload) < 0)
f184836b
CMN
1117 goto on_error;
1118 }
441f57c2
CMN
1119 }
1120
b0f6e45d 1121 if (git_remote_update_fetchhead(remote) &&
4330ab26 1122 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
1123 goto on_error;
1124
b0f6e45d 1125 git_vector_free(&update_heads);
a37ddf7e 1126 git_refspec__free(&tagspec);
97769280 1127 git_buf_free(&refname);
f184836b
CMN
1128 return 0;
1129
1130on_error:
b0f6e45d 1131 git_vector_free(&update_heads);
a37ddf7e 1132 git_refspec__free(&tagspec);
f184836b
CMN
1133 git_buf_free(&refname);
1134 return -1;
97769280 1135
441f57c2
CMN
1136}
1137
c3ab1e5a
BS
1138int git_remote_update_tips(
1139 git_remote *remote,
1140 const git_signature *signature,
1141 const char *reflog_message)
4330ab26 1142{
505b5d0c 1143 git_refspec *spec, tagspec;
4330ab26 1144 git_vector refs;
505b5d0c 1145 int error;
4330ab26
CMN
1146 size_t i;
1147
505b5d0c
CMN
1148 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1149 return -1;
1150
877cde76
CMN
1151
1152 if ((error = ls_to_vector(&refs, remote)) < 0)
505b5d0c
CMN
1153 goto out;
1154
1155 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
c3ab1e5a 1156 error = update_tips_for_spec(remote, &tagspec, &refs, signature, reflog_message);
505b5d0c
CMN
1157 goto out;
1158 }
4330ab26 1159
af613ecd 1160 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1161 if (spec->push)
1162 continue;
1163
c3ab1e5a 1164 if ((error = update_tips_for_spec(remote, spec, &refs, signature, reflog_message)) < 0)
505b5d0c 1165 goto out;
4330ab26
CMN
1166 }
1167
505b5d0c 1168out:
877cde76 1169 git_vector_free(&refs);
505b5d0c 1170 git_refspec__free(&tagspec);
505b5d0c 1171 return error;
4330ab26
CMN
1172}
1173
11f6ad5f 1174int git_remote_connected(const git_remote *remote)
6ac3b707 1175{
4bef3565 1176 assert(remote);
41fb1ca0
PK
1177
1178 if (!remote->transport || !remote->transport->is_connected)
1179 return 0;
1180
1181 /* Ask the transport if it's connected. */
613d5eb9 1182 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
1183}
1184
f0d2ddbb
CMN
1185void git_remote_stop(git_remote *remote)
1186{
613d5eb9
PK
1187 assert(remote);
1188
1189 if (remote->transport && remote->transport->cancel)
41fb1ca0 1190 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
1191}
1192
4cf01e9a
CMN
1193void git_remote_disconnect(git_remote *remote)
1194{
4bef3565
VM
1195 assert(remote);
1196
41fb1ca0
PK
1197 if (git_remote_connected(remote))
1198 remote->transport->close(remote->transport);
4cf01e9a
CMN
1199}
1200
9c82357b
CMN
1201void git_remote_free(git_remote *remote)
1202{
2aae2188
CMN
1203 if (remote == NULL)
1204 return;
1205
42ea35c0
MS
1206 if (remote->transport != NULL) {
1207 git_remote_disconnect(remote);
1208
1209 remote->transport->free(remote->transport);
1210 remote->transport = NULL;
1211 }
1212
1213 git_vector_free(&remote->refs);
1214
af613ecd 1215 free_refspecs(&remote->refspecs);
4330ab26
CMN
1216 git_vector_free(&remote->refspecs);
1217
af613ecd
CMN
1218 free_refspecs(&remote->active_refspecs);
1219 git_vector_free(&remote->active_refspecs);
1220
3286c408 1221 git__free(remote->url);
3ed4b501 1222 git__free(remote->pushurl);
3286c408 1223 git__free(remote->name);
3286c408 1224 git__free(remote);
9c82357b 1225}
8171998f 1226
106c12f1 1227static int remote_list_cb(const git_config_entry *entry, void *payload)
8171998f 1228{
25e0b157 1229 git_vector *list = payload;
106c12f1
RB
1230 const char *name = entry->name + strlen("remote.");
1231 size_t namelen = strlen(name);
1232 char *remote_name;
8171998f 1233
106c12f1 1234 /* we know name matches "remote.<stuff>.(push)?url" */
8171998f 1235
106c12f1
RB
1236 if (!strcmp(&name[namelen - 4], ".url"))
1237 remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1238 else
1239 remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
25e0b157 1240 GITERR_CHECK_ALLOC(remote_name);
8171998f 1241
25e0b157 1242 return git_vector_insert(list, remote_name);
8171998f
CMN
1243}
1244
1245int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1246{
8171998f 1247 int error;
96869a4e 1248 git_config *cfg;
25e0b157 1249 git_vector list = GIT_VECTOR_INIT;
8171998f 1250
96869a4e
RB
1251 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1252 return error;
8171998f 1253
25e0b157 1254 if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
96869a4e 1255 return error;
8171998f 1256
106c12f1 1257 error = git_config_foreach_match(
25e0b157 1258 cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
8171998f 1259
4376f7f6 1260 if (error < 0) {
9cfce273 1261 git_vector_free_deep(&list);
8171998f
CMN
1262 return error;
1263 }
1264
25e0b157 1265 git_vector_uniq(&list, git__free);
aec87f71 1266
25e0b157
RB
1267 remotes_list->strings =
1268 (char **)git_vector_detach(&remotes_list->count, NULL, &list);
8171998f 1269
4376f7f6 1270 return 0;
8171998f 1271}
a209a025 1272
0e0cf787 1273int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks)
b3aaa7a7
CMN
1274{
1275 assert(remote && callbacks);
1276
c7231c45 1277 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
9267ff58 1278
b3aaa7a7 1279 memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
e03e71da 1280
41fb1ca0 1281 if (remote->transport && remote->transport->set_callbacks)
0e0cf787 1282 return remote->transport->set_callbacks(remote->transport,
98020d3a 1283 remote->callbacks.sideband_progress,
41fb1ca0 1284 NULL,
9b940586 1285 remote->callbacks.certificate_check,
df705148 1286 remote->callbacks.payload);
9267ff58
BS
1287
1288 return 0;
41fb1ca0
PK
1289}
1290
2efd7df6
CMN
1291const git_remote_callbacks *git_remote_get_callbacks(git_remote *remote)
1292{
1293 assert(remote);
1294
1295 return &remote->callbacks;
1296}
1297
1697cd6f
PK
1298int git_remote_set_transport(
1299 git_remote *remote,
1300 git_transport_cb transport_cb,
1301 void *payload)
41fb1ca0 1302{
1697cd6f 1303 assert(remote);
10711769 1304
e03e71da 1305 if (remote->transport) {
41fb1ca0
PK
1306 giterr_set(GITERR_NET, "A transport is already bound to this remote");
1307 return -1;
e03e71da 1308 }
41fb1ca0 1309
1697cd6f
PK
1310 remote->transport_cb = transport_cb;
1311 remote->transport_cb_payload = payload;
41fb1ca0 1312 return 0;
b3aaa7a7 1313}
f70e466f 1314
67dad09b 1315const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1316{
1317 assert(remote);
1318 return &remote->stats;
1319}
1320
11f6ad5f 1321git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
f70e466f
CMN
1322{
1323 return remote->download_tags;
1324}
1325
f4a62c30 1326void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value)
f70e466f
CMN
1327{
1328 remote->download_tags = value;
1329}
fcccf304 1330
fcccf304 1331static int rename_remote_config_section(
1332 git_repository *repo,
1333 const char *old_name,
1334 const char *new_name)
1335{
1336 git_buf old_section_name = GIT_BUF_INIT,
1337 new_section_name = GIT_BUF_INIT;
1338 int error = -1;
1339
1340 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1341 goto cleanup;
1342
40e48ea4 1343 if (new_name &&
1344 (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1345 goto cleanup;
fcccf304 1346
1347 error = git_config_rename_section(
1348 repo,
1349 git_buf_cstr(&old_section_name),
40e48ea4 1350 new_name ? git_buf_cstr(&new_section_name) : NULL);
fcccf304 1351
1352cleanup:
1353 git_buf_free(&old_section_name);
1354 git_buf_free(&new_section_name);
1355
1356 return error;
1357}
1358
96869a4e 1359struct update_data {
fcccf304 1360 git_config *config;
1361 const char *old_remote_name;
1362 const char *new_remote_name;
1363};
1364
1365static int update_config_entries_cb(
1366 const git_config_entry *entry,
1367 void *payload)
1368{
1369 struct update_data *data = (struct update_data *)payload;
1370
1371 if (strcmp(entry->value, data->old_remote_name))
1372 return 0;
1373
25e0b157
RB
1374 return git_config_set_string(
1375 data->config, entry->name, data->new_remote_name);
fcccf304 1376}
1377
1378static int update_branch_remote_config_entry(
1379 git_repository *repo,
1380 const char *old_name,
1381 const char *new_name)
1382{
96869a4e
RB
1383 int error;
1384 struct update_data data = { NULL };
fcccf304 1385
96869a4e
RB
1386 if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1387 return error;
fcccf304 1388
fcccf304 1389 data.old_remote_name = old_name;
1390 data.new_remote_name = new_name;
1391
25e0b157 1392 return git_config_foreach_match(
96869a4e 1393 data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
fcccf304 1394}
1395
fcccf304 1396static int rename_one_remote_reference(
d1544564 1397 git_reference *reference_in,
fcccf304 1398 const char *old_remote_name,
1399 const char *new_remote_name)
1400{
96869a4e 1401 int error;
d1544564
CMN
1402 git_reference *ref = NULL, *dummy = NULL;
1403 git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
fcccf304 1404 git_buf new_name = GIT_BUF_INIT;
ccf6ce5c 1405 git_buf log_message = GIT_BUF_INIT;
d1544564
CMN
1406 size_t pfx_len;
1407 const char *target;
fcccf304 1408
d1544564
CMN
1409 if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1410 return error;
1411
1412 pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1413 git_buf_puts(&new_name, namespace.ptr);
1414 if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
ccf6ce5c 1415 goto cleanup;
fcccf304 1416
ccf6ce5c
BS
1417 if ((error = git_buf_printf(&log_message,
1418 "renamed remote %s to %s",
1419 old_remote_name, new_remote_name)) < 0)
1420 goto cleanup;
fcccf304 1421
d1544564
CMN
1422 if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1423 NULL, git_buf_cstr(&log_message))) < 0)
1424 goto cleanup;
1425
1426 if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1427 goto cleanup;
1428
1429 /* Handle refs like origin/HEAD -> origin/master */
1430 target = git_reference_symbolic_target(ref);
1431 if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1432 goto cleanup;
1433
1434 if (git__prefixcmp(target, old_namespace.ptr))
1435 goto cleanup;
1436
1437 git_buf_clear(&new_name);
1438 git_buf_puts(&new_name, namespace.ptr);
1439 if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1440 goto cleanup;
1441
1442 error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
1443 NULL, git_buf_cstr(&log_message));
1444
1445 git_reference_free(dummy);
ccf6ce5c
BS
1446
1447cleanup:
d1544564
CMN
1448 git_reference_free(reference_in);
1449 git_reference_free(ref);
1450 git_buf_free(&namespace);
1451 git_buf_free(&old_namespace);
fcccf304 1452 git_buf_free(&new_name);
ccf6ce5c 1453 git_buf_free(&log_message);
fcccf304 1454 return error;
1455}
1456
1457static int rename_remote_references(
1458 git_repository *repo,
1459 const char *old_name,
1460 const char *new_name)
1461{
96869a4e 1462 int error;
a52ab4b8 1463 git_buf buf = GIT_BUF_INIT;
56960b83 1464 git_reference *ref;
9bd89d96 1465 git_reference_iterator *iter;
fcccf304 1466
a52ab4b8 1467 if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
96869a4e 1468 return error;
fcccf304 1469
a52ab4b8
CMN
1470 error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1471 git_buf_free(&buf);
9bd89d96 1472
a52ab4b8
CMN
1473 if (error < 0)
1474 return error;
1475
1476 while ((error = git_reference_next(&ref, iter)) == 0) {
96869a4e
RB
1477 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1478 break;
9bd89d96
CMN
1479 }
1480
1481 git_reference_iterator_free(iter);
fcccf304 1482
96869a4e 1483 return (error == GIT_ITEROVER) ? 0 : error;
fcccf304 1484}
1485
72bca13e 1486static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
fcccf304 1487{
1488 git_config *config;
4330ab26 1489 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1490 const git_refspec *spec;
4330ab26 1491 size_t i;
25e0b157 1492 int error = 0;
fcccf304 1493
dab89f9b 1494 if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
25e0b157
RB
1495 return error;
1496
72bca13e
CMN
1497 if ((error = git_vector_init(problems, 1, NULL)) < 0)
1498 return error;
1499
25e0b157
RB
1500 if ((error = git_buf_printf(
1501 &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
1502 return error;
dab89f9b 1503
1be680c4 1504 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1505 if (spec->push)
1506 continue;
fcccf304 1507
dab89f9b 1508 /* Does the dst part of the refspec follow the expected format? */
5a49ff9f 1509 if (strcmp(git_buf_cstr(&base), spec->string)) {
72bca13e 1510 char *dup;
fcccf304 1511
72bca13e
CMN
1512 dup = git__strdup(spec->string);
1513 GITERR_CHECK_ALLOC(dup);
1514
1515 if ((error = git_vector_insert(problems, dup)) < 0)
25e0b157 1516 break;
c7b3e1b3 1517
4330ab26
CMN
1518 continue;
1519 }
fcccf304 1520
4330ab26 1521 /* If we do want to move it to the new section */
fcccf304 1522
dab89f9b
RB
1523 git_buf_clear(&val);
1524 git_buf_clear(&var);
fcccf304 1525
dab89f9b
RB
1526 if (git_buf_printf(
1527 &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
1528 git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1529 {
1530 error = -1;
25e0b157 1531 break;
dab89f9b 1532 }
fcccf304 1533
dab89f9b
RB
1534 if ((error = git_config_set_string(
1535 config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
25e0b157 1536 break;
4330ab26 1537 }
fcccf304 1538
4330ab26
CMN
1539 git_buf_free(&base);
1540 git_buf_free(&var);
1541 git_buf_free(&val);
72bca13e
CMN
1542
1543 if (error < 0) {
1544 char *str;
1545 git_vector_foreach(problems, i, str)
1546 git__free(str);
1547
1548 git_vector_free(problems);
1549 }
1550
fcccf304 1551 return error;
1552}
1553
72bca13e 1554int git_remote_rename(git_strarray *out, git_remote *remote, const char *new_name)
fcccf304 1555{
1556 int error;
72bca13e 1557 git_vector problem_refspecs;
61dcfe14 1558 char *tmp, *dup;
fcccf304 1559
72bca13e 1560 assert(out && remote && new_name);
fcccf304 1561
c07b52df 1562 if (!remote->name) {
fd536d29 1563 giterr_set(GITERR_INVALID, "Can't rename an anonymous remote.");
79000951
BS
1564 return GIT_EINVALIDSPEC;
1565 }
1566
fcccf304 1567 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
1568 return error;
1569
5a49ff9f
CMN
1570 if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1571 return error;
fcccf304 1572
5a49ff9f
CMN
1573 if ((error = rename_remote_config_section(remote->repo, remote->name, new_name)) < 0)
1574 return error;
fcccf304 1575
5a49ff9f
CMN
1576 if ((error = update_branch_remote_config_entry(remote->repo, remote->name, new_name)) < 0)
1577 return error;
fcccf304 1578
5a49ff9f
CMN
1579 if ((error = rename_remote_references(remote->repo, remote->name, new_name)) < 0)
1580 return error;
fcccf304 1581
72bca13e 1582 if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
5a49ff9f 1583 return error;
fcccf304 1584
72bca13e
CMN
1585 out->count = problem_refspecs.length;
1586 out->strings = (char **) problem_refspecs.contents;
1587
61dcfe14
CMN
1588 dup = git__strdup(new_name);
1589 GITERR_CHECK_ALLOC(dup);
dab89f9b 1590
61dcfe14
CMN
1591 tmp = remote->name;
1592 remote->name = dup;
1593 git__free(tmp);
fcccf304 1594
1595 return 0;
1596}
b0f6e45d
ET
1597
1598int git_remote_update_fetchhead(git_remote *remote)
1599{
8f2a3d62 1600 return (remote->update_fetchhead != 0);
b0f6e45d
ET
1601}
1602
1603void git_remote_set_update_fetchhead(git_remote *remote, int value)
1604{
8f2a3d62 1605 remote->update_fetchhead = (value != 0);
b0f6e45d 1606}
2bca5b67 1607
1608int git_remote_is_valid_name(
1609 const char *remote_name)
1610{
1611 git_buf buf = GIT_BUF_INIT;
1612 git_refspec refspec;
1613 int error = -1;
1614
1615 if (!remote_name || *remote_name == '\0')
1616 return 0;
1617
1618 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
1619 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
1620
1621 git_buf_free(&buf);
1622 git_refspec__free(&refspec);
1623
1624 giterr_clear();
1625 return error == 0;
1626}
4330ab26
CMN
1627
1628git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
1629{
1630 git_refspec *spec;
1631 size_t i;
1632
af613ecd 1633 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1634 if (spec->push)
1635 continue;
1636
1637 if (git_refspec_src_matches(spec, refname))
1638 return spec;
1639 }
1640
1641 return NULL;
1642}
1643
1644git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
1645{
1646 git_refspec *spec;
1647 size_t i;
1648
af613ecd 1649 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1650 if (spec->push)
1651 continue;
1652
1653 if (git_refspec_dst_matches(spec, refname))
1654 return spec;
1655 }
1656
1657 return NULL;
1658}
1659
1660void git_remote_clear_refspecs(git_remote *remote)
1661{
1662 git_refspec *spec;
4330ab26
CMN
1663 size_t i;
1664
1665 git_vector_foreach(&remote->refspecs, i, spec) {
1666 git_refspec__free(spec);
1be680c4 1667 git__free(spec);
4330ab26
CMN
1668 }
1669 git_vector_clear(&remote->refspecs);
4330ab26
CMN
1670}
1671
bc6374ea 1672int git_remote_add_fetch(git_remote *remote, const char *refspec)
4330ab26 1673{
c300d84a 1674 return add_refspec(remote, refspec, true);
4330ab26
CMN
1675}
1676
bc6374ea 1677int git_remote_add_push(git_remote *remote, const char *refspec)
4330ab26 1678{
c300d84a 1679 return add_refspec(remote, refspec, false);
266af6d8
CMN
1680}
1681
1682static int set_refspecs(git_remote *remote, git_strarray *array, int push)
1683{
1684 git_vector *vec = &remote->refspecs;
1685 git_refspec *spec;
1686 size_t i;
1687
1688 /* Start by removing any refspecs of the same type */
1689 for (i = 0; i < vec->length; i++) {
1690 spec = git_vector_get(vec, i);
1691 if (spec->push != push)
1692 continue;
1693
1694 git_refspec__free(spec);
1695 git__free(spec);
1696 git_vector_remove(vec, i);
1697 i--;
1698 }
1699
1700 /* And now we add the new ones */
1701
1702 for (i = 0; i < array->count; i++) {
1703 if (add_refspec(remote, array->strings[i], !push) < 0)
1704 return -1;
1705 }
1706
c300d84a 1707 return 0;
266af6d8
CMN
1708}
1709
1710int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array)
1711{
1712 return set_refspecs(remote, array, false);
1713}
1714
1715int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array)
1716{
1717 return set_refspecs(remote, array, true);
4330ab26 1718}
bc6374ea 1719
11f6ad5f 1720static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
bc6374ea
CMN
1721{
1722 size_t i;
1723 git_vector refspecs;
1724 git_refspec *spec;
1725 char *dup;
1726
1727 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
1728 return -1;
1729
1730 git_vector_foreach(&remote->refspecs, i, spec) {
1731 if (spec->push != push)
1732 continue;
1733
1be680c4 1734 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 1735 goto on_error;
bc6374ea
CMN
1736
1737 if (git_vector_insert(&refspecs, dup) < 0) {
1738 git__free(dup);
1739 goto on_error;
1740 }
1741 }
1742
1743 array->strings = (char **)refspecs.contents;
1744 array->count = refspecs.length;
1745
1746 return 0;
1747
1748on_error:
9cfce273 1749 git_vector_free_deep(&refspecs);
bc6374ea
CMN
1750
1751 return -1;
1752}
1753
11f6ad5f 1754int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
1755{
1756 return copy_refspecs(array, remote, false);
1757}
1758
11f6ad5f 1759int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
1760{
1761 return copy_refspecs(array, remote, true);
1762}
1ffd0806 1763
11f6ad5f 1764size_t git_remote_refspec_count(const git_remote *remote)
1ffd0806
CMN
1765{
1766 return remote->refspecs.length;
1767}
1768
11f6ad5f 1769const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1ffd0806
CMN
1770{
1771 return git_vector_get(&remote->refspecs, n);
1772}
b9f81997 1773
bc91347b 1774int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
b9f81997 1775{
bc91347b
RB
1776 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1777 opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
1778 return 0;
b9f81997 1779}
40e48ea4 1780
5cdac19c
CMN
1781/* asserts a branch.<foo>.remote format */
1782static const char *name_offset(size_t *len_out, const char *name)
40e48ea4 1783{
5cdac19c
CMN
1784 size_t prefix_len;
1785 const char *dot;
40e48ea4 1786
5cdac19c
CMN
1787 prefix_len = strlen("remote.");
1788 dot = strchr(name + prefix_len, '.');
40e48ea4 1789
5cdac19c 1790 assert(dot);
40e48ea4 1791
5cdac19c
CMN
1792 *len_out = dot - name - prefix_len;
1793 return name + prefix_len;
40e48ea4 1794}
1795
1796static int remove_branch_config_related_entries(
1797 git_repository *repo,
1798 const char *remote_name)
1799{
1800 int error;
1801 git_config *config;
5cdac19c
CMN
1802 git_config_entry *entry;
1803 git_config_iterator *iter;
1804 git_buf buf = GIT_BUF_INIT;
40e48ea4 1805
1806 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1807 return error;
1808
5cdac19c 1809 if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
40e48ea4 1810 return error;
1811
5cdac19c
CMN
1812 /* find any branches with us as upstream and remove that config */
1813 while ((error = git_config_next(&entry, iter)) == 0) {
1814 const char *branch;
1815 size_t branch_len;
40e48ea4 1816
5cdac19c
CMN
1817 if (strcmp(remote_name, entry->value))
1818 continue;
40e48ea4 1819
5cdac19c 1820 branch = name_offset(&branch_len, entry->name);
40e48ea4 1821
5cdac19c
CMN
1822 git_buf_clear(&buf);
1823 if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
1824 break;
1825
1826 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
1827 break;
1828
1829 git_buf_clear(&buf);
1830 if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
1831 break;
1832
1833 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
1834 break;
40e48ea4 1835 }
1836
5cdac19c
CMN
1837 if (error == GIT_ITEROVER)
1838 error = 0;
1839
1840 git_buf_free(&buf);
1841 git_config_iterator_free(iter);
40e48ea4 1842 return error;
1843}
1844
8a9419aa 1845static int remove_refs(git_repository *repo, const git_refspec *spec)
ec8a949a 1846{
8a9419aa
CMN
1847 git_reference_iterator *iter = NULL;
1848 git_vector refs;
ec8a949a 1849 const char *name;
8a9419aa 1850 char *dup;
ec8a949a 1851 int error;
8a9419aa 1852 size_t i;
ec8a949a 1853
8a9419aa 1854 if ((error = git_vector_init(&refs, 8, NULL)) < 0)
ec8a949a
CMN
1855 return error;
1856
8a9419aa
CMN
1857 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
1858 goto cleanup;
1859
ec8a949a 1860 while ((error = git_reference_next_name(&name, iter)) == 0) {
8a9419aa
CMN
1861 if (!git_refspec_dst_matches(spec, name))
1862 continue;
1863
1864 dup = git__strdup(name);
1865 if (!dup) {
1866 error = -1;
1867 goto cleanup;
1868 }
ec8a949a 1869
8a9419aa
CMN
1870 if ((error = git_vector_insert(&refs, dup)) < 0)
1871 goto cleanup;
1872 }
ec8a949a
CMN
1873 if (error == GIT_ITEROVER)
1874 error = 0;
8a9419aa
CMN
1875 if (error < 0)
1876 goto cleanup;
1877
1878 git_vector_foreach(&refs, i, name) {
1879 if ((error = git_reference_remove(repo, name)) < 0)
1880 break;
1881 }
ec8a949a 1882
8a9419aa
CMN
1883cleanup:
1884 git_reference_iterator_free(iter);
1885 git_vector_foreach(&refs, i, dup) {
1886 git__free(dup);
1887 }
1888 git_vector_free(&refs);
ec8a949a
CMN
1889 return error;
1890}
1891
1892static int remove_remote_tracking(git_repository *repo, const char *remote_name)
1893{
1894 git_remote *remote;
1895 int error;
1896 size_t i, count;
1897
1898 /* we want to use what's on the config, regardless of changes to the instance in memory */
1899 if ((error = git_remote_load(&remote, repo, remote_name)) < 0)
1900 return error;
1901
1902 count = git_remote_refspec_count(remote);
1903 for (i = 0; i < count; i++) {
1904 const git_refspec *refspec = git_remote_get_refspec(remote, i);
1905
1906 /* shouldn't ever actually happen */
1907 if (refspec == NULL)
1908 continue;
1909
8a9419aa 1910 if ((error = remove_refs(repo, refspec)) < 0)
ec8a949a
CMN
1911 break;
1912 }
1913
1914 git_remote_free(remote);
1915 return error;
1916}
1917
40e48ea4 1918int git_remote_delete(git_remote *remote)
1919{
1920 int error;
1921 git_repository *repo;
1922
1923 assert(remote);
1924
1925 if (!remote->name) {
1926 giterr_set(GITERR_INVALID, "Can't delete an anonymous remote.");
1927 return -1;
1928 }
1929
1930 repo = git_remote_owner(remote);
1931
40e48ea4 1932 if ((error = remove_branch_config_related_entries(repo,
1933 git_remote_name(remote))) < 0)
1934 return error;
1935
ec8a949a
CMN
1936 if ((error = remove_remote_tracking(repo, git_remote_name(remote))) < 0)
1937 return error;
1938
1939 if ((error = rename_remote_config_section(
1940 repo, git_remote_name(remote), NULL)) < 0)
1941 return error;
1942
40e48ea4 1943 return 0;
1944}
d22db24f
CMN
1945
1946int git_remote_default_branch(git_buf *out, git_remote *remote)
1947{
1948 const git_remote_head **heads;
1949 const git_remote_head *guess = NULL;
1950 const git_oid *head_id;
1951 size_t heads_len, i;
1952 int error;
1953
dc8adda4
JG
1954 assert(out);
1955
d22db24f
CMN
1956 if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
1957 return error;
1958
1959 if (heads_len == 0)
1960 return GIT_ENOTFOUND;
1961
0cdaa376
CMN
1962 if (strcmp(heads[0]->name, GIT_HEAD_FILE))
1963 return GIT_ENOTFOUND;
1964
d22db24f
CMN
1965 git_buf_sanitize(out);
1966 /* the first one must be HEAD so if that has the symref info, we're done */
1967 if (heads[0]->symref_target)
1968 return git_buf_puts(out, heads[0]->symref_target);
1969
1970 /*
1971 * If there's no symref information, we have to look over them
1972 * and guess. We return the first match unless the master
1973 * branch is a candidate. Then we return the master branch.
1974 */
1975 head_id = &heads[0]->oid;
1976
1977 for (i = 1; i < heads_len; i++) {
1978 if (git_oid_cmp(head_id, &heads[i]->oid))
1979 continue;
1980
38952604
CMN
1981 if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
1982 continue;
1983
d22db24f
CMN
1984 if (!guess) {
1985 guess = heads[i];
1986 continue;
1987 }
1988
1989 if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
1990 guess = heads[i];
1991 break;
1992 }
1993 }
1994
1995 if (!guess)
1996 return GIT_ENOTFOUND;
1997
1998 return git_buf_puts(out, guess->name);
1999}