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