rugged 0.23.0b2 → 0.23.0b4

Sign up to get free protection for your applications and to get access to all the features.
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
+ }