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