rugged 0.23.0b2 → 0.23.0b4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_blob.c +39 -0
  3. data/ext/rugged/rugged_diff.c +7 -3
  4. data/ext/rugged/rugged_index.c +2 -2
  5. data/ext/rugged/rugged_remote.c +27 -148
  6. data/ext/rugged/rugged_remote_collection.c +134 -12
  7. data/ext/rugged/rugged_repo.c +74 -5
  8. data/ext/rugged/rugged_submodule.c +18 -208
  9. data/ext/rugged/rugged_submodule_collection.c +148 -0
  10. data/lib/rugged/version.rb +1 -1
  11. data/vendor/libgit2/AUTHORS +1 -0
  12. data/vendor/libgit2/CMakeLists.txt +33 -25
  13. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -29
  14. data/vendor/libgit2/include/git2.h +1 -1
  15. data/vendor/libgit2/include/git2/blob.h +4 -6
  16. data/vendor/libgit2/include/git2/checkout.h +10 -1
  17. data/vendor/libgit2/include/git2/clone.h +6 -7
  18. data/vendor/libgit2/include/git2/commit.h +11 -0
  19. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  20. data/vendor/libgit2/include/git2/describe.h +1 -1
  21. data/vendor/libgit2/include/git2/diff.h +68 -11
  22. data/vendor/libgit2/include/git2/errors.h +4 -1
  23. data/vendor/libgit2/include/git2/filter.h +16 -0
  24. data/vendor/libgit2/include/git2/index.h +38 -11
  25. data/vendor/libgit2/include/git2/odb.h +1 -1
  26. data/vendor/libgit2/include/git2/odb_backend.h +2 -2
  27. data/vendor/libgit2/include/git2/remote.h +300 -207
  28. data/vendor/libgit2/include/git2/reset.h +1 -0
  29. data/vendor/libgit2/include/git2/stash.h +135 -4
  30. data/vendor/libgit2/include/git2/status.h +1 -0
  31. data/vendor/libgit2/include/git2/submodule.h +46 -75
  32. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  33. data/vendor/libgit2/include/git2/sys/stream.h +2 -0
  34. data/vendor/libgit2/include/git2/sys/transport.h +1 -21
  35. data/vendor/libgit2/include/git2/transport.h +27 -0
  36. data/vendor/libgit2/include/git2/types.h +20 -10
  37. data/vendor/libgit2/include/git2/version.h +3 -3
  38. data/vendor/libgit2/libgit2.pc.in +4 -2
  39. data/vendor/libgit2/src/attr.c +2 -1
  40. data/vendor/libgit2/src/attr_file.c +18 -37
  41. data/vendor/libgit2/src/blame.c +2 -2
  42. data/vendor/libgit2/src/blob.c +4 -3
  43. data/vendor/libgit2/src/branch.c +6 -3
  44. data/vendor/libgit2/src/buf_text.c +4 -6
  45. data/vendor/libgit2/src/buf_text.h +1 -2
  46. data/vendor/libgit2/src/buffer.c +8 -6
  47. data/vendor/libgit2/src/buffer.h +1 -1
  48. data/vendor/libgit2/src/cache.c +1 -0
  49. data/vendor/libgit2/src/checkout.c +34 -20
  50. data/vendor/libgit2/src/clone.c +29 -29
  51. data/vendor/libgit2/src/commit.c +65 -0
  52. data/vendor/libgit2/src/common.h +5 -0
  53. data/vendor/libgit2/src/config.c +20 -0
  54. data/vendor/libgit2/src/config.h +6 -0
  55. data/vendor/libgit2/src/config_file.c +2 -2
  56. data/vendor/libgit2/src/crlf.c +39 -17
  57. data/vendor/libgit2/src/curl_stream.c +257 -0
  58. data/vendor/libgit2/src/curl_stream.h +14 -0
  59. data/vendor/libgit2/src/diff.c +223 -88
  60. data/vendor/libgit2/src/diff.h +21 -1
  61. data/vendor/libgit2/src/diff_file.c +23 -13
  62. data/vendor/libgit2/src/diff_file.h +4 -2
  63. data/vendor/libgit2/src/diff_patch.c +266 -71
  64. data/vendor/libgit2/src/diff_patch.h +36 -0
  65. data/vendor/libgit2/src/diff_print.c +156 -126
  66. data/vendor/libgit2/src/diff_tform.c +32 -54
  67. data/vendor/libgit2/src/fetch.c +27 -10
  68. data/vendor/libgit2/src/fetch.h +2 -2
  69. data/vendor/libgit2/src/filebuf.c +1 -1
  70. data/vendor/libgit2/src/fileops.c +6 -2
  71. data/vendor/libgit2/src/filter.c +28 -7
  72. data/vendor/libgit2/src/fnmatch.c +5 -5
  73. data/vendor/libgit2/src/global.c +16 -0
  74. data/vendor/libgit2/src/ident.c +2 -2
  75. data/vendor/libgit2/src/ignore.c +1 -0
  76. data/vendor/libgit2/src/index.c +338 -80
  77. data/vendor/libgit2/src/index.h +4 -1
  78. data/vendor/libgit2/src/indexer.c +19 -5
  79. data/vendor/libgit2/src/iterator.c +118 -11
  80. data/vendor/libgit2/src/iterator.h +25 -0
  81. data/vendor/libgit2/src/merge.c +96 -106
  82. data/vendor/libgit2/src/merge.h +14 -4
  83. data/vendor/libgit2/src/netops.c +3 -3
  84. data/vendor/libgit2/src/odb.c +17 -9
  85. data/vendor/libgit2/src/odb.h +1 -1
  86. data/vendor/libgit2/src/odb_loose.c +2 -2
  87. data/vendor/libgit2/src/odb_pack.c +1 -1
  88. data/vendor/libgit2/src/openssl_stream.c +118 -27
  89. data/vendor/libgit2/src/pack-objects.c +28 -0
  90. data/vendor/libgit2/src/pack-objects.h +1 -0
  91. data/vendor/libgit2/src/pack.c +18 -10
  92. data/vendor/libgit2/src/path.c +16 -11
  93. data/vendor/libgit2/src/path.h +1 -1
  94. data/vendor/libgit2/src/push.c +26 -42
  95. data/vendor/libgit2/src/push.h +2 -34
  96. data/vendor/libgit2/src/rebase.c +1 -1
  97. data/vendor/libgit2/src/refs.c +1 -1
  98. data/vendor/libgit2/src/refspec.c +6 -0
  99. data/vendor/libgit2/src/remote.c +381 -274
  100. data/vendor/libgit2/src/remote.h +0 -4
  101. data/vendor/libgit2/src/repository.c +33 -12
  102. data/vendor/libgit2/src/repository.h +0 -1
  103. data/vendor/libgit2/src/reset.c +1 -0
  104. data/vendor/libgit2/src/stash.c +439 -17
  105. data/vendor/libgit2/src/status.c +6 -0
  106. data/vendor/libgit2/src/stransport_stream.c +58 -21
  107. data/vendor/libgit2/src/stream.h +15 -0
  108. data/vendor/libgit2/src/submodule.c +410 -664
  109. data/vendor/libgit2/src/submodule.h +0 -24
  110. data/vendor/libgit2/src/transaction.c +1 -0
  111. data/vendor/libgit2/src/transports/cred.c +55 -1
  112. data/vendor/libgit2/src/transports/http.c +18 -2
  113. data/vendor/libgit2/src/transports/local.c +60 -59
  114. data/vendor/libgit2/src/transports/smart.h +1 -1
  115. data/vendor/libgit2/src/transports/smart_protocol.c +11 -11
  116. data/vendor/libgit2/src/transports/ssh.c +46 -7
  117. data/vendor/libgit2/src/unix/posix.h +4 -0
  118. data/vendor/libgit2/src/util.c +9 -9
  119. data/vendor/libgit2/src/util.h +9 -0
  120. data/vendor/libgit2/src/win32/posix.h +3 -0
  121. data/vendor/libgit2/src/win32/posix_w32.c +38 -0
  122. data/vendor/libgit2/src/win32/w32_util.h +10 -0
  123. metadata +4 -3
  124. data/vendor/libgit2/include/git2/push.h +0 -94
@@ -65,6 +65,7 @@ struct git_packbuilder {
65
65
  git_zstream zstream;
66
66
 
67
67
  uint32_t nr_objects,
68
+ nr_deltified,
68
69
  nr_alloc,
69
70
  nr_written,
70
71
  nr_remaining;
@@ -319,9 +319,9 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
319
319
 
320
320
  static int pack_index_open(struct git_pack_file *p)
321
321
  {
322
- char *idx_name;
323
322
  int error = 0;
324
- size_t name_len, base_len;
323
+ size_t name_len;
324
+ git_buf idx_name = GIT_BUF_INIT;
325
325
 
326
326
  if (p->index_version > -1)
327
327
  return 0;
@@ -329,22 +329,23 @@ static int pack_index_open(struct git_pack_file *p)
329
329
  name_len = strlen(p->pack_name);
330
330
  assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */
331
331
 
332
- if ((idx_name = git__malloc(name_len)) == NULL)
332
+ git_buf_grow(&idx_name, name_len);
333
+ git_buf_put(&idx_name, p->pack_name, name_len - strlen(".pack"));
334
+ git_buf_puts(&idx_name, ".idx");
335
+ if (git_buf_oom(&idx_name)) {
336
+ giterr_set_oom();
333
337
  return -1;
334
-
335
- base_len = name_len - strlen(".pack");
336
- memcpy(idx_name, p->pack_name, base_len);
337
- memcpy(idx_name + base_len, ".idx", sizeof(".idx"));
338
+ }
338
339
 
339
340
  if ((error = git_mutex_lock(&p->lock)) < 0) {
340
- git__free(idx_name);
341
+ git_buf_free(&idx_name);
341
342
  return error;
342
343
  }
343
344
 
344
345
  if (p->index_version == -1)
345
- error = pack_index_check(idx_name, p);
346
+ error = pack_index_check(idx_name.ptr, p);
346
347
 
347
- git__free(idx_name);
348
+ git_buf_free(&idx_name);
348
349
 
349
350
  git_mutex_unlock(&p->lock);
350
351
 
@@ -959,8 +960,15 @@ git_off_t get_delta_base(
959
960
  if (k != kh_end(p->idx_cache)) {
960
961
  *curpos += 20;
961
962
  return ((struct git_pack_entry *)kh_value(p->idx_cache, k))->offset;
963
+ } else {
964
+ /* If we're building an index, don't try to find the pack
965
+ * entry; we just haven't seen it yet. We'll make
966
+ * progress again in the next loop.
967
+ */
968
+ return GIT_PASSTHROUGH;
962
969
  }
963
970
  }
971
+
964
972
  /* The base entry _must_ be in the same pack */
965
973
  if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < 0)
966
974
  return packfile_error("base entry delta is not in the same pack");
@@ -640,7 +640,7 @@ static bool _check_dir_contents(
640
640
  /* leave base valid even if we could not make space for subdir */
641
641
  if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, dir_size, sub_size) ||
642
642
  GIT_ADD_SIZET_OVERFLOW(&alloc_size, alloc_size, 2) ||
643
- git_buf_try_grow(dir, alloc_size, false, false) < 0)
643
+ git_buf_try_grow(dir, alloc_size, false) < 0)
644
644
  return false;
645
645
 
646
646
  /* save excursion */
@@ -847,7 +847,7 @@ int git_path_make_relative(git_buf *path, const char *parent)
847
847
 
848
848
  /* save the offset as we might realllocate the pointer */
849
849
  offset = p - path->ptr;
850
- if (git_buf_try_grow(path, alloclen, 1, 0) < 0)
850
+ if (git_buf_try_grow(path, alloclen, 1) < 0)
851
851
  return -1;
852
852
  p = path->ptr + offset;
853
853
 
@@ -889,9 +889,9 @@ void git_path_iconv_clear(git_path_iconv_t *ic)
889
889
  }
890
890
  }
891
891
 
892
- int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen)
892
+ int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen)
893
893
  {
894
- char *nfd = *in, *nfc;
894
+ char *nfd = (char*)*in, *nfc;
895
895
  size_t nfdlen = *inlen, nfclen, wantlen = nfdlen, alloclen, rv;
896
896
  int retry = 1;
897
897
 
@@ -1018,8 +1018,7 @@ int git_path_direach(
1018
1018
  int error = 0;
1019
1019
  ssize_t wd_len;
1020
1020
  DIR *dir;
1021
- path_dirent_data de_data;
1022
- struct dirent *de, *de_buf = (struct dirent *)&de_data;
1021
+ struct dirent *de;
1023
1022
 
1024
1023
  #ifdef GIT_USE_ICONV
1025
1024
  git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
@@ -1045,8 +1044,8 @@ int git_path_direach(
1045
1044
  (void)git_path_iconv_init_precompose(&ic);
1046
1045
  #endif
1047
1046
 
1048
- while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) {
1049
- char *de_path = de->d_name;
1047
+ while ((de = readdir(dir)) != NULL) {
1048
+ const char *de_path = de->d_name;
1050
1049
  size_t de_len = strlen(de_path);
1051
1050
 
1052
1051
  if (git_path_is_dot_or_dotdot(de_path))
@@ -1060,12 +1059,16 @@ int git_path_direach(
1060
1059
  if ((error = git_buf_put(path, de_path, de_len)) < 0)
1061
1060
  break;
1062
1061
 
1062
+ giterr_clear();
1063
1063
  error = fn(arg, path);
1064
1064
 
1065
1065
  git_buf_truncate(path, wd_len); /* restore path */
1066
1066
 
1067
+ /* Only set our own error if the callback did not set one already */
1067
1068
  if (error != 0) {
1068
- giterr_set_after_callback(error);
1069
+ if (!giterr_last())
1070
+ giterr_set_after_callback(error);
1071
+
1069
1072
  break;
1070
1073
  }
1071
1074
  }
@@ -1227,6 +1230,8 @@ void git_path_diriter_free(git_path_diriter *diriter)
1227
1230
  if (diriter == NULL)
1228
1231
  return;
1229
1232
 
1233
+ git_buf_free(&diriter->path_utf8);
1234
+
1230
1235
  if (diriter->handle != INVALID_HANDLE_VALUE) {
1231
1236
  FindClose(diriter->handle);
1232
1237
  diriter->handle = INVALID_HANDLE_VALUE;
@@ -1300,7 +1305,7 @@ int git_path_diriter_next(git_path_diriter *diriter)
1300
1305
 
1301
1306
  #ifdef GIT_USE_ICONV
1302
1307
  if ((diriter->flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0 &&
1303
- (error = git_path_iconv(&diriter->ic, (char **)&filename, &filename_len)) < 0)
1308
+ (error = git_path_iconv(&diriter->ic, &filename, &filename_len)) < 0)
1304
1309
  return error;
1305
1310
  #endif
1306
1311
 
@@ -1469,7 +1474,7 @@ static int32_t next_hfs_char(const char **in, size_t *len)
1469
1474
  * the ASCII range, which is perfectly fine, because the
1470
1475
  * git folder name can only be composed of ascii characters
1471
1476
  */
1472
- return tolower(codepoint);
1477
+ return git__tolower(codepoint);
1473
1478
  }
1474
1479
  return 0; /* NULL byte -- end of string */
1475
1480
  }
@@ -407,7 +407,7 @@ extern void git_path_iconv_clear(git_path_iconv_t *ic);
407
407
  * pointer internal iconv buffer if rewrite happened. The `in` pointer
408
408
  * will be left unchanged if no rewrite was needed.
409
409
  */
410
- extern int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen);
410
+ extern int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen);
411
411
 
412
412
  #endif /* GIT_USE_ICONV */
413
413
 
@@ -77,30 +77,6 @@ int git_push_set_options(git_push *push, const git_push_options *opts)
77
77
  return 0;
78
78
  }
79
79
 
80
- int git_push_set_callbacks(
81
- git_push *push,
82
- git_packbuilder_progress pack_progress_cb,
83
- void *pack_progress_cb_payload,
84
- git_push_transfer_progress transfer_progress_cb,
85
- void *transfer_progress_cb_payload,
86
- git_push_negotiation negotiation_cb,
87
- void *negotiation_cb_payload)
88
- {
89
- if (!push)
90
- return -1;
91
-
92
- push->pack_progress_cb = pack_progress_cb;
93
- push->pack_progress_cb_payload = pack_progress_cb_payload;
94
-
95
- push->transfer_progress_cb = transfer_progress_cb;
96
- push->transfer_progress_cb_payload = transfer_progress_cb_payload;
97
-
98
- push->negotiation_cb = negotiation_cb;
99
- push->negotiation_cb_payload = negotiation_cb_payload;
100
-
101
- return 0;
102
- }
103
-
104
80
  static void free_refspec(push_spec *spec)
105
81
  {
106
82
  if (spec == NULL)
@@ -179,7 +155,7 @@ int git_push_add_refspec(git_push *push, const char *refspec)
179
155
  return 0;
180
156
  }
181
157
 
182
- int git_push_update_tips(git_push *push)
158
+ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks)
183
159
  {
184
160
  git_buf remote_ref_name = GIT_BUF_INIT;
185
161
  size_t i, j;
@@ -236,9 +212,9 @@ int git_push_update_tips(git_push *push)
236
212
  fire_callback = 0;
237
213
  }
238
214
 
239
- if (fire_callback && push->remote->callbacks.update_tips) {
240
- error = push->remote->callbacks.update_tips(git_buf_cstr(&remote_ref_name),
241
- &push_spec->roid, &push_spec->loid, push->remote->callbacks.payload);
215
+ if (fire_callback && callbacks && callbacks->update_tips) {
216
+ error = callbacks->update_tips(git_buf_cstr(&remote_ref_name),
217
+ &push_spec->roid, &push_spec->loid, callbacks->payload);
242
218
 
243
219
  if (error < 0)
244
220
  goto on_error;
@@ -553,11 +529,12 @@ static int add_update(git_push *push, push_spec *spec)
553
529
 
554
530
  u->src_refname = git__strdup(spec->refspec.src);
555
531
  GITERR_CHECK_ALLOC(u->src_refname);
556
- u->dst_refname = git__strdup(spec->refspec.src);
532
+
533
+ u->dst_refname = git__strdup(spec->refspec.dst);
557
534
  GITERR_CHECK_ALLOC(u->dst_refname);
558
535
 
559
- git_oid_cpy(&u->src, &spec->loid);
560
- git_oid_cpy(&u->dst, &spec->roid);
536
+ git_oid_cpy(&u->src, &spec->roid);
537
+ git_oid_cpy(&u->dst, &spec->loid);
561
538
 
562
539
  return git_vector_insert(&push->updates, u);
563
540
  }
@@ -595,7 +572,7 @@ static int calculate_work(git_push *push)
595
572
  return 0;
596
573
  }
597
574
 
598
- static int do_push(git_push *push)
575
+ static int do_push(git_push *push, const git_remote_callbacks *callbacks)
599
576
  {
600
577
  int error = 0;
601
578
  git_transport *transport = push->remote->transport;
@@ -617,21 +594,20 @@ static int do_push(git_push *push)
617
594
 
618
595
  git_packbuilder_set_threads(push->pb, push->pb_parallelism);
619
596
 
620
- if (push->pack_progress_cb)
621
- if ((error = git_packbuilder_set_callbacks(push->pb, push->pack_progress_cb, push->pack_progress_cb_payload)) < 0)
597
+ if (callbacks && callbacks->pack_progress)
598
+ if ((error = git_packbuilder_set_callbacks(push->pb, callbacks->pack_progress, callbacks->payload)) < 0)
622
599
  goto on_error;
623
600
 
624
601
  if ((error = calculate_work(push)) < 0)
625
602
  goto on_error;
626
603
 
627
- if (push->negotiation_cb &&
628
- (error = push->negotiation_cb((const git_push_update **) push->updates.contents,
629
- push->updates.length,
630
- push->negotiation_cb_payload)))
604
+ if (callbacks && callbacks->push_negotiation &&
605
+ (error = callbacks->push_negotiation((const git_push_update **) push->updates.contents,
606
+ push->updates.length, callbacks->payload)) < 0)
631
607
  goto on_error;
632
608
 
633
609
  if ((error = queue_objects(push)) < 0 ||
634
- (error = transport->push(transport, push)) < 0)
610
+ (error = transport->push(transport, push, callbacks)) < 0)
635
611
  goto on_error;
636
612
 
637
613
  on_error:
@@ -657,16 +633,16 @@ static int filter_refs(git_remote *remote)
657
633
  return 0;
658
634
  }
659
635
 
660
- int git_push_finish(git_push *push)
636
+ int git_push_finish(git_push *push, const git_remote_callbacks *callbacks)
661
637
  {
662
638
  int error;
663
639
 
664
640
  if (!git_remote_connected(push->remote) &&
665
- (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH)) < 0)
641
+ (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH, callbacks)) < 0)
666
642
  return error;
667
643
 
668
644
  if ((error = filter_refs(push->remote)) < 0 ||
669
- (error = do_push(push)) < 0)
645
+ (error = do_push(push, callbacks)) < 0)
670
646
  return error;
671
647
 
672
648
  if (!push->unpack_ok) {
@@ -707,6 +683,7 @@ void git_push_free(git_push *push)
707
683
  {
708
684
  push_spec *spec;
709
685
  push_status *status;
686
+ git_push_update *update;
710
687
  unsigned int i;
711
688
 
712
689
  if (push == NULL)
@@ -722,6 +699,13 @@ void git_push_free(git_push *push)
722
699
  }
723
700
  git_vector_free(&push->status);
724
701
 
702
+ git_vector_foreach(&push->updates, i, update) {
703
+ git__free(update->src_refname);
704
+ git__free(update->dst_refname);
705
+ git__free(update);
706
+ }
707
+ git_vector_free(&push->updates);
708
+
725
709
  git__free(push);
726
710
  }
727
711
 
@@ -38,13 +38,6 @@ struct git_push {
38
38
 
39
39
  /* options */
40
40
  unsigned pb_parallelism;
41
-
42
- git_packbuilder_progress pack_progress_cb;
43
- void *pack_progress_cb_payload;
44
- git_push_transfer_progress transfer_progress_cb;
45
- void *transfer_progress_cb_payload;
46
- git_push_negotiation negotiation_cb;
47
- void *negotiation_cb_payload;
48
41
  };
49
42
 
50
43
  /**
@@ -76,31 +69,6 @@ int git_push_set_options(
76
69
  git_push *push,
77
70
  const git_push_options *opts);
78
71
 
79
- /**
80
- * Set the callbacks for a push
81
- *
82
- * @param push The push object
83
- * @param pack_progress_cb Function to call with progress information during
84
- * pack building. Be aware that this is called inline with pack building
85
- * operations, so performance may be affected.
86
- * @param pack_progress_cb_payload Payload for the pack progress callback.
87
- * @param transfer_progress_cb Function to call with progress information during
88
- * the upload portion of a push. Be aware that this is called inline with
89
- * pack building operations, so performance may be affected.
90
- * @param transfer_progress_cb_payload Payload for the network progress callback.
91
- * @param push_negotiation_cb Function to call before sending the commands to the remote.
92
- * @param push_negotiation_cb_payload Payload for the negotiation callback
93
- * @return 0 or an error code
94
- */
95
- int git_push_set_callbacks(
96
- git_push *push,
97
- git_packbuilder_progress pack_progress_cb,
98
- void *pack_progress_cb_payload,
99
- git_push_transfer_progress transfer_progress_cb,
100
- void *transfer_progress_cb_payload,
101
- git_push_negotiation negotiation_cb,
102
- void *negotiation_cb_payload);
103
-
104
72
  /**
105
73
  * Add a refspec to be pushed
106
74
  *
@@ -119,7 +87,7 @@ int git_push_add_refspec(git_push *push, const char *refspec);
119
87
  *
120
88
  * @return 0 or an error code
121
89
  */
122
- int git_push_update_tips(git_push *push);
90
+ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks);
123
91
 
124
92
  /**
125
93
  * Perform the push
@@ -135,7 +103,7 @@ int git_push_update_tips(git_push *push);
135
103
  *
136
104
  * @return 0 or an error code
137
105
  */
138
- int git_push_finish(git_push *push);
106
+ int git_push_finish(git_push *push, const git_remote_callbacks *callbacks);
139
107
 
140
108
  /**
141
109
  * Invoke callback `cb' on each status entry
@@ -512,7 +512,7 @@ static int rebase_ensure_not_dirty(
512
512
  git_tree *head = NULL;
513
513
  git_index *index = NULL;
514
514
  git_diff *diff = NULL;
515
- int error;
515
+ int error = 0;
516
516
 
517
517
  if (check_index) {
518
518
  if ((error = git_repository_head_tree(&head, repo)) < 0 ||
@@ -863,7 +863,7 @@ int git_reference__normalize_name(
863
863
  const char *name,
864
864
  unsigned int flags)
865
865
  {
866
- char *current;
866
+ const char *current;
867
867
  int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
868
868
  unsigned int process_flags;
869
869
  bool normalize = (buf != NULL);
@@ -42,6 +42,12 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
42
42
  */
43
43
  if (!is_fetch && rhs == lhs && rhs[1] == '\0') {
44
44
  refspec->matching = 1;
45
+ refspec->string = git__strdup(input);
46
+ GITERR_CHECK_ALLOC(refspec->string);
47
+ refspec->src = git__strdup("");
48
+ GITERR_CHECK_ALLOC(refspec->src);
49
+ refspec->dst = git__strdup("");
50
+ GITERR_CHECK_ALLOC(refspec->dst);
45
51
  return 0;
46
52
  }
47
53
 
@@ -20,8 +20,15 @@
20
20
  #include "fetchhead.h"
21
21
  #include "push.h"
22
22
 
23
+ #define CONFIG_URL_FMT "remote.%s.url"
24
+ #define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
25
+ #define CONFIG_FETCH_FMT "remote.%s.fetch"
26
+ #define CONFIG_PUSH_FMT "remote.%s.push"
27
+ #define CONFIG_TAGOPT_FMT "remote.%s.tagopt"
28
+
23
29
  static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
24
30
  static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
31
+ char *apply_insteadof(git_config *config, const char *url, int direction);
25
32
 
26
33
  static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
27
34
  {
@@ -56,7 +63,6 @@ static int download_tags_value(git_remote *remote, git_config *cfg)
56
63
  git_buf buf = GIT_BUF_INIT;
57
64
  int error;
58
65
 
59
- /* The 0 value is the default (auto), let's see if we need to change it */
60
66
  if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
61
67
  return -1;
62
68
 
@@ -88,6 +94,48 @@ static int ensure_remote_name_is_valid(const char *name)
88
94
  return error;
89
95
  }
90
96
 
97
+ static 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;
101
+ git_refspec spec;
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
+
113
+ if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
114
+ if (giterr_last()->klass != GITERR_NOMEMORY)
115
+ error = GIT_EINVALIDSPEC;
116
+
117
+ return error;
118
+ }
119
+
120
+ git_refspec__free(&spec);
121
+
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
+
134
+ cleanup:
135
+ git_buf_free(&var);
136
+ return 0;
137
+ }
138
+
91
139
  #if 0
92
140
  /* We could export this as a helper */
93
141
  static int get_check_cert(int *out, git_repository *repo)
@@ -119,14 +167,18 @@ static int get_check_cert(int *out, git_repository *repo)
119
167
 
120
168
  static int canonicalize_url(git_buf *out, const char *in)
121
169
  {
122
- #ifdef GIT_WIN32
123
- const char *c;
170
+ if (in == NULL || strlen(in) == 0) {
171
+ giterr_set(GITERR_INVALID, "cannot set empty URL");
172
+ return GIT_EINVALIDSPEC;
173
+ }
124
174
 
175
+ #ifdef GIT_WIN32
125
176
  /* Given a UNC path like \\server\path, we need to convert this
126
177
  * to //server/path for compatibility with core git.
127
178
  */
128
179
  if (in[0] == '\\' && in[1] == '\\' &&
129
180
  (git__isalpha(in[2]) || git__isdigit(in[2]))) {
181
+ const char *c;
130
182
  for (c = in; *c; c++)
131
183
  git_buf_putc(out, *c == '\\' ? '/' : *c);
132
184
 
@@ -141,31 +193,44 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
141
193
  {
142
194
  git_remote *remote;
143
195
  git_config *config = NULL;
144
- git_buf canonical_url = GIT_BUF_INIT, fetchbuf = GIT_BUF_INIT;
196
+ git_buf canonical_url = GIT_BUF_INIT;
197
+ git_buf var = GIT_BUF_INIT;
145
198
  int error = -1;
146
199
 
147
200
  /* name is optional */
148
201
  assert(out && repo && url);
149
202
 
203
+ if ((error = git_repository_config__weakptr(&config, repo)) < 0)
204
+ return error;
205
+
150
206
  remote = git__calloc(1, sizeof(git_remote));
151
207
  GITERR_CHECK_ALLOC(remote);
152
208
 
153
209
  remote->repo = repo;
154
- remote->update_fetchhead = 1;
155
210
 
156
211
  if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
157
212
  canonicalize_url(&canonical_url, url) < 0)
158
213
  goto on_error;
159
214
 
160
- remote->url = git_buf_detach(&canonical_url);
215
+ remote->url = apply_insteadof(repo->_config, canonical_url.ptr, GIT_DIRECTION_FETCH);
161
216
 
162
217
  if (name != NULL) {
163
218
  remote->name = git__strdup(name);
164
219
  GITERR_CHECK_ALLOC(remote->name);
220
+
221
+ if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
222
+ goto on_error;
223
+
224
+ if ((error = git_config_set_string(config, var.ptr, canonical_url.ptr)) < 0)
225
+ goto on_error;
165
226
  }
166
227
 
167
228
  if (fetch != NULL) {
168
- if (add_refspec(remote, fetch, true) < 0)
229
+ if ((error = add_refspec(remote, fetch, true)) < 0)
230
+ goto on_error;
231
+
232
+ /* only write for non-anonymous remotes */
233
+ if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0)
169
234
  goto on_error;
170
235
 
171
236
  if ((error = git_repository_config_snapshot(&config, repo)) < 0)
@@ -179,9 +244,14 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
179
244
  goto on_error;
180
245
  }
181
246
 
247
+ /* A remote without a name doesn't download tags */
182
248
  if (!name)
183
- /* A remote without a name doesn't download tags */
184
249
  remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
250
+ else
251
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
252
+
253
+
254
+ git_buf_free(&var);
185
255
 
186
256
  *out = remote;
187
257
  error = 0;
@@ -191,8 +261,8 @@ on_error:
191
261
  git_remote_free(remote);
192
262
 
193
263
  git_config_free(config);
194
- git_buf_free(&fetchbuf);
195
264
  git_buf_free(&canonical_url);
265
+ git_buf_free(&var);
196
266
  return error;
197
267
  }
198
268
 
@@ -247,9 +317,6 @@ int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, con
247
317
  if (create_internal(&remote, repo, name, url, fetch) < 0)
248
318
  goto on_error;
249
319
 
250
- if (git_remote_save(remote) < 0)
251
- goto on_error;
252
-
253
320
  *out = remote;
254
321
 
255
322
  return 0;
@@ -259,22 +326,16 @@ on_error:
259
326
  return -1;
260
327
  }
261
328
 
262
- int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url, const char *fetch)
329
+ int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
263
330
  {
264
- int error;
265
- git_remote *remote;
266
-
267
- if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0)
268
- return error;
269
-
270
- *out = remote;
271
- return 0;
331
+ return create_internal(out, repo, NULL, url, NULL);
272
332
  }
273
333
 
274
334
  int git_remote_dup(git_remote **dest, git_remote *source)
275
335
  {
336
+ size_t i;
276
337
  int error = 0;
277
- git_strarray refspecs = { 0 };
338
+ git_refspec *spec;
278
339
  git_remote *remote = git__calloc(1, sizeof(git_remote));
279
340
  GITERR_CHECK_ALLOC(remote);
280
341
 
@@ -285,7 +346,7 @@ int git_remote_dup(git_remote **dest, git_remote *source)
285
346
 
286
347
  if (source->url != NULL) {
287
348
  remote->url = git__strdup(source->url);
288
- GITERR_CHECK_ALLOC(remote->url);
349
+ GITERR_CHECK_ALLOC(remote->url);
289
350
  }
290
351
 
291
352
  if (source->pushurl != NULL) {
@@ -293,11 +354,8 @@ int git_remote_dup(git_remote **dest, git_remote *source)
293
354
  GITERR_CHECK_ALLOC(remote->pushurl);
294
355
  }
295
356
 
296
- remote->transport_cb = source->transport_cb;
297
- remote->transport_cb_payload = source->transport_cb_payload;
298
357
  remote->repo = source->repo;
299
358
  remote->download_tags = source->download_tags;
300
- remote->update_fetchhead = source->update_fetchhead;
301
359
  remote->prune_refs = source->prune_refs;
302
360
 
303
361
  if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
@@ -307,22 +365,15 @@ int git_remote_dup(git_remote **dest, git_remote *source)
307
365
  goto cleanup;
308
366
  }
309
367
 
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;
368
+ git_vector_foreach(&source->refspecs, i, spec) {
369
+ if ((error = add_refspec(remote, spec->string, !spec->push)) < 0)
370
+ goto cleanup;
371
+ }
319
372
 
320
373
  *dest = remote;
321
374
 
322
375
  cleanup:
323
376
 
324
- git_strarray_free(&refspecs);
325
-
326
377
  if (error < 0)
327
378
  git__free(remote);
328
379
 
@@ -387,7 +438,6 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
387
438
  remote = git__calloc(1, sizeof(git_remote));
388
439
  GITERR_CHECK_ALLOC(remote);
389
440
 
390
- remote->update_fetchhead = 1;
391
441
  remote->name = git__strdup(name);
392
442
  GITERR_CHECK_ALLOC(remote->name);
393
443
 
@@ -408,9 +458,10 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
408
458
  optional_setting_found |= found;
409
459
 
410
460
  remote->repo = repo;
461
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
411
462
 
412
463
  if (found && strlen(val) > 0) {
413
- remote->url = git__strdup(val);
464
+ remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
414
465
  GITERR_CHECK_ALLOC(remote->url);
415
466
  }
416
467
 
@@ -430,7 +481,7 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
430
481
  }
431
482
 
432
483
  if (found && strlen(val) > 0) {
433
- remote->pushurl = git__strdup(val);
484
+ remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
434
485
  GITERR_CHECK_ALLOC(remote->pushurl);
435
486
  }
436
487
 
@@ -543,87 +594,6 @@ cleanup:
543
594
  return error;
544
595
  }
545
596
 
546
- int git_remote_save(const git_remote *remote)
547
- {
548
- int error;
549
- git_config *cfg;
550
- const char *tagopt = NULL;
551
- git_buf buf = GIT_BUF_INIT;
552
- git_config_entry *existing = NULL;
553
-
554
- assert(remote);
555
-
556
- if (!remote->name) {
557
- giterr_set(GITERR_INVALID, "Can't save an anonymous remote.");
558
- return GIT_EINVALIDSPEC;
559
- }
560
-
561
- if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
562
- return error;
563
-
564
- if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
565
- return error;
566
-
567
- if ((error = git_buf_printf(&buf, "remote.%s.url", remote->name)) < 0)
568
- return error;
569
-
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;
575
-
576
- git_buf_clear(&buf);
577
- if ((error = git_buf_printf(&buf, "remote.%s.pushurl", remote->name)) < 0)
578
- goto cleanup;
579
-
580
- if ((error = git_config__update_entry(
581
- cfg, git_buf_cstr(&buf), remote->pushurl, true, false)) < 0)
582
- goto cleanup;
583
-
584
- if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
585
- goto cleanup;
586
-
587
- if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
588
- goto cleanup;
589
-
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);
604
- if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
605
- goto cleanup;
606
-
607
- if ((error = git_config__lookup_entry(
608
- &existing, cfg, git_buf_cstr(&buf), false)) < 0)
609
- goto cleanup;
610
-
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;
617
-
618
- error = git_config__update_entry(
619
- cfg, git_buf_cstr(&buf), tagopt, true, false);
620
-
621
- cleanup:
622
- git_config_entry_free(existing);
623
- git_buf_free(&buf);
624
- return error;
625
- }
626
-
627
597
  const char *git_remote_name(const git_remote *remote)
628
598
  {
629
599
  assert(remote);
@@ -642,16 +612,42 @@ const char *git_remote_url(const git_remote *remote)
642
612
  return remote->url;
643
613
  }
644
614
 
645
- int git_remote_set_url(git_remote *remote, const char* url)
615
+ static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
646
616
  {
647
- assert(remote);
648
- assert(url);
617
+ git_config *cfg;
618
+ git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
619
+ int error;
649
620
 
650
- git__free(remote->url);
651
- remote->url = git__strdup(url);
652
- GITERR_CHECK_ALLOC(remote->url);
621
+ assert(repo && remote);
653
622
 
654
- return 0;
623
+ if ((error = ensure_remote_name_is_valid(remote)) < 0)
624
+ return error;
625
+
626
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
627
+ return error;
628
+
629
+ if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
630
+ return error;
631
+
632
+ if (url) {
633
+ if ((error = canonicalize_url(&canonical_url, url)) < 0)
634
+ goto cleanup;
635
+
636
+ error = git_config_set_string(cfg, buf.ptr, url);
637
+ } else {
638
+ error = git_config_delete_entry(cfg, buf.ptr);
639
+ }
640
+
641
+ cleanup:
642
+ git_buf_free(&canonical_url);
643
+ git_buf_free(&buf);
644
+
645
+ return error;
646
+ }
647
+
648
+ int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
649
+ {
650
+ return set_url(repo, remote, CONFIG_URL_FMT, url);
655
651
  }
656
652
 
657
653
  const char *git_remote_pushurl(const git_remote *remote)
@@ -660,18 +656,9 @@ const char *git_remote_pushurl(const git_remote *remote)
660
656
  return remote->pushurl;
661
657
  }
662
658
 
663
- int git_remote_set_pushurl(git_remote *remote, const char* url)
659
+ int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
664
660
  {
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;
661
+ return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
675
662
  }
676
663
 
677
664
  const char* git_remote__urlfordirection(git_remote *remote, int direction)
@@ -691,15 +678,34 @@ const char* git_remote__urlfordirection(git_remote *remote, int direction)
691
678
  return NULL;
692
679
  }
693
680
 
694
- int git_remote_connect(git_remote *remote, git_direction direction)
681
+ int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
682
+ {
683
+ if (!t->set_callbacks || !cbs)
684
+ return 0;
685
+
686
+ return t->set_callbacks(t, cbs->sideband_progress, NULL,
687
+ cbs->certificate_check, cbs->payload);
688
+ }
689
+
690
+ int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks)
695
691
  {
696
692
  git_transport *t;
697
693
  const char *url;
698
694
  int flags = GIT_TRANSPORTFLAGS_NONE;
699
695
  int error;
696
+ void *payload = NULL;
697
+ git_cred_acquire_cb credentials = NULL;
698
+ git_transport_cb transport = NULL;
700
699
 
701
700
  assert(remote);
702
701
 
702
+ if (callbacks) {
703
+ GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
704
+ credentials = callbacks->credentials;
705
+ transport = callbacks->transport;
706
+ payload = callbacks->payload;
707
+ }
708
+
703
709
  t = remote->transport;
704
710
 
705
711
  url = git_remote__urlfordirection(remote, direction);
@@ -711,8 +717,8 @@ int git_remote_connect(git_remote *remote, git_direction direction)
711
717
 
712
718
  /* If we don't have a transport object yet, and the caller specified a
713
719
  * custom transport factory, use that */
714
- if (!t && remote->transport_cb &&
715
- (error = remote->transport_cb(&t, remote, remote->transport_cb_payload)) < 0)
720
+ if (!t && transport &&
721
+ (error = transport(&t, remote, payload)) < 0)
716
722
  return error;
717
723
 
718
724
  /* If we still don't have a transport, then use the global
@@ -720,11 +726,8 @@ int git_remote_connect(git_remote *remote, git_direction direction)
720
726
  if (!t && (error = git_transport_new(&t, remote, url)) < 0)
721
727
  return error;
722
728
 
723
- if (t->set_callbacks &&
724
- (error = t->set_callbacks(t, remote->callbacks.sideband_progress, NULL, remote->callbacks.certificate_check, remote->callbacks.payload)) < 0)
725
- goto on_error;
726
-
727
- if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) != 0)
729
+ if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
730
+ (error = t->connect(t, url, credentials, payload, direction, flags)) != 0)
728
731
  goto on_error;
729
732
 
730
733
  remote->transport = t;
@@ -866,14 +869,24 @@ static int ls_to_vector(git_vector *out, git_remote *remote)
866
869
  return 0;
867
870
  }
868
871
 
869
- int git_remote_download(git_remote *remote, const git_strarray *refspecs)
872
+ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
870
873
  {
871
874
  int error = -1;
872
875
  size_t i;
873
- git_vector refs, specs, *to_active;
876
+ git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
877
+ const git_remote_callbacks *cbs = NULL;
874
878
 
875
879
  assert(remote);
876
880
 
881
+ if (opts) {
882
+ GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
883
+ cbs = &opts->callbacks;
884
+ }
885
+
886
+ if (!git_remote_connected(remote) &&
887
+ (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0)
888
+ goto on_error;
889
+
877
890
  if (ls_to_vector(&refs, remote) < 0)
878
891
  return -1;
879
892
 
@@ -912,10 +925,10 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs)
912
925
  remote->push = NULL;
913
926
  }
914
927
 
915
- if ((error = git_fetch_negotiate(remote)) < 0)
928
+ if ((error = git_fetch_negotiate(remote, opts)) < 0)
916
929
  return error;
917
930
 
918
- return git_fetch_download_pack(remote);
931
+ return git_fetch_download_pack(remote, cbs);
919
932
 
920
933
  on_error:
921
934
  git_vector_free(&refs);
@@ -927,16 +940,27 @@ on_error:
927
940
  int git_remote_fetch(
928
941
  git_remote *remote,
929
942
  const git_strarray *refspecs,
943
+ const git_fetch_options *opts,
930
944
  const char *reflog_message)
931
945
  {
932
- int error;
946
+ int error, update_fetchhead = 1;
947
+ git_remote_autotag_option_t tagopt = remote->download_tags;
948
+ bool prune = false;
933
949
  git_buf reflog_msg_buf = GIT_BUF_INIT;
950
+ const git_remote_callbacks *cbs = NULL;
951
+
952
+ if (opts) {
953
+ GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
954
+ cbs = &opts->callbacks;
955
+ update_fetchhead = opts->update_fetchhead;
956
+ tagopt = opts->download_tags;
957
+ }
934
958
 
935
959
  /* Connect and download everything */
936
- if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) != 0)
960
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0)
937
961
  return error;
938
962
 
939
- error = git_remote_download(remote, refspecs);
963
+ error = git_remote_download(remote, refspecs, opts);
940
964
 
941
965
  /* We don't need to be connected anymore */
942
966
  git_remote_disconnect(remote);
@@ -954,13 +978,22 @@ int git_remote_fetch(
954
978
  }
955
979
 
956
980
  /* Create "remote/foo" branches for all remote branches */
957
- error = git_remote_update_tips(remote, git_buf_cstr(&reflog_msg_buf));
981
+ error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
958
982
  git_buf_free(&reflog_msg_buf);
959
983
  if (error < 0)
960
984
  return error;
961
985
 
962
- if (remote->prune_refs)
963
- error = git_remote_prune(remote);
986
+ if (opts && opts->prune == GIT_FETCH_PRUNE)
987
+ prune = true;
988
+ else if (opts && opts->prune == GIT_FETCH_PRUNE_UNSPECIFIED && remote->prune_refs)
989
+ prune = true;
990
+ else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
991
+ prune = false;
992
+ else
993
+ prune = remote->prune_refs;
994
+
995
+ if (prune)
996
+ error = git_remote_prune(remote, cbs);
964
997
 
965
998
  return error;
966
999
  }
@@ -1156,7 +1189,7 @@ static int find_head(const void *_a, const void *_b)
1156
1189
  return strcmp(a->name, b->name);
1157
1190
  }
1158
1191
 
1159
- int git_remote_prune(git_remote *remote)
1192
+ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
1160
1193
  {
1161
1194
  size_t i, j;
1162
1195
  git_vector remote_refs = GIT_VECTOR_INIT;
@@ -1166,6 +1199,9 @@ int git_remote_prune(git_remote *remote)
1166
1199
  int error;
1167
1200
  git_oid zero_id = {{ 0 }};
1168
1201
 
1202
+ if (callbacks)
1203
+ GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1204
+
1169
1205
  if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1170
1206
  goto cleanup;
1171
1207
 
@@ -1242,8 +1278,8 @@ int git_remote_prune(git_remote *remote)
1242
1278
  if (error < 0)
1243
1279
  goto cleanup;
1244
1280
 
1245
- if (remote->callbacks.update_tips)
1246
- error = remote->callbacks.update_tips(refname, &id, &zero_id, remote->callbacks.payload);
1281
+ if (callbacks && callbacks->update_tips)
1282
+ error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
1247
1283
 
1248
1284
  if (error < 0)
1249
1285
  goto cleanup;
@@ -1257,6 +1293,9 @@ cleanup:
1257
1293
 
1258
1294
  static int update_tips_for_spec(
1259
1295
  git_remote *remote,
1296
+ const git_remote_callbacks *callbacks,
1297
+ int update_fetchhead,
1298
+ git_remote_autotag_option_t tagopt,
1260
1299
  git_refspec *spec,
1261
1300
  git_vector *refs,
1262
1301
  const char *log_message)
@@ -1292,9 +1331,9 @@ static int update_tips_for_spec(
1292
1331
  continue;
1293
1332
 
1294
1333
  if (git_refspec_src_matches(&tagspec, head->name)) {
1295
- if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
1334
+ if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
1296
1335
 
1297
- if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1336
+ if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1298
1337
  autotag = 1;
1299
1338
 
1300
1339
  git_buf_clear(&refname);
@@ -1303,9 +1342,20 @@ static int update_tips_for_spec(
1303
1342
  } else {
1304
1343
  continue;
1305
1344
  }
1306
- } else if (git_refspec_src_matches(spec, head->name) && spec->dst) {
1307
- if (git_refspec_transform(&refname, spec, head->name) < 0)
1308
- goto on_error;
1345
+ } else if (git_refspec_src_matches(spec, head->name)) {
1346
+ if (spec->dst) {
1347
+ if (git_refspec_transform(&refname, spec, head->name) < 0)
1348
+ goto on_error;
1349
+ } else {
1350
+ /*
1351
+ * no rhs mans store it in FETCH_HEAD, even if we don't
1352
+ update anything else.
1353
+ */
1354
+ if ((error = git_vector_insert(&update_heads, head)) < 0)
1355
+ goto on_error;
1356
+
1357
+ continue;
1358
+ }
1309
1359
  } else {
1310
1360
  continue;
1311
1361
  }
@@ -1339,13 +1389,13 @@ static int update_tips_for_spec(
1339
1389
 
1340
1390
  git_reference_free(ref);
1341
1391
 
1342
- if (remote->callbacks.update_tips != NULL) {
1343
- if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.payload) < 0)
1392
+ if (callbacks && callbacks->update_tips != NULL) {
1393
+ if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1344
1394
  goto on_error;
1345
1395
  }
1346
1396
  }
1347
1397
 
1348
- if (git_remote_update_fetchhead(remote) &&
1398
+ if (update_fetchhead &&
1349
1399
  (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
1350
1400
  goto on_error;
1351
1401
 
@@ -1419,18 +1469,20 @@ static int next_head(const git_remote *remote, git_vector *refs,
1419
1469
  return GIT_ITEROVER;
1420
1470
  }
1421
1471
 
1422
- static int opportunistic_updates(const git_remote *remote, git_vector *refs, const char *msg)
1472
+ static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
1473
+ git_vector *refs, const char *msg)
1423
1474
  {
1424
1475
  size_t i, j, k;
1425
1476
  git_refspec *spec;
1426
1477
  git_remote_head *head;
1427
1478
  git_reference *ref;
1428
1479
  git_buf refname = GIT_BUF_INIT;
1429
- int error;
1480
+ int error = 0;
1430
1481
 
1431
1482
  i = j = k = 0;
1432
1483
 
1433
1484
  while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1485
+ git_oid old = {{ 0 }};
1434
1486
  /*
1435
1487
  * If we got here, there is a refspec which was used
1436
1488
  * for fetching which matches the source of one of the
@@ -1439,32 +1491,56 @@ static int opportunistic_updates(const git_remote *remote, git_vector *refs, con
1439
1491
  * FETCH_HEAD
1440
1492
  */
1441
1493
 
1494
+ git_buf_clear(&refname);
1442
1495
  if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
1443
- return error;
1496
+ goto cleanup;
1444
1497
 
1445
- error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1446
- git_buf_free(&refname);
1447
- git_reference_free(ref);
1498
+ error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1499
+ if (error < 0 && error != GIT_ENOTFOUND)
1500
+ goto cleanup;
1448
1501
 
1502
+ if (!git_oid_cmp(&old, &head->oid))
1503
+ continue;
1504
+
1505
+ /* If we did find a current reference, make sure we haven't lost a race */
1506
+ if (error)
1507
+ error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1508
+ else
1509
+ error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
1510
+ git_reference_free(ref);
1449
1511
  if (error < 0)
1450
- return error;
1512
+ goto cleanup;
1513
+
1514
+ if (callbacks && callbacks->update_tips != NULL) {
1515
+ if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1516
+ goto cleanup;
1517
+ }
1451
1518
  }
1452
1519
 
1453
- return 0;
1520
+ if (error == GIT_ITEROVER)
1521
+ error = 0;
1522
+
1523
+ cleanup:
1524
+ git_buf_free(&refname);
1525
+ return error;
1454
1526
  }
1455
1527
 
1456
1528
  int git_remote_update_tips(
1457
1529
  git_remote *remote,
1530
+ const git_remote_callbacks *callbacks,
1531
+ int update_fetchhead,
1532
+ git_remote_autotag_option_t download_tags,
1458
1533
  const char *reflog_message)
1459
1534
  {
1460
1535
  git_refspec *spec, tagspec;
1461
1536
  git_vector refs = GIT_VECTOR_INIT;
1537
+ git_remote_autotag_option_t tagopt;
1462
1538
  int error;
1463
1539
  size_t i;
1464
1540
 
1465
1541
  /* push has its own logic hidden away in the push object */
1466
1542
  if (remote->push) {
1467
- return git_push_update_tips(remote->push);
1543
+ return git_push_update_tips(remote->push, callbacks);
1468
1544
  }
1469
1545
 
1470
1546
  if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
@@ -1474,8 +1550,13 @@ int git_remote_update_tips(
1474
1550
  if ((error = ls_to_vector(&refs, remote)) < 0)
1475
1551
  goto out;
1476
1552
 
1477
- if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1478
- if ((error = update_tips_for_spec(remote, &tagspec, &refs, reflog_message)) < 0)
1553
+ if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
1554
+ tagopt = remote->download_tags;
1555
+ else
1556
+ tagopt = download_tags;
1557
+
1558
+ if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1559
+ if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
1479
1560
  goto out;
1480
1561
  }
1481
1562
 
@@ -1483,13 +1564,13 @@ int git_remote_update_tips(
1483
1564
  if (spec->push)
1484
1565
  continue;
1485
1566
 
1486
- if ((error = update_tips_for_spec(remote, spec, &refs, reflog_message)) < 0)
1567
+ if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
1487
1568
  goto out;
1488
1569
  }
1489
1570
 
1490
1571
  /* only try to do opportunisitic updates if the refpec lists differ */
1491
1572
  if (remote->passed_refspecs)
1492
- error = opportunistic_updates(remote, &refs, reflog_message);
1573
+ error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
1493
1574
 
1494
1575
  out:
1495
1576
  git_vector_free(&refs);
@@ -1600,48 +1681,6 @@ int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1600
1681
  return 0;
1601
1682
  }
1602
1683
 
1603
- int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks)
1604
- {
1605
- assert(remote && callbacks);
1606
-
1607
- GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1608
-
1609
- memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
1610
-
1611
- if (remote->transport && remote->transport->set_callbacks)
1612
- return remote->transport->set_callbacks(remote->transport,
1613
- remote->callbacks.sideband_progress,
1614
- NULL,
1615
- remote->callbacks.certificate_check,
1616
- remote->callbacks.payload);
1617
-
1618
- return 0;
1619
- }
1620
-
1621
- const git_remote_callbacks *git_remote_get_callbacks(git_remote *remote)
1622
- {
1623
- assert(remote);
1624
-
1625
- return &remote->callbacks;
1626
- }
1627
-
1628
- int git_remote_set_transport(
1629
- git_remote *remote,
1630
- git_transport_cb transport_cb,
1631
- void *payload)
1632
- {
1633
- assert(remote);
1634
-
1635
- if (remote->transport) {
1636
- giterr_set(GITERR_NET, "A transport is already bound to this remote");
1637
- return -1;
1638
- }
1639
-
1640
- remote->transport_cb = transport_cb;
1641
- remote->transport_cb_payload = payload;
1642
- return 0;
1643
- }
1644
-
1645
1684
  const git_transfer_progress* git_remote_stats(git_remote *remote)
1646
1685
  {
1647
1686
  assert(remote);
@@ -1653,9 +1692,42 @@ git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1653
1692
  return remote->download_tags;
1654
1693
  }
1655
1694
 
1656
- void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value)
1695
+ int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
1657
1696
  {
1658
- remote->download_tags = value;
1697
+ git_buf var = GIT_BUF_INIT;
1698
+ git_config *config;
1699
+ int error;
1700
+
1701
+ assert(repo && remote);
1702
+
1703
+ if ((error = ensure_remote_name_is_valid(remote)) < 0)
1704
+ return error;
1705
+
1706
+ if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1707
+ return error;
1708
+
1709
+ if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
1710
+ return error;
1711
+
1712
+ switch (value) {
1713
+ case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
1714
+ error = git_config_set_string(config, var.ptr, "--no-tags");
1715
+ break;
1716
+ case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
1717
+ error = git_config_set_string(config, var.ptr, "--tags");
1718
+ break;
1719
+ case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
1720
+ error = git_config_delete_entry(config, var.ptr);
1721
+ if (error == GIT_ENOTFOUND)
1722
+ error = 0;
1723
+ break;
1724
+ default:
1725
+ giterr_set(GITERR_INVALID, "Invalid value for the tagopt setting");
1726
+ error = -1;
1727
+ }
1728
+
1729
+ git_buf_free(&var);
1730
+ return error;
1659
1731
  }
1660
1732
 
1661
1733
  int git_remote_prune_refs(const git_remote *remote)
@@ -1926,16 +1998,6 @@ cleanup:
1926
1998
  return error;
1927
1999
  }
1928
2000
 
1929
- int git_remote_update_fetchhead(git_remote *remote)
1930
- {
1931
- return (remote->update_fetchhead != 0);
1932
- }
1933
-
1934
- void git_remote_set_update_fetchhead(git_remote *remote, int value)
1935
- {
1936
- remote->update_fetchhead = (value != 0);
1937
- }
1938
-
1939
2001
  int git_remote_is_valid_name(
1940
2002
  const char *remote_name)
1941
2003
  {
@@ -1988,26 +2050,14 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re
1988
2050
  return NULL;
1989
2051
  }
1990
2052
 
1991
- void git_remote_clear_refspecs(git_remote *remote)
1992
- {
1993
- git_refspec *spec;
1994
- size_t i;
1995
-
1996
- git_vector_foreach(&remote->refspecs, i, spec) {
1997
- git_refspec__free(spec);
1998
- git__free(spec);
1999
- }
2000
- git_vector_clear(&remote->refspecs);
2001
- }
2002
-
2003
- int git_remote_add_fetch(git_remote *remote, const char *refspec)
2053
+ int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
2004
2054
  {
2005
- return add_refspec(remote, refspec, true);
2055
+ return write_add_refspec(repo, remote, refspec, true);
2006
2056
  }
2007
2057
 
2008
- int git_remote_add_push(git_remote *remote, const char *refspec)
2058
+ int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
2009
2059
  {
2010
- return add_refspec(remote, refspec, false);
2060
+ return write_add_refspec(repo, remote, refspec, false);
2011
2061
  }
2012
2062
 
2013
2063
  static int set_refspecs(git_remote *remote, git_strarray *array, int push)
@@ -2038,16 +2088,6 @@ static int set_refspecs(git_remote *remote, git_strarray *array, int push)
2038
2088
  return 0;
2039
2089
  }
2040
2090
 
2041
- int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array)
2042
- {
2043
- return set_refspecs(remote, array, false);
2044
- }
2045
-
2046
- int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array)
2047
- {
2048
- return set_refspecs(remote, array, true);
2049
- }
2050
-
2051
2091
  static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
2052
2092
  {
2053
2093
  size_t i;
@@ -2321,12 +2361,15 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
2321
2361
  int error;
2322
2362
  git_push *push;
2323
2363
  git_refspec *spec;
2324
- git_remote_callbacks *cbs;
2364
+ const git_remote_callbacks *cbs = NULL;
2325
2365
 
2326
2366
  assert(remote);
2327
2367
 
2368
+ if (opts)
2369
+ cbs = &opts->callbacks;
2370
+
2328
2371
  if (!git_remote_connected(remote) &&
2329
- (error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
2372
+ (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
2330
2373
  goto cleanup;
2331
2374
 
2332
2375
  free_refspecs(&remote->active_refspecs);
@@ -2360,17 +2403,10 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
2360
2403
  }
2361
2404
  }
2362
2405
 
2363
- cbs = &remote->callbacks;
2364
- if ((error = git_push_set_callbacks(push,
2365
- cbs->pack_progress, cbs->payload,
2366
- cbs->push_transfer_progress, cbs->payload,
2367
- cbs->push_negotiation, cbs->payload)) < 0)
2406
+ if ((error = git_push_finish(push, cbs)) < 0)
2368
2407
  goto cleanup;
2369
2408
 
2370
- if ((error = git_push_finish(push)) < 0)
2371
- goto cleanup;
2372
-
2373
- if (cbs->push_update_reference &&
2409
+ if (cbs && cbs->push_update_reference &&
2374
2410
  (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
2375
2411
  goto cleanup;
2376
2412
 
@@ -2381,17 +2417,88 @@ cleanup:
2381
2417
  int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2382
2418
  {
2383
2419
  int error;
2420
+ const git_remote_callbacks *cbs = NULL;
2421
+
2422
+ if (opts) {
2423
+ GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2424
+ cbs = &opts->callbacks;
2425
+ }
2384
2426
 
2385
2427
  assert(remote && refspecs);
2386
2428
 
2387
- if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
2429
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
2388
2430
  return error;
2389
2431
 
2390
2432
  if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2391
2433
  return error;
2392
2434
 
2393
- error = git_remote_update_tips(remote, NULL);
2435
+ error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
2394
2436
 
2395
2437
  git_remote_disconnect(remote);
2396
2438
  return error;
2397
2439
  }
2440
+
2441
+ #define PREFIX "url"
2442
+ #define SUFFIX_FETCH "insteadof"
2443
+ #define SUFFIX_PUSH "pushinsteadof"
2444
+
2445
+ char *apply_insteadof(git_config *config, const char *url, int direction)
2446
+ {
2447
+ size_t match_length, prefix_length, suffix_length;
2448
+ char *replacement = NULL;
2449
+ const char *regexp;
2450
+
2451
+ git_buf result = GIT_BUF_INIT;
2452
+ git_config_entry *entry;
2453
+ git_config_iterator *iter;
2454
+
2455
+ assert(config);
2456
+ assert(url);
2457
+ assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
2458
+
2459
+ /* Add 1 to prefix/suffix length due to the additional escaped dot */
2460
+ prefix_length = strlen(PREFIX) + 1;
2461
+ if (direction == GIT_DIRECTION_FETCH) {
2462
+ regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
2463
+ suffix_length = strlen(SUFFIX_FETCH) + 1;
2464
+ } else {
2465
+ regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
2466
+ suffix_length = strlen(SUFFIX_PUSH) + 1;
2467
+ }
2468
+
2469
+ if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
2470
+ return NULL;
2471
+
2472
+ match_length = 0;
2473
+ while (git_config_next(&entry, iter) == 0) {
2474
+ size_t n, replacement_length;
2475
+
2476
+ /* Check if entry value is a prefix of URL */
2477
+ if (git__prefixcmp(url, entry->value))
2478
+ continue;
2479
+ /* Check if entry value is longer than previous
2480
+ * prefixes */
2481
+ if ((n = strlen(entry->value)) <= match_length)
2482
+ continue;
2483
+
2484
+ git__free(replacement);
2485
+ match_length = n;
2486
+
2487
+ /* Cut off prefix and suffix of the value */
2488
+ replacement_length =
2489
+ strlen(entry->name) - (prefix_length + suffix_length);
2490
+ replacement = git__strndup(entry->name + prefix_length,
2491
+ replacement_length);
2492
+ }
2493
+
2494
+ git_config_iterator_free(iter);
2495
+
2496
+ if (match_length == 0)
2497
+ return git__strdup(url);
2498
+
2499
+ git_buf_printf(&result, "%s%s", replacement, url + match_length);
2500
+
2501
+ git__free(replacement);
2502
+
2503
+ return result.ptr;
2504
+ }