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