rugged 0.19.0 → 0.28.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (668) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/README.md +184 -33
  4. data/ext/rugged/extconf.rb +111 -28
  5. data/ext/rugged/rugged.c +327 -89
  6. data/ext/rugged/rugged.h +64 -28
  7. data/ext/rugged/rugged_allocator.c +89 -0
  8. data/ext/rugged/rugged_backend.c +17 -0
  9. data/ext/rugged/rugged_blame.c +278 -0
  10. data/ext/rugged/rugged_blob.c +301 -75
  11. data/ext/rugged/rugged_branch.c +92 -242
  12. data/ext/rugged/rugged_branch_collection.c +388 -0
  13. data/ext/rugged/rugged_commit.c +575 -79
  14. data/ext/rugged/rugged_config.c +129 -36
  15. data/ext/rugged/rugged_cred.c +131 -0
  16. data/ext/rugged/rugged_diff.c +291 -122
  17. data/ext/rugged/rugged_diff_delta.c +16 -22
  18. data/ext/rugged/rugged_diff_hunk.c +35 -51
  19. data/ext/rugged/rugged_diff_line.c +23 -36
  20. data/ext/rugged/rugged_index.c +289 -152
  21. data/ext/rugged/rugged_note.c +50 -60
  22. data/ext/rugged/rugged_object.c +13 -30
  23. data/ext/rugged/rugged_patch.c +400 -0
  24. data/ext/rugged/rugged_rebase.c +397 -0
  25. data/ext/rugged/rugged_reference.c +76 -346
  26. data/ext/rugged/rugged_reference_collection.c +423 -0
  27. data/ext/rugged/rugged_remote.c +438 -461
  28. data/ext/rugged/rugged_remote_collection.c +435 -0
  29. data/ext/rugged/rugged_repo.c +1548 -365
  30. data/ext/rugged/rugged_revwalk.c +378 -99
  31. data/ext/rugged/rugged_settings.c +86 -23
  32. data/ext/rugged/rugged_signature.c +47 -37
  33. data/ext/rugged/rugged_submodule.c +835 -0
  34. data/ext/rugged/rugged_submodule_collection.c +366 -0
  35. data/ext/rugged/rugged_tag.c +88 -210
  36. data/ext/rugged/rugged_tag_collection.c +326 -0
  37. data/ext/rugged/rugged_tree.c +460 -217
  38. data/lib/rugged/attributes.rb +46 -0
  39. data/lib/rugged/blob.rb +33 -0
  40. data/lib/rugged/branch.rb +12 -16
  41. data/lib/rugged/commit.rb +9 -0
  42. data/lib/rugged/console.rb +5 -0
  43. data/lib/rugged/credentials.rb +48 -0
  44. data/lib/rugged/diff/delta.rb +6 -2
  45. data/lib/rugged/diff/hunk.rb +9 -9
  46. data/lib/rugged/diff/line.rb +28 -5
  47. data/lib/rugged/diff.rb +7 -1
  48. data/lib/rugged/index.rb +120 -0
  49. data/lib/rugged/object.rb +5 -0
  50. data/lib/rugged/patch.rb +41 -0
  51. data/lib/rugged/reference.rb +6 -3
  52. data/lib/rugged/remote.rb +5 -9
  53. data/lib/rugged/repository.rb +126 -14
  54. data/lib/rugged/submodule_collection.rb +53 -0
  55. data/lib/rugged/tag.rb +45 -16
  56. data/lib/rugged/tree.rb +163 -1
  57. data/lib/rugged/version.rb +6 -1
  58. data/lib/rugged/walker.rb +5 -0
  59. data/lib/rugged.rb +16 -1
  60. data/vendor/libgit2/AUTHORS +77 -0
  61. data/vendor/libgit2/CMakeLists.txt +317 -0
  62. data/vendor/libgit2/COPYING +993 -0
  63. data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +30 -0
  64. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.c.in +29 -0
  65. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.cmake +96 -0
  66. data/vendor/libgit2/cmake/Modules/EnableWarnings.cmake +11 -0
  67. data/vendor/libgit2/cmake/Modules/FindCoreFoundation.cmake +26 -0
  68. data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
  69. data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
  70. data/vendor/libgit2/cmake/Modules/FindIconv.cmake +45 -0
  71. data/vendor/libgit2/cmake/Modules/FindPkgLibraries.cmake +28 -0
  72. data/vendor/libgit2/cmake/Modules/FindSecurity.cmake +28 -0
  73. data/vendor/libgit2/cmake/Modules/FindStatNsec.cmake +20 -0
  74. data/vendor/libgit2/cmake/Modules/FindmbedTLS.cmake +93 -0
  75. data/vendor/libgit2/cmake/Modules/IdeSplitSources.cmake +22 -0
  76. data/vendor/libgit2/deps/http-parser/CMakeLists.txt +5 -0
  77. data/vendor/libgit2/deps/http-parser/COPYING +23 -0
  78. data/vendor/libgit2/deps/http-parser/http_parser.c +5 -2
  79. data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
  80. data/vendor/libgit2/deps/regex/CMakeLists.txt +2 -0
  81. data/vendor/libgit2/deps/regex/COPYING +502 -0
  82. data/vendor/libgit2/deps/regex/regex.c +10 -3
  83. data/vendor/libgit2/deps/winhttp/CMakeLists.txt +26 -0
  84. data/vendor/libgit2/deps/winhttp/COPYING.GPL +993 -0
  85. data/vendor/libgit2/deps/winhttp/COPYING.LGPL +502 -0
  86. data/vendor/libgit2/deps/winhttp/urlmon.h +45 -0
  87. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -0
  88. data/vendor/libgit2/deps/winhttp/winhttp.h +594 -0
  89. data/vendor/libgit2/deps/winhttp/winhttp64.def +29 -0
  90. data/vendor/libgit2/deps/zlib/CMakeLists.txt +5 -0
  91. data/vendor/libgit2/deps/zlib/COPYING +27 -0
  92. data/vendor/libgit2/deps/zlib/adler32.c +51 -34
  93. data/vendor/libgit2/deps/zlib/crc32.c +61 -61
  94. data/vendor/libgit2/deps/zlib/crc32.h +1 -1
  95. data/vendor/libgit2/deps/zlib/deflate.c +681 -352
  96. data/vendor/libgit2/deps/zlib/deflate.h +25 -18
  97. data/vendor/libgit2/deps/zlib/gzguts.h +218 -0
  98. data/vendor/libgit2/deps/zlib/infback.c +640 -0
  99. data/vendor/libgit2/deps/zlib/inffast.c +36 -53
  100. data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
  101. data/vendor/libgit2/deps/zlib/inflate.c +167 -86
  102. data/vendor/libgit2/deps/zlib/inflate.h +7 -4
  103. data/vendor/libgit2/deps/zlib/inftrees.c +24 -50
  104. data/vendor/libgit2/deps/zlib/trees.c +55 -96
  105. data/vendor/libgit2/deps/zlib/zconf.h +499 -19
  106. data/vendor/libgit2/deps/zlib/zlib.h +526 -227
  107. data/vendor/libgit2/deps/zlib/zutil.c +39 -32
  108. data/vendor/libgit2/deps/zlib/zutil.h +75 -78
  109. data/vendor/libgit2/include/git2/annotated_commit.h +125 -0
  110. data/vendor/libgit2/include/git2/apply.h +129 -0
  111. data/vendor/libgit2/include/git2/attr.h +36 -21
  112. data/vendor/libgit2/include/git2/blame.h +229 -0
  113. data/vendor/libgit2/include/git2/blob.h +81 -44
  114. data/vendor/libgit2/include/git2/branch.h +81 -42
  115. data/vendor/libgit2/include/git2/buffer.h +128 -0
  116. data/vendor/libgit2/include/git2/checkout.h +141 -67
  117. data/vendor/libgit2/include/git2/cherrypick.h +92 -0
  118. data/vendor/libgit2/include/git2/clone.h +157 -58
  119. data/vendor/libgit2/include/git2/commit.h +231 -12
  120. data/vendor/libgit2/include/git2/common.h +216 -30
  121. data/vendor/libgit2/include/git2/config.h +274 -48
  122. data/vendor/libgit2/include/git2/cred_helpers.h +4 -4
  123. data/vendor/libgit2/include/git2/deprecated.h +253 -0
  124. data/vendor/libgit2/include/git2/describe.h +189 -0
  125. data/vendor/libgit2/include/git2/diff.h +985 -575
  126. data/vendor/libgit2/include/git2/errors.h +93 -52
  127. data/vendor/libgit2/include/git2/filter.h +217 -0
  128. data/vendor/libgit2/include/git2/global.h +44 -0
  129. data/vendor/libgit2/include/git2/graph.h +17 -0
  130. data/vendor/libgit2/include/git2/ignore.h +2 -2
  131. data/vendor/libgit2/include/git2/index.h +269 -94
  132. data/vendor/libgit2/include/git2/indexer.h +44 -12
  133. data/vendor/libgit2/include/git2/mailmap.h +115 -0
  134. data/vendor/libgit2/include/git2/merge.h +501 -64
  135. data/vendor/libgit2/include/git2/message.h +52 -17
  136. data/vendor/libgit2/include/git2/net.h +11 -5
  137. data/vendor/libgit2/include/git2/notes.h +120 -16
  138. data/vendor/libgit2/include/git2/object.h +62 -23
  139. data/vendor/libgit2/include/git2/odb.h +140 -24
  140. data/vendor/libgit2/include/git2/odb_backend.h +56 -12
  141. data/vendor/libgit2/include/git2/oid.h +17 -18
  142. data/vendor/libgit2/include/git2/oidarray.h +40 -0
  143. data/vendor/libgit2/include/git2/pack.h +86 -7
  144. data/vendor/libgit2/include/git2/patch.h +274 -0
  145. data/vendor/libgit2/include/git2/pathspec.h +280 -0
  146. data/vendor/libgit2/include/git2/proxy.h +96 -0
  147. data/vendor/libgit2/include/git2/rebase.h +323 -0
  148. data/vendor/libgit2/include/git2/reflog.h +12 -9
  149. data/vendor/libgit2/include/git2/refs.h +241 -46
  150. data/vendor/libgit2/include/git2/refspec.h +20 -4
  151. data/vendor/libgit2/include/git2/remote.h +636 -209
  152. data/vendor/libgit2/include/git2/repository.h +267 -57
  153. data/vendor/libgit2/include/git2/reset.h +36 -6
  154. data/vendor/libgit2/include/git2/revert.h +91 -0
  155. data/vendor/libgit2/include/git2/revparse.h +27 -16
  156. data/vendor/libgit2/include/git2/revwalk.h +78 -35
  157. data/vendor/libgit2/include/git2/signature.h +32 -5
  158. data/vendor/libgit2/include/git2/stash.h +160 -21
  159. data/vendor/libgit2/include/git2/status.h +92 -30
  160. data/vendor/libgit2/include/git2/submodule.h +226 -133
  161. data/vendor/libgit2/include/git2/sys/alloc.h +101 -0
  162. data/vendor/libgit2/include/git2/sys/commit.h +38 -4
  163. data/vendor/libgit2/include/git2/sys/config.h +68 -9
  164. data/vendor/libgit2/include/git2/sys/diff.h +94 -0
  165. data/vendor/libgit2/include/git2/sys/filter.h +332 -0
  166. data/vendor/libgit2/include/git2/sys/hashsig.h +106 -0
  167. data/vendor/libgit2/include/git2/sys/index.h +6 -5
  168. data/vendor/libgit2/include/git2/sys/mempack.h +86 -0
  169. data/vendor/libgit2/include/git2/sys/merge.h +182 -0
  170. data/vendor/libgit2/include/git2/sys/odb_backend.h +66 -28
  171. data/vendor/libgit2/include/git2/sys/openssl.h +38 -0
  172. data/vendor/libgit2/include/git2/sys/path.h +64 -0
  173. data/vendor/libgit2/include/git2/sys/refdb_backend.h +79 -19
  174. data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
  175. data/vendor/libgit2/include/git2/sys/refs.h +13 -2
  176. data/vendor/libgit2/include/git2/sys/repository.h +64 -1
  177. data/vendor/libgit2/include/git2/sys/stream.h +138 -0
  178. data/vendor/libgit2/include/git2/sys/time.h +31 -0
  179. data/vendor/libgit2/include/git2/sys/transport.h +439 -0
  180. data/vendor/libgit2/include/git2/tag.h +11 -2
  181. data/vendor/libgit2/include/git2/trace.h +1 -1
  182. data/vendor/libgit2/include/git2/transaction.h +121 -0
  183. data/vendor/libgit2/include/git2/transport.h +261 -292
  184. data/vendor/libgit2/include/git2/tree.h +111 -21
  185. data/vendor/libgit2/include/git2/types.h +244 -32
  186. data/vendor/libgit2/include/git2/version.h +5 -2
  187. data/vendor/libgit2/include/git2/worktree.h +255 -0
  188. data/vendor/libgit2/include/git2.h +50 -40
  189. data/vendor/libgit2/libgit2.pc.in +13 -0
  190. data/vendor/libgit2/src/CMakeLists.txt +525 -0
  191. data/vendor/libgit2/src/alloc.c +55 -0
  192. data/vendor/libgit2/src/alloc.h +40 -0
  193. data/vendor/libgit2/src/annotated_commit.c +228 -0
  194. data/vendor/libgit2/src/annotated_commit.h +52 -0
  195. data/vendor/libgit2/src/apply.c +855 -0
  196. data/vendor/libgit2/src/apply.h +25 -0
  197. data/vendor/libgit2/src/array.h +74 -16
  198. data/vendor/libgit2/src/attr.c +239 -408
  199. data/vendor/libgit2/src/attr.h +3 -33
  200. data/vendor/libgit2/src/attr_file.c +424 -156
  201. data/vendor/libgit2/src/attr_file.h +95 -23
  202. data/vendor/libgit2/src/attrcache.c +469 -0
  203. data/vendor/libgit2/src/attrcache.h +37 -5
  204. data/vendor/libgit2/src/bitvec.h +75 -0
  205. data/vendor/libgit2/src/blame.c +532 -0
  206. data/vendor/libgit2/src/blame.h +95 -0
  207. data/vendor/libgit2/src/blame_git.c +668 -0
  208. data/vendor/libgit2/src/blame_git.h +22 -0
  209. data/vendor/libgit2/src/blob.c +233 -129
  210. data/vendor/libgit2/src/blob.h +29 -1
  211. data/vendor/libgit2/src/branch.c +295 -197
  212. data/vendor/libgit2/src/branch.h +2 -0
  213. data/vendor/libgit2/src/buf_text.c +52 -27
  214. data/vendor/libgit2/src/buf_text.h +7 -7
  215. data/vendor/libgit2/src/buffer.c +609 -52
  216. data/vendor/libgit2/src/buffer.h +68 -23
  217. data/vendor/libgit2/src/cache.c +48 -51
  218. data/vendor/libgit2/src/cache.h +6 -4
  219. data/vendor/libgit2/src/cc-compat.h +35 -7
  220. data/vendor/libgit2/src/checkout.c +1827 -483
  221. data/vendor/libgit2/src/checkout.h +4 -1
  222. data/vendor/libgit2/src/cherrypick.c +230 -0
  223. data/vendor/libgit2/src/clone.c +338 -258
  224. data/vendor/libgit2/src/{compress.h → clone.h} +5 -5
  225. data/vendor/libgit2/src/commit.c +711 -124
  226. data/vendor/libgit2/src/commit.h +10 -3
  227. data/vendor/libgit2/src/commit_list.c +21 -14
  228. data/vendor/libgit2/src/commit_list.h +9 -3
  229. data/vendor/libgit2/src/common.h +153 -13
  230. data/vendor/libgit2/src/config.c +871 -242
  231. data/vendor/libgit2/src/config.h +58 -14
  232. data/vendor/libgit2/src/config_backend.h +84 -0
  233. data/vendor/libgit2/src/config_cache.c +44 -18
  234. data/vendor/libgit2/src/config_entries.c +259 -0
  235. data/vendor/libgit2/src/config_entries.h +23 -0
  236. data/vendor/libgit2/src/config_file.c +837 -1113
  237. data/vendor/libgit2/src/config_mem.c +224 -0
  238. data/vendor/libgit2/src/config_parse.c +558 -0
  239. data/vendor/libgit2/src/config_parse.h +64 -0
  240. data/vendor/libgit2/src/crlf.c +290 -195
  241. data/vendor/libgit2/src/date.c +35 -7
  242. data/vendor/libgit2/src/delta.c +275 -71
  243. data/vendor/libgit2/src/delta.h +80 -58
  244. data/vendor/libgit2/src/describe.c +893 -0
  245. data/vendor/libgit2/src/diff.c +330 -1128
  246. data/vendor/libgit2/src/diff.h +25 -67
  247. data/vendor/libgit2/src/diff_driver.c +225 -109
  248. data/vendor/libgit2/src/diff_driver.h +5 -2
  249. data/vendor/libgit2/src/diff_file.c +128 -103
  250. data/vendor/libgit2/src/diff_file.h +17 -12
  251. data/vendor/libgit2/src/diff_generate.c +1622 -0
  252. data/vendor/libgit2/src/diff_generate.h +128 -0
  253. data/vendor/libgit2/src/diff_parse.c +108 -0
  254. data/vendor/libgit2/src/diff_parse.h +20 -0
  255. data/vendor/libgit2/src/diff_print.c +578 -218
  256. data/vendor/libgit2/src/diff_stats.c +362 -0
  257. data/vendor/libgit2/src/diff_tform.c +429 -257
  258. data/vendor/libgit2/src/diff_tform.h +25 -0
  259. data/vendor/libgit2/src/diff_xdiff.c +143 -46
  260. data/vendor/libgit2/src/diff_xdiff.h +12 -5
  261. data/vendor/libgit2/src/errors.c +150 -34
  262. data/vendor/libgit2/src/features.h.in +37 -0
  263. data/vendor/libgit2/src/fetch.c +69 -46
  264. data/vendor/libgit2/src/fetch.h +6 -12
  265. data/vendor/libgit2/src/fetchhead.c +40 -33
  266. data/vendor/libgit2/src/fetchhead.h +5 -4
  267. data/vendor/libgit2/src/filebuf.c +163 -61
  268. data/vendor/libgit2/src/filebuf.h +13 -7
  269. data/vendor/libgit2/src/fileops.c +549 -407
  270. data/vendor/libgit2/src/fileops.h +97 -106
  271. data/vendor/libgit2/src/filter.c +989 -46
  272. data/vendor/libgit2/src/filter.h +21 -70
  273. data/vendor/libgit2/src/fnmatch.c +67 -11
  274. data/vendor/libgit2/src/fnmatch.h +27 -7
  275. data/vendor/libgit2/src/global.c +257 -63
  276. data/vendor/libgit2/src/global.h +19 -0
  277. data/vendor/libgit2/src/graph.c +39 -23
  278. data/vendor/libgit2/src/hash/hash_collisiondetect.h +51 -0
  279. data/vendor/libgit2/src/hash/hash_common_crypto.h +61 -0
  280. data/vendor/libgit2/src/hash/hash_generic.c +3 -3
  281. data/vendor/libgit2/src/hash/hash_generic.h +10 -5
  282. data/vendor/libgit2/src/hash/hash_mbedtls.c +38 -0
  283. data/vendor/libgit2/src/hash/hash_mbedtls.h +24 -0
  284. data/vendor/libgit2/src/hash/hash_openssl.h +26 -8
  285. data/vendor/libgit2/src/hash/hash_win32.c +71 -43
  286. data/vendor/libgit2/src/hash/hash_win32.h +4 -3
  287. data/vendor/libgit2/src/hash/sha1dc/sha1.c +1900 -0
  288. data/vendor/libgit2/src/hash/sha1dc/sha1.h +110 -0
  289. data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +372 -0
  290. data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +52 -0
  291. data/vendor/libgit2/src/hash.c +0 -1
  292. data/vendor/libgit2/src/hash.h +13 -6
  293. data/vendor/libgit2/src/hashsig.c +121 -126
  294. data/vendor/libgit2/src/ident.c +129 -0
  295. data/vendor/libgit2/src/idxmap.c +153 -0
  296. data/vendor/libgit2/src/idxmap.h +41 -0
  297. data/vendor/libgit2/src/ignore.c +362 -123
  298. data/vendor/libgit2/src/ignore.h +16 -4
  299. data/vendor/libgit2/src/index.c +2131 -692
  300. data/vendor/libgit2/src/index.h +138 -6
  301. data/vendor/libgit2/src/indexer.c +866 -266
  302. data/vendor/libgit2/src/indexer.h +16 -0
  303. data/vendor/libgit2/src/integer.h +106 -0
  304. data/vendor/libgit2/src/iterator.c +1888 -967
  305. data/vendor/libgit2/src/iterator.h +130 -67
  306. data/vendor/libgit2/src/khash.h +43 -29
  307. data/vendor/libgit2/src/mailmap.c +485 -0
  308. data/vendor/libgit2/src/mailmap.h +35 -0
  309. data/vendor/libgit2/src/map.h +1 -1
  310. data/vendor/libgit2/src/merge.c +1679 -479
  311. data/vendor/libgit2/src/merge.h +89 -22
  312. data/vendor/libgit2/src/merge_driver.c +426 -0
  313. data/vendor/libgit2/src/merge_driver.h +62 -0
  314. data/vendor/libgit2/src/merge_file.c +238 -101
  315. data/vendor/libgit2/src/message.c +4 -28
  316. data/vendor/libgit2/src/message.h +3 -1
  317. data/vendor/libgit2/src/mwindow.c +123 -15
  318. data/vendor/libgit2/src/mwindow.h +10 -1
  319. data/vendor/libgit2/src/netops.c +178 -499
  320. data/vendor/libgit2/src/netops.h +51 -27
  321. data/vendor/libgit2/src/notes.c +251 -94
  322. data/vendor/libgit2/src/notes.h +5 -2
  323. data/vendor/libgit2/src/object.c +253 -67
  324. data/vendor/libgit2/src/object.h +40 -2
  325. data/vendor/libgit2/src/object_api.c +30 -11
  326. data/vendor/libgit2/src/odb.c +765 -201
  327. data/vendor/libgit2/src/odb.h +40 -8
  328. data/vendor/libgit2/src/odb_loose.c +560 -346
  329. data/vendor/libgit2/src/odb_mempack.c +185 -0
  330. data/vendor/libgit2/src/odb_pack.c +117 -73
  331. data/vendor/libgit2/src/offmap.c +113 -0
  332. data/vendor/libgit2/src/offmap.h +32 -42
  333. data/vendor/libgit2/src/oid.c +45 -25
  334. data/vendor/libgit2/src/oid.h +26 -8
  335. data/vendor/libgit2/src/oidarray.c +34 -0
  336. data/vendor/libgit2/src/oidarray.h +20 -0
  337. data/vendor/libgit2/src/oidmap.c +125 -0
  338. data/vendor/libgit2/src/oidmap.h +30 -17
  339. data/vendor/libgit2/src/pack-objects.c +688 -265
  340. data/vendor/libgit2/src/pack-objects.h +27 -13
  341. data/vendor/libgit2/src/pack.c +418 -202
  342. data/vendor/libgit2/src/pack.h +25 -16
  343. data/vendor/libgit2/src/parse.c +124 -0
  344. data/vendor/libgit2/src/parse.h +61 -0
  345. data/vendor/libgit2/src/patch.c +223 -0
  346. data/vendor/libgit2/src/patch.h +68 -0
  347. data/vendor/libgit2/src/patch_generate.c +901 -0
  348. data/vendor/libgit2/src/patch_generate.h +69 -0
  349. data/vendor/libgit2/src/patch_parse.c +1136 -0
  350. data/vendor/libgit2/src/patch_parse.h +51 -0
  351. data/vendor/libgit2/src/path.c +1247 -241
  352. data/vendor/libgit2/src/path.h +353 -57
  353. data/vendor/libgit2/src/pathspec.c +586 -58
  354. data/vendor/libgit2/src/pathspec.h +37 -15
  355. data/vendor/libgit2/src/pool.c +134 -221
  356. data/vendor/libgit2/src/pool.h +38 -50
  357. data/vendor/libgit2/src/posix.c +76 -10
  358. data/vendor/libgit2/src/posix.h +74 -32
  359. data/vendor/libgit2/src/pqueue.c +79 -117
  360. data/vendor/libgit2/src/pqueue.h +38 -82
  361. data/vendor/libgit2/src/proxy.c +39 -0
  362. data/vendor/libgit2/src/proxy.h +17 -0
  363. data/vendor/libgit2/src/push.c +178 -279
  364. data/vendor/libgit2/src/push.h +93 -4
  365. data/vendor/libgit2/src/reader.c +265 -0
  366. data/vendor/libgit2/src/reader.h +107 -0
  367. data/vendor/libgit2/src/rebase.c +1364 -0
  368. data/vendor/libgit2/src/refdb.c +74 -19
  369. data/vendor/libgit2/src/refdb.h +16 -3
  370. data/vendor/libgit2/src/refdb_fs.c +1472 -603
  371. data/vendor/libgit2/src/refdb_fs.h +4 -0
  372. data/vendor/libgit2/src/reflog.c +40 -330
  373. data/vendor/libgit2/src/reflog.h +8 -2
  374. data/vendor/libgit2/src/refs.c +641 -225
  375. data/vendor/libgit2/src/refs.h +53 -6
  376. data/vendor/libgit2/src/refspec.c +175 -62
  377. data/vendor/libgit2/src/refspec.h +10 -25
  378. data/vendor/libgit2/src/remote.c +1741 -723
  379. data/vendor/libgit2/src/remote.h +17 -5
  380. data/vendor/libgit2/src/repository.c +1505 -421
  381. data/vendor/libgit2/src/repository.h +95 -15
  382. data/vendor/libgit2/src/reset.c +63 -26
  383. data/vendor/libgit2/src/revert.c +232 -0
  384. data/vendor/libgit2/src/revparse.c +94 -80
  385. data/vendor/libgit2/src/revwalk.c +427 -194
  386. data/vendor/libgit2/src/revwalk.h +14 -5
  387. data/vendor/libgit2/src/settings.c +290 -0
  388. data/vendor/libgit2/src/sha1_lookup.c +16 -159
  389. data/vendor/libgit2/src/sha1_lookup.h +5 -4
  390. data/vendor/libgit2/src/signature.c +138 -26
  391. data/vendor/libgit2/src/signature.h +5 -0
  392. data/vendor/libgit2/src/sortedcache.c +395 -0
  393. data/vendor/libgit2/src/sortedcache.h +180 -0
  394. data/vendor/libgit2/src/stash.c +629 -168
  395. data/vendor/libgit2/src/status.c +125 -75
  396. data/vendor/libgit2/src/status.h +4 -2
  397. data/vendor/libgit2/src/stdalloc.c +120 -0
  398. data/vendor/libgit2/src/stdalloc.h +17 -0
  399. data/vendor/libgit2/src/stream.h +86 -0
  400. data/vendor/libgit2/src/streams/mbedtls.c +483 -0
  401. data/vendor/libgit2/src/streams/mbedtls.h +23 -0
  402. data/vendor/libgit2/src/streams/openssl.c +789 -0
  403. data/vendor/libgit2/src/streams/openssl.h +23 -0
  404. data/vendor/libgit2/src/streams/registry.c +118 -0
  405. data/vendor/libgit2/src/streams/registry.h +19 -0
  406. data/vendor/libgit2/src/streams/socket.c +235 -0
  407. data/vendor/libgit2/src/streams/socket.h +23 -0
  408. data/vendor/libgit2/src/streams/stransport.c +323 -0
  409. data/vendor/libgit2/src/streams/stransport.h +21 -0
  410. data/vendor/libgit2/src/streams/tls.c +73 -0
  411. data/vendor/libgit2/src/streams/tls.h +31 -0
  412. data/vendor/libgit2/src/strmap.c +147 -0
  413. data/vendor/libgit2/src/strmap.h +46 -51
  414. data/vendor/libgit2/src/strnlen.h +24 -0
  415. data/vendor/libgit2/src/submodule.c +1633 -877
  416. data/vendor/libgit2/src/submodule.h +83 -21
  417. data/vendor/libgit2/src/sysdir.c +355 -0
  418. data/vendor/libgit2/src/sysdir.h +119 -0
  419. data/vendor/libgit2/src/tag.c +87 -62
  420. data/vendor/libgit2/src/tag.h +4 -1
  421. data/vendor/libgit2/src/thread-utils.c +3 -0
  422. data/vendor/libgit2/src/thread-utils.h +71 -35
  423. data/vendor/libgit2/src/trace.c +4 -4
  424. data/vendor/libgit2/src/trace.h +11 -3
  425. data/vendor/libgit2/src/trailer.c +416 -0
  426. data/vendor/libgit2/src/transaction.c +382 -0
  427. data/vendor/libgit2/src/transaction.h +14 -0
  428. data/vendor/libgit2/src/transport.c +133 -67
  429. data/vendor/libgit2/src/transports/auth.c +75 -0
  430. data/vendor/libgit2/src/transports/auth.h +64 -0
  431. data/vendor/libgit2/src/transports/auth_negotiate.c +277 -0
  432. data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
  433. data/vendor/libgit2/src/transports/cred.c +296 -68
  434. data/vendor/libgit2/src/transports/cred.h +16 -0
  435. data/vendor/libgit2/src/transports/cred_helpers.c +4 -0
  436. data/vendor/libgit2/src/transports/git.c +108 -90
  437. data/vendor/libgit2/src/transports/http.c +803 -258
  438. data/vendor/libgit2/src/transports/http.h +25 -0
  439. data/vendor/libgit2/src/transports/local.c +265 -169
  440. data/vendor/libgit2/src/transports/smart.c +255 -45
  441. data/vendor/libgit2/src/transports/smart.h +42 -22
  442. data/vendor/libgit2/src/transports/smart_pkt.c +250 -159
  443. data/vendor/libgit2/src/transports/smart_protocol.c +414 -196
  444. data/vendor/libgit2/src/transports/ssh.c +645 -236
  445. data/vendor/libgit2/src/transports/ssh.h +14 -0
  446. data/vendor/libgit2/src/transports/winhttp.c +809 -353
  447. data/vendor/libgit2/src/tree-cache.c +138 -52
  448. data/vendor/libgit2/src/tree-cache.h +14 -7
  449. data/vendor/libgit2/src/tree.c +620 -259
  450. data/vendor/libgit2/src/tree.h +12 -19
  451. data/vendor/libgit2/src/tsort.c +3 -2
  452. data/vendor/libgit2/src/unix/map.c +25 -7
  453. data/vendor/libgit2/src/unix/posix.h +77 -12
  454. data/vendor/libgit2/src/unix/pthread.h +56 -0
  455. data/vendor/libgit2/src/unix/realpath.c +12 -8
  456. data/vendor/libgit2/src/userdiff.h +208 -0
  457. data/vendor/libgit2/src/util.c +349 -165
  458. data/vendor/libgit2/src/util.h +167 -85
  459. data/vendor/libgit2/src/varint.c +43 -0
  460. data/vendor/libgit2/src/varint.h +17 -0
  461. data/vendor/libgit2/src/vector.c +156 -33
  462. data/vendor/libgit2/src/vector.h +41 -5
  463. data/vendor/libgit2/src/win32/dir.c +22 -42
  464. data/vendor/libgit2/src/win32/dir.h +7 -5
  465. data/vendor/libgit2/src/win32/error.c +6 -32
  466. data/vendor/libgit2/src/win32/error.h +4 -2
  467. data/vendor/libgit2/src/win32/findfile.c +62 -69
  468. data/vendor/libgit2/src/win32/findfile.h +5 -13
  469. data/vendor/libgit2/src/win32/git2.rc +44 -0
  470. data/vendor/libgit2/src/win32/map.c +39 -11
  471. data/vendor/libgit2/src/win32/mingw-compat.h +10 -11
  472. data/vendor/libgit2/src/win32/msvc-compat.h +10 -33
  473. data/vendor/libgit2/src/win32/path_w32.c +476 -0
  474. data/vendor/libgit2/src/win32/path_w32.h +104 -0
  475. data/vendor/libgit2/src/win32/posix.h +35 -30
  476. data/vendor/libgit2/src/win32/posix_w32.c +659 -327
  477. data/vendor/libgit2/src/win32/precompiled.h +7 -2
  478. data/vendor/libgit2/src/win32/reparse.h +57 -0
  479. data/vendor/libgit2/src/win32/thread.c +258 -0
  480. data/vendor/libgit2/src/win32/thread.h +64 -0
  481. data/vendor/libgit2/src/win32/utf-conv.c +127 -62
  482. data/vendor/libgit2/src/win32/utf-conv.h +47 -6
  483. data/vendor/libgit2/src/win32/version.h +21 -4
  484. data/vendor/libgit2/src/win32/w32_buffer.c +54 -0
  485. data/vendor/libgit2/src/win32/w32_buffer.h +20 -0
  486. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +438 -0
  487. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +129 -0
  488. data/vendor/libgit2/src/win32/w32_stack.c +193 -0
  489. data/vendor/libgit2/src/win32/w32_stack.h +140 -0
  490. data/vendor/libgit2/src/win32/w32_util.c +95 -0
  491. data/vendor/libgit2/src/win32/w32_util.h +170 -0
  492. data/vendor/libgit2/src/win32/win32-compat.h +52 -0
  493. data/vendor/libgit2/src/worktree.c +578 -0
  494. data/vendor/libgit2/src/worktree.h +39 -0
  495. data/vendor/libgit2/src/xdiff/xdiff.h +33 -18
  496. data/vendor/libgit2/src/xdiff/xdiffi.c +578 -88
  497. data/vendor/libgit2/src/xdiff/xdiffi.h +3 -2
  498. data/vendor/libgit2/src/xdiff/xemit.c +106 -45
  499. data/vendor/libgit2/src/xdiff/xemit.h +3 -3
  500. data/vendor/libgit2/src/xdiff/xhistogram.c +5 -4
  501. data/vendor/libgit2/src/xdiff/xinclude.h +3 -2
  502. data/vendor/libgit2/src/xdiff/xmacros.h +2 -2
  503. data/vendor/libgit2/src/xdiff/xmerge.c +167 -48
  504. data/vendor/libgit2/src/xdiff/xpatience.c +42 -10
  505. data/vendor/libgit2/src/xdiff/xprepare.c +14 -14
  506. data/vendor/libgit2/src/xdiff/xprepare.h +2 -2
  507. data/vendor/libgit2/src/xdiff/xtypes.h +2 -2
  508. data/vendor/libgit2/src/xdiff/xutils.c +60 -56
  509. data/vendor/libgit2/src/xdiff/xutils.h +3 -5
  510. data/vendor/libgit2/src/zstream.c +205 -0
  511. data/vendor/libgit2/src/zstream.h +53 -0
  512. metadata +281 -233
  513. data/Rakefile +0 -61
  514. data/ext/rugged/rugged_diff_patch.c +0 -169
  515. data/lib/rugged/diff/patch.rb +0 -28
  516. data/test/blob_test.rb +0 -341
  517. data/test/branch_test.rb +0 -199
  518. data/test/commit_test.rb +0 -104
  519. data/test/config_test.rb +0 -45
  520. data/test/coverage/cover.rb +0 -133
  521. data/test/diff_test.rb +0 -777
  522. data/test/errors_test.rb +0 -34
  523. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  524. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  525. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  526. data/test/fixtures/archive.tar.gz +0 -0
  527. data/test/fixtures/attr/attr0 +0 -1
  528. data/test/fixtures/attr/attr1 +0 -29
  529. data/test/fixtures/attr/attr2 +0 -21
  530. data/test/fixtures/attr/attr3 +0 -4
  531. data/test/fixtures/attr/binfile +0 -1
  532. data/test/fixtures/attr/dir/file +0 -0
  533. data/test/fixtures/attr/file +0 -1
  534. data/test/fixtures/attr/gitattributes +0 -29
  535. data/test/fixtures/attr/gitignore +0 -2
  536. data/test/fixtures/attr/ign +0 -1
  537. data/test/fixtures/attr/macro_bad +0 -1
  538. data/test/fixtures/attr/macro_test +0 -1
  539. data/test/fixtures/attr/root_test1 +0 -1
  540. data/test/fixtures/attr/root_test2 +0 -6
  541. data/test/fixtures/attr/root_test3 +0 -19
  542. data/test/fixtures/attr/root_test4.txt +0 -14
  543. data/test/fixtures/attr/sub/abc +0 -37
  544. data/test/fixtures/attr/sub/dir/file +0 -0
  545. data/test/fixtures/attr/sub/file +0 -1
  546. data/test/fixtures/attr/sub/ign/file +0 -1
  547. data/test/fixtures/attr/sub/ign/sub/file +0 -1
  548. data/test/fixtures/attr/sub/sub/dir +0 -0
  549. data/test/fixtures/attr/sub/sub/file +0 -1
  550. data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
  551. data/test/fixtures/attr/sub/subdir_test1 +0 -2
  552. data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
  553. data/test/fixtures/diff/another.txt +0 -38
  554. data/test/fixtures/diff/readme.txt +0 -36
  555. data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
  556. data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
  557. data/test/fixtures/mergedrepo/one.txt +0 -10
  558. data/test/fixtures/mergedrepo/two.txt +0 -12
  559. data/test/fixtures/status/current_file +0 -1
  560. data/test/fixtures/status/ignored_file +0 -1
  561. data/test/fixtures/status/modified_file +0 -2
  562. data/test/fixtures/status/new_file +0 -1
  563. data/test/fixtures/status/staged_changes +0 -2
  564. data/test/fixtures/status/staged_changes_modified_file +0 -3
  565. data/test/fixtures/status/staged_delete_modified_file +0 -1
  566. data/test/fixtures/status/staged_new_file +0 -1
  567. data/test/fixtures/status/staged_new_file_modified_file +0 -2
  568. data/test/fixtures/status/subdir/current_file +0 -1
  569. data/test/fixtures/status/subdir/modified_file +0 -2
  570. data/test/fixtures/status/subdir/new_file +0 -1
  571. data/test/fixtures/status/subdir.txt +0 -2
  572. data/test/fixtures/status//350/277/231 +0 -1
  573. data/test/fixtures/testrepo.git/HEAD +0 -1
  574. data/test/fixtures/testrepo.git/config +0 -13
  575. data/test/fixtures/testrepo.git/description +0 -1
  576. data/test/fixtures/testrepo.git/index +0 -0
  577. data/test/fixtures/testrepo.git/info/exclude +0 -6
  578. data/test/fixtures/testrepo.git/logs/HEAD +0 -3
  579. data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
  580. data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
  581. data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
  582. data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
  583. data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
  584. data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
  585. data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
  586. data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
  587. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
  588. data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
  589. data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
  590. data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
  591. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  592. data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
  593. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
  594. data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
  595. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  596. data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
  597. data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -0
  598. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  599. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  600. data/test/fixtures/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
  601. data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
  602. data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
  603. data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
  604. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
  605. data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
  606. data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
  607. data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
  608. data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  609. data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
  610. data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
  611. data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
  612. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
  613. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
  614. data/test/fixtures/testrepo.git/packed-refs +0 -2
  615. data/test/fixtures/testrepo.git/refs/heads/master +0 -1
  616. data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
  617. data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
  618. data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
  619. data/test/fixtures/text_file.md +0 -464
  620. data/test/fixtures/unsymlinked.git/HEAD +0 -1
  621. data/test/fixtures/unsymlinked.git/config +0 -6
  622. data/test/fixtures/unsymlinked.git/description +0 -1
  623. data/test/fixtures/unsymlinked.git/info/exclude +0 -2
  624. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  625. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  626. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  627. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  628. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  629. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  630. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  631. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  632. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  633. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
  634. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  635. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  636. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  637. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  638. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
  639. data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
  640. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
  641. data/test/index_test.rb +0 -333
  642. data/test/lib_test.rb +0 -127
  643. data/test/note_test.rb +0 -158
  644. data/test/object_test.rb +0 -43
  645. data/test/reference_test.rb +0 -207
  646. data/test/remote_test.rb +0 -324
  647. data/test/repo_pack_test.rb +0 -24
  648. data/test/repo_reset_test.rb +0 -82
  649. data/test/repo_test.rb +0 -402
  650. data/test/tag_test.rb +0 -68
  651. data/test/test_helper.rb +0 -92
  652. data/test/tree_test.rb +0 -91
  653. data/test/walker_test.rb +0 -88
  654. data/vendor/libgit2/Makefile.embed +0 -42
  655. data/vendor/libgit2/include/git2/push.h +0 -131
  656. data/vendor/libgit2/include/git2/threads.h +0 -50
  657. data/vendor/libgit2/src/amiga/map.c +0 -48
  658. data/vendor/libgit2/src/bswap.h +0 -97
  659. data/vendor/libgit2/src/compress.c +0 -53
  660. data/vendor/libgit2/src/config_file.h +0 -60
  661. data/vendor/libgit2/src/delta-apply.c +0 -134
  662. data/vendor/libgit2/src/delta-apply.h +0 -50
  663. data/vendor/libgit2/src/diff_patch.c +0 -995
  664. data/vendor/libgit2/src/diff_patch.h +0 -46
  665. data/vendor/libgit2/src/hashsig.h +0 -72
  666. data/vendor/libgit2/src/merge_file.h +0 -71
  667. data/vendor/libgit2/src/win32/pthread.c +0 -144
  668. data/vendor/libgit2/src/win32/pthread.h +0 -50
@@ -5,6 +5,8 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
+ #include "remote.h"
9
+
8
10
  #include "git2/config.h"
9
11
  #include "git2/types.h"
10
12
  #include "git2/oid.h"
@@ -12,20 +14,28 @@
12
14
 
13
15
  #include "config.h"
14
16
  #include "repository.h"
15
- #include "remote.h"
16
17
  #include "fetch.h"
17
18
  #include "refs.h"
18
19
  #include "refspec.h"
19
20
  #include "fetchhead.h"
21
+ #include "push.h"
20
22
 
21
- #include <regex.h>
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"
22
28
 
23
- static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
29
+ static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
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);
32
+
33
+ static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
24
34
  {
25
35
  git_refspec *spec;
26
36
 
27
37
  spec = git__calloc(1, sizeof(git_refspec));
28
- GITERR_CHECK_ALLOC(spec);
38
+ GIT_ERROR_CHECK_ALLOC(spec);
29
39
 
30
40
  if (git_refspec__parse(spec, string, is_fetch) < 0) {
31
41
  git__free(spec);
@@ -33,8 +43,8 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
33
43
  }
34
44
 
35
45
  spec->push = !is_fetch;
36
- if (git_vector_insert(&remote->refspecs, spec) < 0) {
37
- git_refspec__free(spec);
46
+ if (git_vector_insert(vector, spec) < 0) {
47
+ git_refspec__dispose(spec);
38
48
  git__free(spec);
39
49
  return -1;
40
50
  }
@@ -42,28 +52,31 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
42
52
  return 0;
43
53
  }
44
54
 
55
+ static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
56
+ {
57
+ return add_refspec_to(&remote->refspecs, string, is_fetch);
58
+ }
59
+
45
60
  static int download_tags_value(git_remote *remote, git_config *cfg)
46
61
  {
47
- const char *val;
62
+ git_config_entry *ce;
48
63
  git_buf buf = GIT_BUF_INIT;
49
64
  int error;
50
65
 
51
- /* The 0 value is the default (auto), let's see if we need to change it */
52
66
  if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
53
67
  return -1;
54
68
 
55
- error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
56
- git_buf_free(&buf);
57
- if (!error && !strcmp(val, "--no-tags"))
58
- remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
59
- else if (!error && !strcmp(val, "--tags"))
60
- remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
69
+ error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
70
+ git_buf_dispose(&buf);
61
71
 
62
- if (error == GIT_ENOTFOUND) {
63
- giterr_clear();
64
- error = 0;
72
+ if (!error && ce && ce->value) {
73
+ if (!strcmp(ce->value, "--no-tags"))
74
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
75
+ else if (!strcmp(ce->value, "--tags"))
76
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
65
77
  }
66
78
 
79
+ git_config_entry_free(ce);
67
80
  return error;
68
81
  }
69
82
 
@@ -72,59 +85,116 @@ static int ensure_remote_name_is_valid(const char *name)
72
85
  int error = 0;
73
86
 
74
87
  if (!git_remote_is_valid_name(name)) {
75
- giterr_set(
76
- GITERR_CONFIG,
77
- "'%s' is not a valid remote name.", name);
88
+ git_error_set(
89
+ GIT_ERROR_CONFIG,
90
+ "'%s' is not a valid remote name.", name ? name : "(null)");
78
91
  error = GIT_EINVALIDSPEC;
79
92
  }
80
93
 
81
94
  return error;
82
95
  }
83
96
 
84
- static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
97
+ static int write_add_refspec(git_repository *repo, const char *name, const char *refspec, bool fetch)
85
98
  {
86
- git_remote *remote;
87
- git_buf fetchbuf = GIT_BUF_INIT;
88
- int error = -1;
89
-
90
- /* name is optional */
91
- assert(out && repo && url);
99
+ git_config *cfg;
100
+ git_buf var = GIT_BUF_INIT;
101
+ git_refspec spec;
102
+ const char *fmt;
103
+ int error;
92
104
 
93
- remote = git__calloc(1, sizeof(git_remote));
94
- GITERR_CHECK_ALLOC(remote);
105
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
106
+ return error;
95
107
 
96
- remote->repo = repo;
97
- remote->check_cert = 1;
98
- remote->update_fetchhead = 1;
108
+ fmt = fetch ? CONFIG_FETCH_FMT : CONFIG_PUSH_FMT;
99
109
 
100
- if (git_vector_init(&remote->refs, 32, NULL) < 0)
101
- goto on_error;
110
+ if ((error = ensure_remote_name_is_valid(name)) < 0)
111
+ return error;
102
112
 
103
- remote->url = git__strdup(url);
104
- GITERR_CHECK_ALLOC(remote->url);
113
+ if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
114
+ if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
115
+ error = GIT_EINVALIDSPEC;
105
116
 
106
- if (name != NULL) {
107
- remote->name = git__strdup(name);
108
- GITERR_CHECK_ALLOC(remote->name);
117
+ return error;
109
118
  }
110
119
 
111
- if (fetch != NULL) {
112
- if (add_refspec(remote, fetch, true) < 0)
113
- goto on_error;
120
+ git_refspec__dispose(&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;
114
132
  }
115
133
 
116
- if (!name)
117
- /* A remote without a name doesn't download tags */
118
- remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
134
+ cleanup:
135
+ git_buf_dispose(&var);
136
+ return 0;
137
+ }
119
138
 
120
- *out = remote;
121
- git_buf_free(&fetchbuf);
139
+ #if 0
140
+ /* We could export this as a helper */
141
+ static int get_check_cert(int *out, git_repository *repo)
142
+ {
143
+ git_config *cfg;
144
+ const char *val;
145
+ int error = 0;
146
+
147
+ assert(out && repo);
148
+
149
+ /* By default, we *DO* want to verify the certificate. */
150
+ *out = 1;
151
+
152
+ /* Go through the possible sources for SSL verification settings, from
153
+ * most specific to least specific. */
154
+
155
+ /* GIT_SSL_NO_VERIFY environment variable */
156
+ if ((val = p_getenv("GIT_SSL_NO_VERIFY")) != NULL)
157
+ return git_config_parse_bool(out, val);
158
+
159
+ /* http.sslVerify config setting */
160
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
161
+ return error;
162
+
163
+ *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
122
164
  return 0;
165
+ }
166
+ #endif
123
167
 
124
- on_error:
125
- git_remote_free(remote);
126
- git_buf_free(&fetchbuf);
127
- return error;
168
+ static int canonicalize_url(git_buf *out, const char *in)
169
+ {
170
+ if (in == NULL || strlen(in) == 0) {
171
+ git_error_set(GIT_ERROR_INVALID, "cannot set empty URL");
172
+ return GIT_EINVALIDSPEC;
173
+ }
174
+
175
+ #ifdef GIT_WIN32
176
+ /* Given a UNC path like \\server\path, we need to convert this
177
+ * to //server/path for compatibility with core git.
178
+ */
179
+ if (in[0] == '\\' && in[1] == '\\' &&
180
+ (git__isalpha(in[2]) || git__isdigit(in[2]))) {
181
+ const char *c;
182
+ for (c = in; *c; c++)
183
+ git_buf_putc(out, *c == '\\' ? '/' : *c);
184
+
185
+ return git_buf_oom(out) ? -1 : 0;
186
+ }
187
+ #endif
188
+
189
+ return git_buf_puts(out, in);
190
+ }
191
+
192
+ static int default_fetchspec_for_name(git_buf *buf, const char *name)
193
+ {
194
+ if (git_buf_printf(buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
195
+ return -1;
196
+
197
+ return 0;
128
198
  }
129
199
 
130
200
  static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
@@ -132,7 +202,7 @@ static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
132
202
  int error;
133
203
  git_remote *remote;
134
204
 
135
- error = git_remote_load(&remote, repo, name);
205
+ error = git_remote_lookup(&remote, repo, name);
136
206
 
137
207
  if (error == GIT_ENOTFOUND)
138
208
  return 0;
@@ -142,57 +212,228 @@ static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
142
212
 
143
213
  git_remote_free(remote);
144
214
 
145
- giterr_set(
146
- GITERR_CONFIG,
147
- "Remote '%s' already exists.", name);
215
+ git_error_set(GIT_ERROR_CONFIG, "remote '%s' already exists", name);
148
216
 
149
217
  return GIT_EEXISTS;
150
218
  }
151
219
 
220
+ int git_remote_create_init_options(git_remote_create_options *opts, unsigned int version)
221
+ {
222
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
223
+ opts, version, git_remote_create_options, GIT_REMOTE_CREATE_OPTIONS_INIT);
224
+ return 0;
225
+ }
152
226
 
153
- int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
227
+ int git_remote_create_with_opts(git_remote **out, const char *url, const git_remote_create_options *opts)
154
228
  {
155
- git_buf buf = GIT_BUF_INIT;
156
229
  git_remote *remote = NULL;
157
- int error;
230
+ git_config *config_ro = NULL, *config_rw;
231
+ git_buf canonical_url = GIT_BUF_INIT;
232
+ git_buf var = GIT_BUF_INIT;
233
+ git_buf specbuf = GIT_BUF_INIT;
234
+ const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
235
+ int error = -1;
158
236
 
159
- if ((error = ensure_remote_name_is_valid(name)) < 0)
160
- return error;
237
+ assert(out && url);
161
238
 
162
- if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
163
- return error;
239
+ if (!opts) {
240
+ opts = &dummy_opts;
241
+ }
164
242
 
165
- if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
166
- return -1;
243
+ GIT_ERROR_CHECK_VERSION(opts, GIT_REMOTE_CREATE_OPTIONS_VERSION, "git_remote_create_options");
167
244
 
168
- if (create_internal(&remote, repo, name, url, git_buf_cstr(&buf)) < 0)
169
- goto on_error;
245
+ if (opts->name != NULL) {
246
+ if ((error = ensure_remote_name_is_valid(opts->name)) < 0)
247
+ return error;
248
+
249
+ if (opts->repository &&
250
+ (error = ensure_remote_doesnot_exist(opts->repository, opts->name)) < 0)
251
+ return error;
252
+ }
253
+
254
+ if (opts->repository) {
255
+ if ((error = git_repository_config_snapshot(&config_ro, opts->repository)) < 0)
256
+ goto on_error;
257
+ }
258
+
259
+ remote = git__calloc(1, sizeof(git_remote));
260
+ GIT_ERROR_CHECK_ALLOC(remote);
170
261
 
171
- git_buf_free(&buf);
262
+ remote->repo = opts->repository;
172
263
 
173
- if (git_remote_save(remote) < 0)
264
+ if ((error = git_vector_init(&remote->refs, 8, NULL)) < 0 ||
265
+ (error = canonicalize_url(&canonical_url, url)) < 0)
174
266
  goto on_error;
175
267
 
176
- *out = remote;
268
+ if (opts->repository && !(opts->flags & GIT_REMOTE_CREATE_SKIP_INSTEADOF)) {
269
+ remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
270
+ } else {
271
+ remote->url = git__strdup(canonical_url.ptr);
272
+ }
273
+ GIT_ERROR_CHECK_ALLOC(remote->url);
177
274
 
178
- return 0;
275
+ if (opts->name != NULL) {
276
+ remote->name = git__strdup(opts->name);
277
+ GIT_ERROR_CHECK_ALLOC(remote->name);
278
+
279
+ if (opts->repository &&
280
+ ((error = git_buf_printf(&var, CONFIG_URL_FMT, opts->name)) < 0 ||
281
+ (error = git_repository_config__weakptr(&config_rw, opts->repository)) < 0 ||
282
+ (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0))
283
+ goto on_error;
284
+ }
285
+
286
+ if (opts->fetchspec != NULL ||
287
+ (opts->name && !(opts->flags & GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC))) {
288
+ const char *fetch = NULL;
289
+ if (opts->fetchspec) {
290
+ fetch = opts->fetchspec;
291
+ } else {
292
+ if ((error = default_fetchspec_for_name(&specbuf, opts->name)) < 0)
293
+ goto on_error;
294
+
295
+ fetch = git_buf_cstr(&specbuf);
296
+ }
297
+
298
+ if ((error = add_refspec(remote, fetch, true)) < 0)
299
+ goto on_error;
300
+
301
+ /* only write for named remotes with a repository */
302
+ if (opts->repository && opts->name &&
303
+ ((error = write_add_refspec(opts->repository, opts->name, fetch, true)) < 0 ||
304
+ (error = lookup_remote_prune_config(remote, config_ro, opts->name)) < 0))
305
+ goto on_error;
306
+
307
+ /* Move the data over to where the matching functions can find them */
308
+ if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
309
+ goto on_error;
310
+ }
311
+
312
+ /* A remote without a name doesn't download tags */
313
+ if (!opts->name)
314
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
315
+ else
316
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
317
+
318
+
319
+ git_buf_dispose(&var);
320
+
321
+ *out = remote;
322
+ error = 0;
179
323
 
180
324
  on_error:
181
- git_buf_free(&buf);
182
- git_remote_free(remote);
183
- return -1;
325
+ if (error)
326
+ git_remote_free(remote);
327
+
328
+ git_config_free(config_ro);
329
+ git_buf_dispose(&specbuf);
330
+ git_buf_dispose(&canonical_url);
331
+ git_buf_dispose(&var);
332
+ return error;
184
333
  }
185
334
 
186
- int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url)
335
+ int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
187
336
  {
337
+ git_buf buf = GIT_BUF_INIT;
188
338
  int error;
189
- git_remote *remote;
339
+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
190
340
 
191
- if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0)
341
+ /* Those 2 tests are duplicated here because of backward-compatibility */
342
+ if ((error = ensure_remote_name_is_valid(name)) < 0)
192
343
  return error;
193
344
 
194
- *out = remote;
195
- return 0;
345
+ if (canonicalize_url(&buf, url) < 0)
346
+ return GIT_ERROR;
347
+
348
+ git_buf_clear(&buf);
349
+
350
+ opts.repository = repo;
351
+ opts.name = name;
352
+
353
+ error = git_remote_create_with_opts(out, url, &opts);
354
+
355
+ git_buf_dispose(&buf);
356
+
357
+ return error;
358
+ }
359
+
360
+ int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
361
+ {
362
+ int error;
363
+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
364
+
365
+ if ((error = ensure_remote_name_is_valid(name)) < 0)
366
+ return error;
367
+
368
+ opts.repository = repo;
369
+ opts.name = name;
370
+ opts.fetchspec = fetch;
371
+ opts.flags = GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC;
372
+
373
+ return git_remote_create_with_opts(out, url, &opts);
374
+ }
375
+
376
+ int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
377
+ {
378
+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
379
+
380
+ opts.repository = repo;
381
+
382
+ return git_remote_create_with_opts(out, url, &opts);
383
+ }
384
+
385
+ int git_remote_create_detached(git_remote **out, const char *url)
386
+ {
387
+ return git_remote_create_with_opts(out, url, NULL);
388
+ }
389
+
390
+ int git_remote_dup(git_remote **dest, git_remote *source)
391
+ {
392
+ size_t i;
393
+ int error = 0;
394
+ git_refspec *spec;
395
+ git_remote *remote = git__calloc(1, sizeof(git_remote));
396
+ GIT_ERROR_CHECK_ALLOC(remote);
397
+
398
+ if (source->name != NULL) {
399
+ remote->name = git__strdup(source->name);
400
+ GIT_ERROR_CHECK_ALLOC(remote->name);
401
+ }
402
+
403
+ if (source->url != NULL) {
404
+ remote->url = git__strdup(source->url);
405
+ GIT_ERROR_CHECK_ALLOC(remote->url);
406
+ }
407
+
408
+ if (source->pushurl != NULL) {
409
+ remote->pushurl = git__strdup(source->pushurl);
410
+ GIT_ERROR_CHECK_ALLOC(remote->pushurl);
411
+ }
412
+
413
+ remote->repo = source->repo;
414
+ remote->download_tags = source->download_tags;
415
+ remote->prune_refs = source->prune_refs;
416
+
417
+ if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
418
+ git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
419
+ git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
420
+ error = -1;
421
+ goto cleanup;
422
+ }
423
+
424
+ git_vector_foreach(&source->refspecs, i, spec) {
425
+ if ((error = add_refspec(remote, spec->string, !spec->push)) < 0)
426
+ goto cleanup;
427
+ }
428
+
429
+ *dest = remote;
430
+
431
+ cleanup:
432
+
433
+ if (error < 0)
434
+ git__free(remote);
435
+
436
+ return error;
196
437
  }
197
438
 
198
439
  struct refspec_cb_data {
@@ -202,13 +443,13 @@ struct refspec_cb_data {
202
443
 
203
444
  static int refspec_cb(const git_config_entry *entry, void *payload)
204
445
  {
205
- const struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
206
-
446
+ struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
207
447
  return add_refspec(data->remote, entry->value, data->fetch);
208
448
  }
209
449
 
210
450
  static int get_optional_config(
211
- git_config *config, git_buf *buf, git_config_foreach_cb cb, void *payload)
451
+ bool *found, git_config *config, git_buf *buf,
452
+ git_config_foreach_cb cb, void *payload)
212
453
  {
213
454
  int error = 0;
214
455
  const char *key = git_buf_cstr(buf);
@@ -217,105 +458,120 @@ static int get_optional_config(
217
458
  return -1;
218
459
 
219
460
  if (cb != NULL)
220
- error = git_config_get_multivar(config, key, NULL, cb, payload);
461
+ error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
221
462
  else
222
463
  error = git_config_get_string(payload, config, key);
223
464
 
465
+ if (found)
466
+ *found = !error;
467
+
224
468
  if (error == GIT_ENOTFOUND) {
225
- giterr_clear();
469
+ git_error_clear();
226
470
  error = 0;
227
471
  }
228
472
 
229
- if (error < 0)
230
- error = -1;
231
-
232
473
  return error;
233
474
  }
234
475
 
235
- int git_remote_load(git_remote **out, git_repository *repo, const char *name)
476
+ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
236
477
  {
237
- git_remote *remote;
478
+ git_remote *remote = NULL;
238
479
  git_buf buf = GIT_BUF_INIT;
239
480
  const char *val;
240
481
  int error = 0;
241
482
  git_config *config;
242
- struct refspec_cb_data data;
483
+ struct refspec_cb_data data = { NULL };
484
+ bool optional_setting_found = false, found;
243
485
 
244
486
  assert(out && repo && name);
245
487
 
246
488
  if ((error = ensure_remote_name_is_valid(name)) < 0)
247
489
  return error;
248
490
 
249
- if (git_repository_config__weakptr(&config, repo) < 0)
250
- return -1;
491
+ if ((error = git_repository_config_snapshot(&config, repo)) < 0)
492
+ return error;
251
493
 
252
- remote = git__malloc(sizeof(git_remote));
253
- GITERR_CHECK_ALLOC(remote);
494
+ remote = git__calloc(1, sizeof(git_remote));
495
+ GIT_ERROR_CHECK_ALLOC(remote);
254
496
 
255
- memset(remote, 0x0, sizeof(git_remote));
256
- remote->check_cert = 1;
257
- remote->update_fetchhead = 1;
258
497
  remote->name = git__strdup(name);
259
- GITERR_CHECK_ALLOC(remote->name);
498
+ GIT_ERROR_CHECK_ALLOC(remote->name);
260
499
 
261
- if ((git_vector_init(&remote->refs, 32, NULL) < 0) ||
262
- (git_vector_init(&remote->refspecs, 2, NULL))) {
500
+ if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
501
+ git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
502
+ git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 ||
503
+ git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
263
504
  error = -1;
264
505
  goto cleanup;
265
506
  }
266
507
 
267
- if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
268
- error = -1;
508
+ if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
269
509
  goto cleanup;
270
- }
271
510
 
272
- if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
511
+ if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
273
512
  goto cleanup;
274
513
 
275
- if (strlen(val) == 0) {
276
- giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name);
277
- error = -1;
278
- goto cleanup;
279
- }
514
+ optional_setting_found |= found;
280
515
 
281
516
  remote->repo = repo;
282
- remote->url = git__strdup(val);
283
- GITERR_CHECK_ALLOC(remote->url);
517
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
518
+
519
+ if (found && strlen(val) > 0) {
520
+ remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
521
+ GIT_ERROR_CHECK_ALLOC(remote->url);
522
+ }
284
523
 
285
524
  val = NULL;
286
525
  git_buf_clear(&buf);
287
526
  git_buf_printf(&buf, "remote.%s.pushurl", name);
288
527
 
289
- if ((error = get_optional_config(config, &buf, NULL, (void *)&val)) < 0)
528
+ if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
529
+ goto cleanup;
530
+
531
+ optional_setting_found |= found;
532
+
533
+ if (!optional_setting_found) {
534
+ error = GIT_ENOTFOUND;
535
+ git_error_set(GIT_ERROR_CONFIG, "remote '%s' does not exist", name);
290
536
  goto cleanup;
537
+ }
291
538
 
292
- if (val) {
293
- remote->pushurl = git__strdup(val);
294
- GITERR_CHECK_ALLOC(remote->pushurl);
539
+ if (found && strlen(val) > 0) {
540
+ remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
541
+ GIT_ERROR_CHECK_ALLOC(remote->pushurl);
295
542
  }
296
543
 
297
544
  data.remote = remote;
298
545
  data.fetch = true;
546
+
299
547
  git_buf_clear(&buf);
300
548
  git_buf_printf(&buf, "remote.%s.fetch", name);
301
549
 
302
- if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0)
550
+ if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
303
551
  goto cleanup;
304
552
 
305
553
  data.fetch = false;
306
554
  git_buf_clear(&buf);
307
555
  git_buf_printf(&buf, "remote.%s.push", name);
308
556
 
309
- if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0)
557
+ if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
558
+ goto cleanup;
559
+
560
+ if ((error = download_tags_value(remote, config)) < 0)
310
561
  goto cleanup;
311
562
 
312
- if (download_tags_value(remote, config) < 0)
563
+ if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
564
+ goto cleanup;
565
+
566
+ /* Move the data over to where the matching functions can find them */
567
+ if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
313
568
  goto cleanup;
314
569
 
315
570
  *out = remote;
316
571
 
317
572
  cleanup:
318
- git_buf_free(&buf);
573
+ git_config_free(config);
574
+ git_buf_dispose(&buf);
319
575
 
320
576
  if (error < 0)
321
577
  git_remote_free(remote);
@@ -323,166 +579,84 @@ cleanup:
323
579
  return error;
324
580
  }
325
581
 
326
- static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
582
+ static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
327
583
  {
328
- git_buf name = GIT_BUF_INIT;
329
- int push;
330
- const char *dir;
331
- size_t i;
584
+ git_buf buf = GIT_BUF_INIT;
332
585
  int error = 0;
333
586
 
334
- push = direction == GIT_DIRECTION_PUSH;
335
- dir = push ? "push" : "fetch";
336
-
337
- if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
338
- return -1;
339
-
340
- /* Clear out the existing config */
341
- while (!error)
342
- error = git_config_delete_entry(config, git_buf_cstr(&name));
343
-
344
- if (error != GIT_ENOTFOUND)
345
- return error;
346
-
347
- for (i = 0; i < remote->refspecs.length; i++) {
348
- git_refspec *spec = git_vector_get(&remote->refspecs, i);
587
+ git_buf_printf(&buf, "remote.%s.prune", name);
349
588
 
350
- if (spec->push != push)
351
- continue;
589
+ if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
590
+ if (error == GIT_ENOTFOUND) {
591
+ git_error_clear();
352
592
 
353
- if ((error = git_config_set_multivar(
354
- config, git_buf_cstr(&name), "", spec->string)) < 0) {
355
- goto cleanup;
593
+ if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
594
+ if (error == GIT_ENOTFOUND) {
595
+ git_error_clear();
596
+ error = 0;
597
+ }
598
+ }
356
599
  }
357
600
  }
358
601
 
359
- giterr_clear();
360
- error = 0;
602
+ git_buf_dispose(&buf);
603
+ return error;
604
+ }
361
605
 
362
- cleanup:
363
- git_buf_free(&name);
606
+ const char *git_remote_name(const git_remote *remote)
607
+ {
608
+ assert(remote);
609
+ return remote->name;
610
+ }
364
611
 
365
- return error;
612
+ git_repository *git_remote_owner(const git_remote *remote)
613
+ {
614
+ assert(remote);
615
+ return remote->repo;
616
+ }
617
+
618
+ const char *git_remote_url(const git_remote *remote)
619
+ {
620
+ assert(remote);
621
+ return remote->url;
366
622
  }
367
623
 
368
- int git_remote_save(const git_remote *remote)
624
+ static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
369
625
  {
626
+ git_config *cfg;
627
+ git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
370
628
  int error;
371
- git_config *config;
372
- const char *tagopt = NULL;
373
- git_buf buf = GIT_BUF_INIT;
374
629
 
375
- assert(remote);
630
+ assert(repo && remote);
376
631
 
377
- if (!remote->name) {
378
- giterr_set(GITERR_INVALID, "Can't save an in-memory remote.");
379
- return GIT_EINVALIDSPEC;
380
- }
632
+ if ((error = ensure_remote_name_is_valid(remote)) < 0)
633
+ return error;
381
634
 
382
- if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
635
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
383
636
  return error;
384
637
 
385
- if (git_repository_config__weakptr(&config, remote->repo) < 0)
386
- return -1;
638
+ if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
639
+ return error;
387
640
 
388
- if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
389
- return -1;
641
+ if (url) {
642
+ if ((error = canonicalize_url(&canonical_url, url)) < 0)
643
+ goto cleanup;
390
644
 
391
- if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
392
- git_buf_free(&buf);
393
- return -1;
645
+ error = git_config_set_string(cfg, buf.ptr, url);
646
+ } else {
647
+ error = git_config_delete_entry(cfg, buf.ptr);
394
648
  }
395
649
 
396
- git_buf_clear(&buf);
397
- if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
398
- return -1;
650
+ cleanup:
651
+ git_buf_dispose(&canonical_url);
652
+ git_buf_dispose(&buf);
399
653
 
400
- if (remote->pushurl) {
401
- if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
402
- git_buf_free(&buf);
403
- return -1;
404
- }
405
- } else {
406
- int error = git_config_delete_entry(config, git_buf_cstr(&buf));
407
- if (error == GIT_ENOTFOUND) {
408
- error = 0;
409
- giterr_clear();
410
- }
411
- if (error < 0) {
412
- git_buf_free(&buf);
413
- return -1;
414
- }
415
- }
416
-
417
- if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
418
- goto on_error;
419
-
420
- if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
421
- goto on_error;
422
-
423
- /*
424
- * What action to take depends on the old and new values. This
425
- * is describes by the table below. tagopt means whether the
426
- * is already a value set in the config
427
- *
428
- * AUTO ALL or NONE
429
- * +-----------------------+
430
- * tagopt | remove | set |
431
- * +---------+-------------|
432
- * !tagopt | nothing | set |
433
- * +---------+-------------+
434
- */
435
-
436
- git_buf_clear(&buf);
437
- if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
438
- goto on_error;
439
-
440
- error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
441
- if (error < 0 && error != GIT_ENOTFOUND)
442
- goto on_error;
443
-
444
- if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
445
- if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
446
- goto on_error;
447
- } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
448
- if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
449
- goto on_error;
450
- } else if (tagopt) {
451
- if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
452
- goto on_error;
453
- }
454
-
455
- git_buf_free(&buf);
456
-
457
- return 0;
458
-
459
- on_error:
460
- git_buf_free(&buf);
461
- return -1;
462
- }
463
-
464
- const char *git_remote_name(const git_remote *remote)
465
- {
466
- assert(remote);
467
- return remote->name;
468
- }
469
-
470
- const char *git_remote_url(const git_remote *remote)
471
- {
472
- assert(remote);
473
- return remote->url;
654
+ return error;
474
655
  }
475
656
 
476
- int git_remote_set_url(git_remote *remote, const char* url)
657
+ int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
477
658
  {
478
- assert(remote);
479
- assert(url);
480
-
481
- git__free(remote->url);
482
- remote->url = git__strdup(url);
483
- GITERR_CHECK_ALLOC(remote->url);
484
-
485
- return 0;
659
+ return set_url(repo, remote, CONFIG_URL_FMT, url);
486
660
  }
487
661
 
488
662
  const char *git_remote_pushurl(const git_remote *remote)
@@ -491,24 +665,17 @@ const char *git_remote_pushurl(const git_remote *remote)
491
665
  return remote->pushurl;
492
666
  }
493
667
 
494
- int git_remote_set_pushurl(git_remote *remote, const char* url)
668
+ int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
495
669
  {
496
- assert(remote);
497
-
498
- git__free(remote->pushurl);
499
- if (url) {
500
- remote->pushurl = git__strdup(url);
501
- GITERR_CHECK_ALLOC(remote->pushurl);
502
- } else {
503
- remote->pushurl = NULL;
504
- }
505
- return 0;
670
+ return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
506
671
  }
507
672
 
508
673
  const char* git_remote__urlfordirection(git_remote *remote, int direction)
509
674
  {
510
675
  assert(remote);
511
676
 
677
+ assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
678
+
512
679
  if (direction == GIT_DIRECTION_FETCH) {
513
680
  return remote->url;
514
681
  }
@@ -520,33 +687,72 @@ const char* git_remote__urlfordirection(git_remote *remote, int direction)
520
687
  return NULL;
521
688
  }
522
689
 
523
- int git_remote_connect(git_remote *remote, git_direction direction)
690
+ int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
691
+ {
692
+ if (!t->set_callbacks || !cbs)
693
+ return 0;
694
+
695
+ return t->set_callbacks(t, cbs->sideband_progress, NULL,
696
+ cbs->certificate_check, cbs->payload);
697
+ }
698
+
699
+ static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers)
700
+ {
701
+ if (!t->set_custom_headers)
702
+ return 0;
703
+
704
+ return t->set_custom_headers(t, custom_headers);
705
+ }
706
+
707
+ int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn)
524
708
  {
525
709
  git_transport *t;
526
710
  const char *url;
527
711
  int flags = GIT_TRANSPORTFLAGS_NONE;
712
+ int error;
713
+ void *payload = NULL;
714
+ git_cred_acquire_cb credentials = NULL;
715
+ git_transport_cb transport = NULL;
528
716
 
529
717
  assert(remote);
530
718
 
719
+ if (callbacks) {
720
+ GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
721
+ credentials = callbacks->credentials;
722
+ transport = callbacks->transport;
723
+ payload = callbacks->payload;
724
+ }
725
+
726
+ if (conn->proxy)
727
+ GIT_ERROR_CHECK_VERSION(conn->proxy, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
728
+
531
729
  t = remote->transport;
532
730
 
533
731
  url = git_remote__urlfordirection(remote, direction);
534
- if (url == NULL )
732
+ if (url == NULL) {
733
+ git_error_set(GIT_ERROR_INVALID,
734
+ "Malformed remote '%s' - missing %s URL",
735
+ remote->name ? remote->name : "(anonymous)",
736
+ direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
535
737
  return -1;
738
+ }
536
739
 
537
- /* A transport could have been supplied in advance with
538
- * git_remote_set_transport */
539
- if (!t && git_transport_new(&t, remote, url) < 0)
540
- return -1;
740
+ /* If we don't have a transport object yet, and the caller specified a
741
+ * custom transport factory, use that */
742
+ if (!t && transport &&
743
+ (error = transport(&t, remote, payload)) < 0)
744
+ return error;
541
745
 
542
- if (t->set_callbacks &&
543
- t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload) < 0)
544
- goto on_error;
746
+ /* If we still don't have a transport, then use the global
747
+ * transport registrations which map URI schemes to transport factories */
748
+ if (!t && (error = git_transport_new(&t, remote, url)) < 0)
749
+ return error;
545
750
 
546
- if (!remote->check_cert)
547
- flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT;
751
+ if ((error = set_transport_custom_headers(t, conn->custom_headers)) != 0)
752
+ goto on_error;
548
753
 
549
- if (t->connect(t, url, remote->cred_acquire_cb, remote->cred_acquire_payload, direction, flags) < 0)
754
+ if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
755
+ (error = t->connect(t, url, credentials, payload, conn->proxy, direction, flags)) != 0)
550
756
  goto on_error;
551
757
 
552
758
  remote->transport = t;
@@ -559,20 +765,37 @@ on_error:
559
765
  if (t == remote->transport)
560
766
  remote->transport = NULL;
561
767
 
562
- return -1;
768
+ return error;
769
+ }
770
+
771
+ int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy, const git_strarray *custom_headers)
772
+ {
773
+ git_remote_connection_opts conn;
774
+
775
+ conn.proxy = proxy;
776
+ conn.custom_headers = custom_headers;
777
+
778
+ return git_remote__connect(remote, direction, callbacks, &conn);
563
779
  }
564
780
 
565
- int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
781
+ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
566
782
  {
567
783
  assert(remote);
568
784
 
569
- return remote->transport->ls(remote->transport, list_cb, payload);
785
+ if (!remote->transport) {
786
+ git_error_set(GIT_ERROR_NET, "this remote has never connected");
787
+ return -1;
788
+ }
789
+
790
+ return remote->transport->ls(out, size, remote->transport);
570
791
  }
571
792
 
572
793
  int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
573
794
  {
574
795
  git_config *cfg;
575
- const char *val;
796
+ git_config_entry *ce = NULL;
797
+ git_buf val = GIT_BUF_INIT;
798
+ int error;
576
799
 
577
800
  assert(remote);
578
801
 
@@ -581,112 +804,90 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur
581
804
 
582
805
  *proxy_url = NULL;
583
806
 
584
- if (git_repository_config__weakptr(&cfg, remote->repo) < 0)
585
- return -1;
807
+ if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
808
+ return error;
586
809
 
587
810
  /* Go through the possible sources for proxy configuration, from most specific
588
811
  * to least specific. */
589
812
 
590
813
  /* remote.<name>.proxy config setting */
591
- if (remote->name && 0 != *(remote->name)) {
814
+ if (remote->name && remote->name[0]) {
592
815
  git_buf buf = GIT_BUF_INIT;
593
816
 
594
- if (git_buf_printf(&buf, "remote.%s.proxy", remote->name) < 0)
595
- return -1;
817
+ if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
818
+ return error;
596
819
 
597
- if (!git_config_get_string(&val, cfg, git_buf_cstr(&buf)) &&
598
- val && ('\0' != *val)) {
599
- git_buf_free(&buf);
820
+ error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
821
+ git_buf_dispose(&buf);
600
822
 
601
- *proxy_url = git__strdup(val);
602
- GITERR_CHECK_ALLOC(*proxy_url);
603
- return 0;
604
- }
823
+ if (error < 0)
824
+ return error;
605
825
 
606
- git_buf_free(&buf);
826
+ if (ce && ce->value) {
827
+ *proxy_url = git__strdup(ce->value);
828
+ goto found;
829
+ }
607
830
  }
608
831
 
609
832
  /* http.proxy config setting */
610
- if (!git_config_get_string(&val, cfg, "http.proxy") &&
611
- val && ('\0' != *val)) {
612
- *proxy_url = git__strdup(val);
613
- GITERR_CHECK_ALLOC(*proxy_url);
614
- return 0;
833
+ if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
834
+ return error;
835
+
836
+ if (ce && ce->value) {
837
+ *proxy_url = git__strdup(ce->value);
838
+ goto found;
615
839
  }
616
840
 
617
- /* HTTP_PROXY / HTTPS_PROXY environment variables */
618
- val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
841
+ /* http_proxy / https_proxy environment variables */
842
+ error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy");
619
843
 
620
- if (val && ('\0' != *val)) {
621
- *proxy_url = git__strdup(val);
622
- GITERR_CHECK_ALLOC(*proxy_url);
623
- return 0;
844
+ /* try uppercase environment variables */
845
+ if (error == GIT_ENOTFOUND)
846
+ error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
847
+
848
+ if (error < 0) {
849
+ if (error == GIT_ENOTFOUND) {
850
+ git_error_clear();
851
+ error = 0;
852
+ }
853
+
854
+ return error;
624
855
  }
625
856
 
626
- return 0;
627
- }
857
+ *proxy_url = git_buf_detach(&val);
628
858
 
629
- static int store_refs(git_remote_head *head, void *payload)
630
- {
631
- git_vector *refs = (git_vector *)payload;
859
+ found:
860
+ GIT_ERROR_CHECK_ALLOC(*proxy_url);
861
+ git_config_entry_free(ce);
632
862
 
633
- return git_vector_insert(refs, head);
863
+ return 0;
634
864
  }
635
865
 
636
- static int dwim_refspecs(git_vector *refspecs, git_vector *refs)
866
+ /* DWIM `refspecs` based on `refs` and append the output to `out` */
867
+ static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
637
868
  {
638
- git_buf buf = GIT_BUF_INIT;
869
+ size_t i;
639
870
  git_refspec *spec;
640
- size_t i, j, pos;
641
- git_remote_head key;
642
-
643
- const char* formatters[] = {
644
- GIT_REFS_DIR "%s",
645
- GIT_REFS_TAGS_DIR "%s",
646
- GIT_REFS_HEADS_DIR "%s",
647
- NULL
648
- };
649
871
 
650
872
  git_vector_foreach(refspecs, i, spec) {
651
- if (spec->dwim)
652
- continue;
653
-
654
- /* shorthand on the lhs */
655
- if (git__prefixcmp(spec->src, GIT_REFS_DIR)) {
656
- for (j = 0; formatters[j]; j++) {
657
- git_buf_clear(&buf);
658
- if (git_buf_printf(&buf, formatters[j], spec->src) < 0)
659
- return -1;
660
-
661
- key.name = (char *) git_buf_cstr(&buf);
662
- if (!git_vector_search(&pos, refs, &key)) {
663
- /* we found something to match the shorthand, set src to that */
664
- git__free(spec->src);
665
- spec->src = git_buf_detach(&buf);
666
- }
667
- }
668
- }
669
-
670
- if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) {
671
- /* if it starts with "remotes" then we just prepend "refs/" */
672
- if (!git__prefixcmp(spec->dst, "remotes/")) {
673
- git_buf_puts(&buf, GIT_REFS_DIR);
674
- } else {
675
- git_buf_puts(&buf, GIT_REFS_HEADS_DIR);
676
- }
873
+ if (git_refspec__dwim_one(out, spec, refs) < 0)
874
+ return -1;
875
+ }
677
876
 
678
- if (git_buf_puts(&buf, spec->dst) < 0)
679
- return -1;
877
+ return 0;
878
+ }
680
879
 
681
- git__free(spec->dst);
682
- spec->dst = git_buf_detach(&buf);
683
- }
880
+ static void free_refspecs(git_vector *vec)
881
+ {
882
+ size_t i;
883
+ git_refspec *spec;
684
884
 
685
- spec->dwim = 1;
885
+ git_vector_foreach(vec, i, spec) {
886
+ git_refspec__dispose(spec);
887
+ git__free(spec);
686
888
  }
687
889
 
688
- git_buf_free(&buf);
689
- return 0;
890
+ git_vector_clear(vec);
690
891
  }
691
892
 
692
893
  static int remote_head_cmp(const void *_a, const void *_b)
@@ -697,32 +898,166 @@ static int remote_head_cmp(const void *_a, const void *_b)
697
898
  return git__strcmp_cb(a->name, b->name);
698
899
  }
699
900
 
700
- int git_remote_download(
701
- git_remote *remote,
702
- git_transfer_progress_callback progress_cb,
703
- void *progress_payload)
901
+ static int ls_to_vector(git_vector *out, git_remote *remote)
704
902
  {
705
- int error;
706
- git_vector refs;
903
+ git_remote_head **heads;
904
+ size_t heads_len, i;
905
+
906
+ if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
907
+ return -1;
908
+
909
+ if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
910
+ return -1;
911
+
912
+ for (i = 0; i < heads_len; i++) {
913
+ if (git_vector_insert(out, heads[i]) < 0)
914
+ return -1;
915
+ }
916
+
917
+ return 0;
918
+ }
919
+
920
+ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
921
+ {
922
+ int error = -1;
923
+ size_t i;
924
+ git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
925
+ const git_remote_callbacks *cbs = NULL;
926
+ const git_strarray *custom_headers = NULL;
927
+ const git_proxy_options *proxy = NULL;
707
928
 
708
929
  assert(remote);
709
930
 
710
- if (git_vector_init(&refs, 16, remote_head_cmp) < 0)
931
+ if (!remote->repo) {
932
+ git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
711
933
  return -1;
934
+ }
935
+
936
+ if (opts) {
937
+ GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
938
+ cbs = &opts->callbacks;
939
+ custom_headers = &opts->custom_headers;
940
+ GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
941
+ proxy = &opts->proxy_opts;
942
+ }
943
+
944
+ if (!git_remote_connected(remote) &&
945
+ (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, proxy, custom_headers)) < 0)
946
+ goto on_error;
712
947
 
713
- if (git_remote_ls(remote, store_refs, &refs) < 0) {
948
+ if (ls_to_vector(&refs, remote) < 0)
714
949
  return -1;
950
+
951
+ if ((git_vector_init(&specs, 0, NULL)) < 0)
952
+ goto on_error;
953
+
954
+ remote->passed_refspecs = 0;
955
+ if (!refspecs || !refspecs->count) {
956
+ to_active = &remote->refspecs;
957
+ } else {
958
+ for (i = 0; i < refspecs->count; i++) {
959
+ if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
960
+ goto on_error;
961
+ }
962
+
963
+ to_active = &specs;
964
+ remote->passed_refspecs = 1;
715
965
  }
716
966
 
717
- error = dwim_refspecs(&remote->refspecs, &refs);
967
+ free_refspecs(&remote->passive_refspecs);
968
+ if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
969
+ goto on_error;
970
+
971
+ free_refspecs(&remote->active_refspecs);
972
+ error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
973
+
718
974
  git_vector_free(&refs);
975
+ free_refspecs(&specs);
976
+ git_vector_free(&specs);
977
+
719
978
  if (error < 0)
720
- return -1;
979
+ return error;
980
+
981
+ if (remote->push) {
982
+ git_push_free(remote->push);
983
+ remote->push = NULL;
984
+ }
985
+
986
+ if ((error = git_fetch_negotiate(remote, opts)) < 0)
987
+ return error;
988
+
989
+ return git_fetch_download_pack(remote, cbs);
990
+
991
+ on_error:
992
+ git_vector_free(&refs);
993
+ free_refspecs(&specs);
994
+ git_vector_free(&specs);
995
+ return error;
996
+ }
721
997
 
722
- if ((error = git_fetch_negotiate(remote)) < 0)
998
+ int git_remote_fetch(
999
+ git_remote *remote,
1000
+ const git_strarray *refspecs,
1001
+ const git_fetch_options *opts,
1002
+ const char *reflog_message)
1003
+ {
1004
+ int error, update_fetchhead = 1;
1005
+ git_remote_autotag_option_t tagopt = remote->download_tags;
1006
+ bool prune = false;
1007
+ git_buf reflog_msg_buf = GIT_BUF_INIT;
1008
+ const git_remote_callbacks *cbs = NULL;
1009
+ git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
1010
+
1011
+ if (opts) {
1012
+ GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1013
+ cbs = &opts->callbacks;
1014
+ conn.custom_headers = &opts->custom_headers;
1015
+ update_fetchhead = opts->update_fetchhead;
1016
+ tagopt = opts->download_tags;
1017
+ GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
1018
+ conn.proxy = &opts->proxy_opts;
1019
+ }
1020
+
1021
+ /* Connect and download everything */
1022
+ if ((error = git_remote__connect(remote, GIT_DIRECTION_FETCH, cbs, &conn)) != 0)
1023
+ return error;
1024
+
1025
+ error = git_remote_download(remote, refspecs, opts);
1026
+
1027
+ /* We don't need to be connected anymore */
1028
+ git_remote_disconnect(remote);
1029
+
1030
+ /* If the download failed, return the error */
1031
+ if (error != 0)
1032
+ return error;
1033
+
1034
+ /* Default reflog message */
1035
+ if (reflog_message)
1036
+ git_buf_sets(&reflog_msg_buf, reflog_message);
1037
+ else {
1038
+ git_buf_printf(&reflog_msg_buf, "fetch %s",
1039
+ remote->name ? remote->name : remote->url);
1040
+ }
1041
+
1042
+ /* Create "remote/foo" branches for all remote branches */
1043
+ error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
1044
+ git_buf_dispose(&reflog_msg_buf);
1045
+ if (error < 0)
723
1046
  return error;
724
1047
 
725
- return git_fetch_download_pack(remote, progress_cb, progress_payload);
1048
+ if (opts && opts->prune == GIT_FETCH_PRUNE)
1049
+ prune = true;
1050
+ else if (opts && opts->prune == GIT_FETCH_PRUNE_UNSPECIFIED && remote->prune_refs)
1051
+ prune = true;
1052
+ else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
1053
+ prune = false;
1054
+ else
1055
+ prune = remote->prune_refs;
1056
+
1057
+ if (prune)
1058
+ error = git_remote_prune(remote, cbs);
1059
+
1060
+ return error;
726
1061
  }
727
1062
 
728
1063
  static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
@@ -744,34 +1079,70 @@ static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *upda
744
1079
  return 0;
745
1080
  }
746
1081
 
747
- static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref)
1082
+ static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
1083
+ {
1084
+ int error = 0;
1085
+ git_repository *repo;
1086
+ git_buf upstream_remote = GIT_BUF_INIT;
1087
+ git_buf upstream_name = GIT_BUF_INIT;
1088
+
1089
+ repo = git_remote_owner(remote);
1090
+
1091
+ if ((!git_reference__is_branch(ref_name)) ||
1092
+ !git_remote_name(remote) ||
1093
+ (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
1094
+ git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
1095
+ (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
1096
+ !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
1097
+ (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
1098
+ /* Not an error if there is no upstream */
1099
+ if (error == GIT_ENOTFOUND) {
1100
+ git_error_clear();
1101
+ error = 0;
1102
+ }
1103
+
1104
+ *update = 0;
1105
+ } else {
1106
+ *update = 1;
1107
+ }
1108
+
1109
+ git_buf_dispose(&upstream_remote);
1110
+ git_buf_dispose(&upstream_name);
1111
+ return error;
1112
+ }
1113
+
1114
+ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
748
1115
  {
749
1116
  git_reference *resolved_ref = NULL;
750
- git_reference *tracking_ref = NULL;
751
1117
  git_buf remote_name = GIT_BUF_INIT;
752
- int error = 0;
1118
+ git_config *config = NULL;
1119
+ const char *ref_name;
1120
+ int error = 0, update;
753
1121
 
754
1122
  assert(out && spec && ref);
755
1123
 
756
1124
  *out = NULL;
757
1125
 
758
- if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 ||
759
- (!git_reference_is_branch(resolved_ref)) ||
760
- (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 ||
761
- (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) {
762
- /* Not an error if HEAD is orphaned or no tracking branch */
763
- if (error == GIT_ENOTFOUND)
764
- error = 0;
1126
+ error = git_reference_resolve(&resolved_ref, ref);
765
1127
 
766
- goto cleanup;
1128
+ /* If we're in an unborn branch, let's pretend nothing happened */
1129
+ if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1130
+ ref_name = git_reference_symbolic_target(ref);
1131
+ error = 0;
1132
+ } else {
1133
+ ref_name = git_reference_name(resolved_ref);
767
1134
  }
768
1135
 
769
- error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
1136
+ if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
1137
+ goto cleanup;
1138
+
1139
+ if (update)
1140
+ error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
770
1141
 
771
1142
  cleanup:
772
- git_reference_free(tracking_ref);
1143
+ git_buf_dispose(&remote_name);
773
1144
  git_reference_free(resolved_ref);
774
- git_buf_free(&remote_name);
1145
+ git_config_free(config);
775
1146
  return error;
776
1147
  }
777
1148
 
@@ -800,7 +1171,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git
800
1171
  /* Determine what to merge: if refspec was a wildcard, just use HEAD */
801
1172
  if (git_refspec_is_wildcard(spec)) {
802
1173
  if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
803
- (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0)
1174
+ (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
804
1175
  goto cleanup;
805
1176
  } else {
806
1177
  /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
@@ -840,139 +1211,463 @@ cleanup:
840
1211
  return error;
841
1212
  }
842
1213
 
843
- static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs)
1214
+ /**
1215
+ * Generate a list of candidates for pruning by getting a list of
1216
+ * references which match the rhs of an active refspec.
1217
+ */
1218
+ static int prune_candidates(git_vector *candidates, git_remote *remote)
844
1219
  {
845
- int error = 0, autotag;
846
- unsigned int i = 0;
847
- git_buf refname = GIT_BUF_INIT;
848
- git_oid old;
849
- git_odb *odb;
850
- git_remote_head *head;
851
- git_reference *ref;
852
- git_refspec tagspec;
853
- git_vector update_heads;
1220
+ git_strarray arr = { 0 };
1221
+ size_t i;
1222
+ int error;
854
1223
 
855
- assert(remote);
1224
+ if ((error = git_reference_list(&arr, remote->repo)) < 0)
1225
+ return error;
856
1226
 
857
- if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
858
- return -1;
1227
+ for (i = 0; i < arr.count; i++) {
1228
+ const char *refname = arr.strings[i];
1229
+ char *refname_dup;
859
1230
 
860
- if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
861
- return -1;
1231
+ if (!git_remote__matching_dst_refspec(remote, refname))
1232
+ continue;
862
1233
 
863
- /* Make a copy of the transport's refs */
864
- if (git_vector_init(&update_heads, 16, NULL) < 0)
865
- return -1;
1234
+ refname_dup = git__strdup(refname);
1235
+ GIT_ERROR_CHECK_ALLOC(refname_dup);
866
1236
 
867
- for (; i < refs->length; ++i) {
868
- head = git_vector_get(refs, i);
869
- autotag = 0;
1237
+ if ((error = git_vector_insert(candidates, refname_dup)) < 0)
1238
+ goto out;
1239
+ }
870
1240
 
871
- /* Ignore malformed ref names (which also saves us from tag^{} */
872
- if (!git_reference_is_valid_name(head->name))
873
- continue;
1241
+ out:
1242
+ git_strarray_free(&arr);
1243
+ return error;
1244
+ }
874
1245
 
875
- if (git_refspec_src_matches(spec, head->name) && spec->dst) {
876
- if (git_refspec_transform_r(&refname, spec, head->name) < 0)
877
- goto on_error;
878
- } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
1246
+ static int find_head(const void *_a, const void *_b)
1247
+ {
1248
+ git_remote_head *a = (git_remote_head *) _a;
1249
+ git_remote_head *b = (git_remote_head *) _b;
879
1250
 
880
- if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL)
881
- autotag = 1;
1251
+ return strcmp(a->name, b->name);
1252
+ }
882
1253
 
883
- if (!git_refspec_src_matches(&tagspec, head->name))
884
- continue;
1254
+ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
1255
+ {
1256
+ size_t i, j;
1257
+ git_vector remote_refs = GIT_VECTOR_INIT;
1258
+ git_vector candidates = GIT_VECTOR_INIT;
1259
+ const git_refspec *spec;
1260
+ const char *refname;
1261
+ int error;
1262
+ git_oid zero_id = {{ 0 }};
885
1263
 
886
- git_buf_clear(&refname);
887
- if (git_buf_puts(&refname, head->name) < 0)
888
- goto on_error;
889
- } else {
890
- continue;
891
- }
1264
+ if (callbacks)
1265
+ GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
892
1266
 
1267
+ if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1268
+ goto cleanup;
1269
+
1270
+ git_vector_set_cmp(&remote_refs, find_head);
1271
+
1272
+ if ((error = prune_candidates(&candidates, remote)) < 0)
1273
+ goto cleanup;
1274
+
1275
+ /*
1276
+ * Remove those entries from the candidate list for which we
1277
+ * can find a remote reference in at least one refspec.
1278
+ */
1279
+ git_vector_foreach(&candidates, i, refname) {
1280
+ git_vector_foreach(&remote->active_refspecs, j, spec) {
1281
+ git_buf buf = GIT_BUF_INIT;
1282
+ size_t pos;
1283
+ char *src_name;
1284
+ git_remote_head key = {0};
1285
+
1286
+ if (!git_refspec_dst_matches(spec, refname))
1287
+ continue;
1288
+
1289
+ if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
1290
+ goto cleanup;
1291
+
1292
+ key.name = (char *) git_buf_cstr(&buf);
1293
+ error = git_vector_bsearch(&pos, &remote_refs, &key);
1294
+ git_buf_dispose(&buf);
1295
+
1296
+ if (error < 0 && error != GIT_ENOTFOUND)
1297
+ goto cleanup;
1298
+
1299
+ if (error == GIT_ENOTFOUND)
1300
+ continue;
1301
+
1302
+ /* if we did find a source, remove it from the candiates */
1303
+ if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
1304
+ goto cleanup;
1305
+
1306
+ git__free(src_name);
1307
+ break;
1308
+ }
1309
+ }
1310
+
1311
+ /*
1312
+ * For those candidates still left in the list, we need to
1313
+ * remove them. We do not remove symrefs, as those are for
1314
+ * stuff like origin/HEAD which will never match, but we do
1315
+ * not want to remove them.
1316
+ */
1317
+ git_vector_foreach(&candidates, i, refname) {
1318
+ git_reference *ref;
1319
+ git_oid id;
1320
+
1321
+ if (refname == NULL)
1322
+ continue;
1323
+
1324
+ error = git_reference_lookup(&ref, remote->repo, refname);
1325
+ /* as we want it gone, let's not consider this an error */
1326
+ if (error == GIT_ENOTFOUND)
1327
+ continue;
1328
+
1329
+ if (error < 0)
1330
+ goto cleanup;
1331
+
1332
+ if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1333
+ git_reference_free(ref);
1334
+ continue;
1335
+ }
1336
+
1337
+ git_oid_cpy(&id, git_reference_target(ref));
1338
+ error = git_reference_delete(ref);
1339
+ git_reference_free(ref);
1340
+ if (error < 0)
1341
+ goto cleanup;
1342
+
1343
+ if (callbacks && callbacks->update_tips)
1344
+ error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
1345
+
1346
+ if (error < 0)
1347
+ goto cleanup;
1348
+ }
1349
+
1350
+ cleanup:
1351
+ git_vector_free(&remote_refs);
1352
+ git_vector_free_deep(&candidates);
1353
+ return error;
1354
+ }
1355
+
1356
+ static int update_tips_for_spec(
1357
+ git_remote *remote,
1358
+ const git_remote_callbacks *callbacks,
1359
+ int update_fetchhead,
1360
+ git_remote_autotag_option_t tagopt,
1361
+ git_refspec *spec,
1362
+ git_vector *refs,
1363
+ const char *log_message)
1364
+ {
1365
+ int error = 0, autotag;
1366
+ unsigned int i = 0;
1367
+ git_buf refname = GIT_BUF_INIT;
1368
+ git_oid old;
1369
+ git_odb *odb;
1370
+ git_remote_head *head;
1371
+ git_reference *ref;
1372
+ git_refspec tagspec;
1373
+ git_vector update_heads;
1374
+
1375
+ assert(remote);
1376
+
1377
+ if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
1378
+ return -1;
1379
+
1380
+ if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1381
+ return -1;
1382
+
1383
+ /* Make a copy of the transport's refs */
1384
+ if (git_vector_init(&update_heads, 16, NULL) < 0)
1385
+ return -1;
1386
+
1387
+ for (; i < refs->length; ++i) {
1388
+ head = git_vector_get(refs, i);
1389
+ autotag = 0;
1390
+ git_buf_clear(&refname);
1391
+
1392
+ /* Ignore malformed ref names (which also saves us from tag^{} */
1393
+ if (!git_reference_is_valid_name(head->name))
1394
+ continue;
1395
+
1396
+ /* If we have a tag, see if the auto-follow rules say to update it */
1397
+ if (git_refspec_src_matches(&tagspec, head->name)) {
1398
+ if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
1399
+
1400
+ if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1401
+ autotag = 1;
1402
+
1403
+ git_buf_clear(&refname);
1404
+ if (git_buf_puts(&refname, head->name) < 0)
1405
+ goto on_error;
1406
+ }
1407
+ }
1408
+
1409
+ /* If we didn't want to auto-follow the tag, check if the refspec matches */
1410
+ if (!autotag && git_refspec_src_matches(spec, head->name)) {
1411
+ if (spec->dst) {
1412
+ if (git_refspec_transform(&refname, spec, head->name) < 0)
1413
+ goto on_error;
1414
+ } else {
1415
+ /*
1416
+ * no rhs mans store it in FETCH_HEAD, even if we don't
1417
+ update anything else.
1418
+ */
1419
+ if ((error = git_vector_insert(&update_heads, head)) < 0)
1420
+ goto on_error;
1421
+
1422
+ continue;
1423
+ }
1424
+ }
1425
+
1426
+ /* If we still don't have a refname, we don't want it */
1427
+ if (git_buf_len(&refname) == 0) {
1428
+ continue;
1429
+ }
1430
+
1431
+ /* In autotag mode, only create tags for objects already in db */
893
1432
  if (autotag && !git_odb_exists(odb, &head->oid))
894
1433
  continue;
895
1434
 
896
- if (git_vector_insert(&update_heads, head) < 0)
1435
+ if (!autotag && git_vector_insert(&update_heads, head) < 0)
897
1436
  goto on_error;
898
1437
 
899
1438
  error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
900
1439
  if (error < 0 && error != GIT_ENOTFOUND)
901
1440
  goto on_error;
902
1441
 
903
- if (error == GIT_ENOTFOUND)
1442
+ if (error == GIT_ENOTFOUND) {
904
1443
  memset(&old, 0, GIT_OID_RAWSZ);
905
1444
 
1445
+ if (autotag && git_vector_insert(&update_heads, head) < 0)
1446
+ goto on_error;
1447
+ }
1448
+
906
1449
  if (!git_oid__cmp(&old, &head->oid))
907
1450
  continue;
908
1451
 
909
1452
  /* In autotag mode, don't overwrite any locally-existing tags */
910
- error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
911
- if (error < 0 && error != GIT_EEXISTS)
1453
+ error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
1454
+ log_message);
1455
+
1456
+ if (error == GIT_EEXISTS)
1457
+ continue;
1458
+
1459
+ if (error < 0)
912
1460
  goto on_error;
913
1461
 
914
1462
  git_reference_free(ref);
915
1463
 
916
- if (remote->callbacks.update_tips != NULL) {
917
- if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.payload) < 0)
1464
+ if (callbacks && callbacks->update_tips != NULL) {
1465
+ if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
918
1466
  goto on_error;
919
1467
  }
920
1468
  }
921
1469
 
922
- if (git_remote_update_fetchhead(remote) &&
1470
+ if (update_fetchhead &&
923
1471
  (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
924
1472
  goto on_error;
925
1473
 
926
1474
  git_vector_free(&update_heads);
927
- git_refspec__free(&tagspec);
928
- git_buf_free(&refname);
1475
+ git_refspec__dispose(&tagspec);
1476
+ git_buf_dispose(&refname);
929
1477
  return 0;
930
1478
 
931
1479
  on_error:
932
1480
  git_vector_free(&update_heads);
933
- git_refspec__free(&tagspec);
934
- git_buf_free(&refname);
1481
+ git_refspec__dispose(&tagspec);
1482
+ git_buf_dispose(&refname);
935
1483
  return -1;
936
1484
 
937
1485
  }
938
1486
 
939
- int git_remote_update_tips(git_remote *remote)
1487
+ /**
1488
+ * Iteration over the three vectors, with a pause whenever we find a match
1489
+ *
1490
+ * On each stop, we store the iteration stat in the inout i,j,k
1491
+ * parameters, and return the currently matching passive refspec as
1492
+ * well as the head which we matched.
1493
+ */
1494
+ static int next_head(const git_remote *remote, git_vector *refs,
1495
+ git_refspec **out_spec, git_remote_head **out_head,
1496
+ size_t *out_i, size_t *out_j, size_t *out_k)
1497
+ {
1498
+ const git_vector *active, *passive;
1499
+ git_remote_head *head;
1500
+ git_refspec *spec, *passive_spec;
1501
+ size_t i, j, k;
1502
+
1503
+ active = &remote->active_refspecs;
1504
+ passive = &remote->passive_refspecs;
1505
+
1506
+ i = *out_i;
1507
+ j = *out_j;
1508
+ k = *out_k;
1509
+
1510
+ for (; i < refs->length; i++) {
1511
+ head = git_vector_get(refs, i);
1512
+
1513
+ if (!git_reference_is_valid_name(head->name))
1514
+ continue;
1515
+
1516
+ for (; j < active->length; j++) {
1517
+ spec = git_vector_get(active, j);
1518
+
1519
+ if (!git_refspec_src_matches(spec, head->name))
1520
+ continue;
1521
+
1522
+ for (; k < passive->length; k++) {
1523
+ passive_spec = git_vector_get(passive, k);
1524
+
1525
+ if (!git_refspec_src_matches(passive_spec, head->name))
1526
+ continue;
1527
+
1528
+ *out_spec = passive_spec;
1529
+ *out_head = head;
1530
+ *out_i = i;
1531
+ *out_j = j;
1532
+ *out_k = k + 1;
1533
+ return 0;
1534
+
1535
+ }
1536
+ k = 0;
1537
+ }
1538
+ j = 0;
1539
+ }
1540
+
1541
+ return GIT_ITEROVER;
1542
+ }
1543
+
1544
+ static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
1545
+ git_vector *refs, const char *msg)
1546
+ {
1547
+ size_t i, j, k;
1548
+ git_refspec *spec;
1549
+ git_remote_head *head;
1550
+ git_reference *ref;
1551
+ git_buf refname = GIT_BUF_INIT;
1552
+ int error = 0;
1553
+
1554
+ i = j = k = 0;
1555
+
1556
+ while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1557
+ git_oid old = {{ 0 }};
1558
+ /*
1559
+ * If we got here, there is a refspec which was used
1560
+ * for fetching which matches the source of one of the
1561
+ * passive refspecs, so we should update that
1562
+ * remote-tracking branch, but not add it to
1563
+ * FETCH_HEAD
1564
+ */
1565
+
1566
+ git_buf_clear(&refname);
1567
+ if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
1568
+ goto cleanup;
1569
+
1570
+ error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1571
+ if (error < 0 && error != GIT_ENOTFOUND)
1572
+ goto cleanup;
1573
+
1574
+ if (!git_oid_cmp(&old, &head->oid))
1575
+ continue;
1576
+
1577
+ /* If we did find a current reference, make sure we haven't lost a race */
1578
+ if (error)
1579
+ error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1580
+ else
1581
+ error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
1582
+ git_reference_free(ref);
1583
+ if (error < 0)
1584
+ goto cleanup;
1585
+
1586
+ if (callbacks && callbacks->update_tips != NULL) {
1587
+ if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1588
+ goto cleanup;
1589
+ }
1590
+ }
1591
+
1592
+ if (error == GIT_ITEROVER)
1593
+ error = 0;
1594
+
1595
+ cleanup:
1596
+ git_buf_dispose(&refname);
1597
+ return error;
1598
+ }
1599
+
1600
+ static int truncate_fetch_head(const char *gitdir)
1601
+ {
1602
+ git_buf path = GIT_BUF_INIT;
1603
+ int error;
1604
+
1605
+ if ((error = git_buf_joinpath(&path, gitdir, GIT_FETCH_HEAD_FILE)) < 0)
1606
+ return error;
1607
+
1608
+ error = git_futils_truncate(path.ptr, GIT_REFS_FILE_MODE);
1609
+ git_buf_dispose(&path);
1610
+
1611
+ return error;
1612
+ }
1613
+
1614
+ int git_remote_update_tips(
1615
+ git_remote *remote,
1616
+ const git_remote_callbacks *callbacks,
1617
+ int update_fetchhead,
1618
+ git_remote_autotag_option_t download_tags,
1619
+ const char *reflog_message)
940
1620
  {
941
1621
  git_refspec *spec, tagspec;
942
- git_vector refs;
1622
+ git_vector refs = GIT_VECTOR_INIT;
1623
+ git_remote_autotag_option_t tagopt;
943
1624
  int error;
944
1625
  size_t i;
945
1626
 
1627
+ /* push has its own logic hidden away in the push object */
1628
+ if (remote->push) {
1629
+ return git_push_update_tips(remote->push, callbacks);
1630
+ }
946
1631
 
947
1632
  if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
948
1633
  return -1;
949
1634
 
950
- if (git_vector_init(&refs, 16, NULL) < 0)
951
- return -1;
952
1635
 
953
- if ((error = git_remote_ls(remote, store_refs, &refs)) < 0)
1636
+ if ((error = ls_to_vector(&refs, remote)) < 0)
954
1637
  goto out;
955
1638
 
956
- if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
957
- error = update_tips_for_spec(remote, &tagspec, &refs);
1639
+ if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
1640
+ tagopt = remote->download_tags;
1641
+ else
1642
+ tagopt = download_tags;
1643
+
1644
+ if ((error = truncate_fetch_head(git_repository_path(remote->repo))) < 0)
958
1645
  goto out;
1646
+
1647
+ if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1648
+ if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
1649
+ goto out;
959
1650
  }
960
1651
 
961
- git_vector_foreach(&remote->refspecs, i, spec) {
1652
+ git_vector_foreach(&remote->active_refspecs, i, spec) {
962
1653
  if (spec->push)
963
1654
  continue;
964
1655
 
965
- if ((error = update_tips_for_spec(remote, spec, &refs)) < 0)
1656
+ if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
966
1657
  goto out;
967
1658
  }
968
1659
 
1660
+ /* only try to do opportunisitic updates if the refpec lists differ */
1661
+ if (remote->passed_refspecs)
1662
+ error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
1663
+
969
1664
  out:
970
- git_refspec__free(&tagspec);
971
1665
  git_vector_free(&refs);
1666
+ git_refspec__dispose(&tagspec);
972
1667
  return error;
973
1668
  }
974
1669
 
975
- int git_remote_connected(git_remote *remote)
1670
+ int git_remote_connected(const git_remote *remote)
976
1671
  {
977
1672
  assert(remote);
978
1673
 
@@ -1001,9 +1696,6 @@ void git_remote_disconnect(git_remote *remote)
1001
1696
 
1002
1697
  void git_remote_free(git_remote *remote)
1003
1698
  {
1004
- git_refspec *spec;
1005
- size_t i;
1006
-
1007
1699
  if (remote == NULL)
1008
1700
  return;
1009
1701
 
@@ -1016,150 +1708,120 @@ void git_remote_free(git_remote *remote)
1016
1708
 
1017
1709
  git_vector_free(&remote->refs);
1018
1710
 
1019
- git_vector_foreach(&remote->refspecs, i, spec) {
1020
- git_refspec__free(spec);
1021
- git__free(spec);
1022
- }
1711
+ free_refspecs(&remote->refspecs);
1023
1712
  git_vector_free(&remote->refspecs);
1024
1713
 
1714
+ free_refspecs(&remote->active_refspecs);
1715
+ git_vector_free(&remote->active_refspecs);
1716
+
1717
+ free_refspecs(&remote->passive_refspecs);
1718
+ git_vector_free(&remote->passive_refspecs);
1719
+
1720
+ git_push_free(remote->push);
1025
1721
  git__free(remote->url);
1026
1722
  git__free(remote->pushurl);
1027
1723
  git__free(remote->name);
1028
1724
  git__free(remote);
1029
1725
  }
1030
1726
 
1031
- struct cb_data {
1032
- git_vector *list;
1033
- regex_t *preg;
1034
- };
1035
-
1036
- static int remote_list_cb(const git_config_entry *entry, void *data_)
1727
+ static int remote_list_cb(const git_config_entry *entry, void *payload)
1037
1728
  {
1038
- struct cb_data *data = (struct cb_data *)data_;
1039
- size_t nmatch = 2;
1040
- regmatch_t pmatch[2];
1041
- const char *name = entry->name;
1729
+ git_vector *list = payload;
1730
+ const char *name = entry->name + strlen("remote.");
1731
+ size_t namelen = strlen(name);
1732
+ char *remote_name;
1042
1733
 
1043
- if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
1044
- char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
1045
- GITERR_CHECK_ALLOC(remote_name);
1734
+ /* we know name matches "remote.<stuff>.(push)?url" */
1046
1735
 
1047
- if (git_vector_insert(data->list, remote_name) < 0)
1048
- return -1;
1049
- }
1736
+ if (!strcmp(&name[namelen - 4], ".url"))
1737
+ remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1738
+ else
1739
+ remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
1740
+ GIT_ERROR_CHECK_ALLOC(remote_name);
1050
1741
 
1051
- return 0;
1742
+ return git_vector_insert(list, remote_name);
1052
1743
  }
1053
1744
 
1054
1745
  int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1055
1746
  {
1056
- git_config *cfg;
1057
- git_vector list;
1058
- regex_t preg;
1059
- struct cb_data data;
1060
1747
  int error;
1748
+ git_config *cfg;
1749
+ git_vector list = GIT_VECTOR_INIT;
1061
1750
 
1062
- if (git_repository_config__weakptr(&cfg, repo) < 0)
1063
- return -1;
1751
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1752
+ return error;
1064
1753
 
1065
- if (git_vector_init(&list, 4, NULL) < 0)
1066
- return -1;
1754
+ if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
1755
+ return error;
1067
1756
 
1068
- if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
1069
- giterr_set(GITERR_OS, "Remote catch regex failed to compile");
1070
- return -1;
1071
- }
1757
+ error = git_config_foreach_match(
1758
+ cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
1072
1759
 
1073
- data.list = &list;
1074
- data.preg = &preg;
1075
- error = git_config_foreach(cfg, remote_list_cb, &data);
1076
- regfree(&preg);
1077
1760
  if (error < 0) {
1078
- size_t i;
1079
- char *elem;
1080
- git_vector_foreach(&list, i, elem) {
1081
- git__free(elem);
1082
- }
1083
-
1084
- git_vector_free(&list);
1085
-
1086
- /* cb error is converted to GIT_EUSER by git_config_foreach */
1087
- if (error == GIT_EUSER)
1088
- error = -1;
1089
-
1761
+ git_vector_free_deep(&list);
1090
1762
  return error;
1091
1763
  }
1092
1764
 
1093
- remotes_list->strings = (char **)list.contents;
1094
- remotes_list->count = list.length;
1765
+ git_vector_uniq(&list, git__free);
1766
+
1767
+ remotes_list->strings =
1768
+ (char **)git_vector_detach(&remotes_list->count, NULL, &list);
1095
1769
 
1096
1770
  return 0;
1097
1771
  }
1098
1772
 
1099
- void git_remote_check_cert(git_remote *remote, int check)
1773
+ const git_transfer_progress* git_remote_stats(git_remote *remote)
1100
1774
  {
1101
1775
  assert(remote);
1102
-
1103
- remote->check_cert = check;
1776
+ return &remote->stats;
1104
1777
  }
1105
1778
 
1106
- int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
1779
+ git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1107
1780
  {
1108
- assert(remote && callbacks);
1109
-
1110
- GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1111
-
1112
- memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
1113
-
1114
- if (remote->transport && remote->transport->set_callbacks)
1115
- remote->transport->set_callbacks(remote->transport,
1116
- remote->callbacks.progress,
1117
- NULL,
1118
- remote->callbacks.payload);
1119
-
1120
- return 0;
1781
+ return remote->download_tags;
1121
1782
  }
1122
1783
 
1123
- void git_remote_set_cred_acquire_cb(
1124
- git_remote *remote,
1125
- git_cred_acquire_cb cred_acquire_cb,
1126
- void *payload)
1784
+ int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
1127
1785
  {
1128
- assert(remote);
1129
-
1130
- remote->cred_acquire_cb = cred_acquire_cb;
1131
- remote->cred_acquire_payload = payload;
1132
- }
1786
+ git_buf var = GIT_BUF_INIT;
1787
+ git_config *config;
1788
+ int error;
1133
1789
 
1134
- int git_remote_set_transport(git_remote *remote, git_transport *transport)
1135
- {
1136
- assert(remote && transport);
1790
+ assert(repo && remote);
1137
1791
 
1138
- GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
1792
+ if ((error = ensure_remote_name_is_valid(remote)) < 0)
1793
+ return error;
1139
1794
 
1140
- if (remote->transport) {
1141
- giterr_set(GITERR_NET, "A transport is already bound to this remote");
1142
- return -1;
1143
- }
1795
+ if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1796
+ return error;
1144
1797
 
1145
- remote->transport = transport;
1146
- return 0;
1147
- }
1798
+ if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
1799
+ return error;
1148
1800
 
1149
- const git_transfer_progress* git_remote_stats(git_remote *remote)
1150
- {
1151
- assert(remote);
1152
- return &remote->stats;
1153
- }
1801
+ switch (value) {
1802
+ case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
1803
+ error = git_config_set_string(config, var.ptr, "--no-tags");
1804
+ break;
1805
+ case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
1806
+ error = git_config_set_string(config, var.ptr, "--tags");
1807
+ break;
1808
+ case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
1809
+ error = git_config_delete_entry(config, var.ptr);
1810
+ if (error == GIT_ENOTFOUND)
1811
+ error = 0;
1812
+ break;
1813
+ default:
1814
+ git_error_set(GIT_ERROR_INVALID, "invalid value for the tagopt setting");
1815
+ error = -1;
1816
+ }
1154
1817
 
1155
- git_remote_autotag_option_t git_remote_autotag(git_remote *remote)
1156
- {
1157
- return remote->download_tags;
1818
+ git_buf_dispose(&var);
1819
+ return error;
1158
1820
  }
1159
1821
 
1160
- void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value)
1822
+ int git_remote_prune_refs(const git_remote *remote)
1161
1823
  {
1162
- remote->download_tags = value;
1824
+ return remote->prune_refs;
1163
1825
  }
1164
1826
 
1165
1827
  static int rename_remote_config_section(
@@ -1174,23 +1836,23 @@ static int rename_remote_config_section(
1174
1836
  if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1175
1837
  goto cleanup;
1176
1838
 
1177
- if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0)
1178
- goto cleanup;
1839
+ if (new_name &&
1840
+ (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1841
+ goto cleanup;
1179
1842
 
1180
1843
  error = git_config_rename_section(
1181
1844
  repo,
1182
1845
  git_buf_cstr(&old_section_name),
1183
- git_buf_cstr(&new_section_name));
1846
+ new_name ? git_buf_cstr(&new_section_name) : NULL);
1184
1847
 
1185
1848
  cleanup:
1186
- git_buf_free(&old_section_name);
1187
- git_buf_free(&new_section_name);
1849
+ git_buf_dispose(&old_section_name);
1850
+ git_buf_dispose(&new_section_name);
1188
1851
 
1189
1852
  return error;
1190
1853
  }
1191
1854
 
1192
- struct update_data
1193
- {
1855
+ struct update_data {
1194
1856
  git_config *config;
1195
1857
  const char *old_remote_name;
1196
1858
  const char *new_remote_name;
@@ -1206,9 +1868,7 @@ static int update_config_entries_cb(
1206
1868
  return 0;
1207
1869
 
1208
1870
  return git_config_set_string(
1209
- data->config,
1210
- entry->name,
1211
- data->new_remote_name);
1871
+ data->config, entry->name, data->new_remote_name);
1212
1872
  }
1213
1873
 
1214
1874
  static int update_branch_remote_config_entry(
@@ -1216,214 +1876,213 @@ static int update_branch_remote_config_entry(
1216
1876
  const char *old_name,
1217
1877
  const char *new_name)
1218
1878
  {
1219
- git_config *config;
1220
- struct update_data data;
1879
+ int error;
1880
+ struct update_data data = { NULL };
1221
1881
 
1222
- if (git_repository_config__weakptr(&config, repo) < 0)
1223
- return -1;
1882
+ if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1883
+ return error;
1224
1884
 
1225
- data.config = config;
1226
1885
  data.old_remote_name = old_name;
1227
1886
  data.new_remote_name = new_name;
1228
1887
 
1229
1888
  return git_config_foreach_match(
1230
- config,
1231
- "branch\\..+\\.remote",
1232
- update_config_entries_cb, &data);
1889
+ data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
1233
1890
  }
1234
1891
 
1235
1892
  static int rename_one_remote_reference(
1236
- git_reference *reference,
1893
+ git_reference *reference_in,
1237
1894
  const char *old_remote_name,
1238
1895
  const char *new_remote_name)
1239
1896
  {
1240
- int error = -1;
1897
+ int error;
1898
+ git_reference *ref = NULL, *dummy = NULL;
1899
+ git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
1241
1900
  git_buf new_name = GIT_BUF_INIT;
1901
+ git_buf log_message = GIT_BUF_INIT;
1902
+ size_t pfx_len;
1903
+ const char *target;
1242
1904
 
1243
- if (git_buf_printf(
1244
- &new_name,
1245
- GIT_REFS_REMOTES_DIR "%s%s",
1246
- new_remote_name,
1247
- reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0)
1248
- return -1;
1905
+ if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1906
+ return error;
1249
1907
 
1250
- error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0);
1251
- git_reference_free(reference);
1908
+ pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1909
+ git_buf_puts(&new_name, namespace.ptr);
1910
+ if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
1911
+ goto cleanup;
1252
1912
 
1253
- git_buf_free(&new_name);
1254
- return error;
1255
- }
1913
+ if ((error = git_buf_printf(&log_message,
1914
+ "renamed remote %s to %s",
1915
+ old_remote_name, new_remote_name)) < 0)
1916
+ goto cleanup;
1256
1917
 
1257
- static int rename_remote_references(
1258
- git_repository *repo,
1259
- const char *old_name,
1918
+ if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1919
+ git_buf_cstr(&log_message))) < 0)
1920
+ goto cleanup;
1921
+
1922
+ if (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC)
1923
+ goto cleanup;
1924
+
1925
+ /* Handle refs like origin/HEAD -> origin/master */
1926
+ target = git_reference_symbolic_target(ref);
1927
+ if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1928
+ goto cleanup;
1929
+
1930
+ if (git__prefixcmp(target, old_namespace.ptr))
1931
+ goto cleanup;
1932
+
1933
+ git_buf_clear(&new_name);
1934
+ git_buf_puts(&new_name, namespace.ptr);
1935
+ if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1936
+ goto cleanup;
1937
+
1938
+ error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
1939
+ git_buf_cstr(&log_message));
1940
+
1941
+ git_reference_free(dummy);
1942
+
1943
+ cleanup:
1944
+ git_reference_free(reference_in);
1945
+ git_reference_free(ref);
1946
+ git_buf_dispose(&namespace);
1947
+ git_buf_dispose(&old_namespace);
1948
+ git_buf_dispose(&new_name);
1949
+ git_buf_dispose(&log_message);
1950
+ return error;
1951
+ }
1952
+
1953
+ static int rename_remote_references(
1954
+ git_repository *repo,
1955
+ const char *old_name,
1260
1956
  const char *new_name)
1261
1957
  {
1262
- int error = -1;
1958
+ int error;
1959
+ git_buf buf = GIT_BUF_INIT;
1263
1960
  git_reference *ref;
1264
1961
  git_reference_iterator *iter;
1265
1962
 
1266
- if (git_reference_iterator_new(&iter, repo) < 0)
1267
- return -1;
1963
+ if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
1964
+ return error;
1268
1965
 
1269
- while ((error = git_reference_next(&ref, iter)) == 0) {
1270
- if (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) {
1271
- git_reference_free(ref);
1272
- continue;
1273
- }
1966
+ error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1967
+ git_buf_dispose(&buf);
1274
1968
 
1275
- if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) {
1276
- git_reference_iterator_free(iter);
1277
- return error;
1278
- }
1969
+ if (error < 0)
1970
+ return error;
1971
+
1972
+ while ((error = git_reference_next(&ref, iter)) == 0) {
1973
+ if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1974
+ break;
1279
1975
  }
1280
1976
 
1281
1977
  git_reference_iterator_free(iter);
1282
1978
 
1283
- if (error == GIT_ITEROVER)
1284
- return 0;
1285
-
1286
- return error;
1979
+ return (error == GIT_ITEROVER) ? 0 : error;
1287
1980
  }
1288
1981
 
1289
- static int rename_fetch_refspecs(
1290
- git_remote *remote,
1291
- const char *new_name,
1292
- int (*callback)(const char *problematic_refspec, void *payload),
1293
- void *payload)
1982
+ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
1294
1983
  {
1295
1984
  git_config *config;
1296
1985
  git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1297
1986
  const git_refspec *spec;
1298
1987
  size_t i;
1299
- int error = -1;
1988
+ int error = 0;
1300
1989
 
1301
- if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0)
1302
- goto cleanup;
1990
+ if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
1991
+ return error;
1992
+
1993
+ if ((error = git_vector_init(problems, 1, NULL)) < 0)
1994
+ return error;
1995
+
1996
+ if ((error = default_fetchspec_for_name(&base, remote->name)) < 0)
1997
+ return error;
1303
1998
 
1304
1999
  git_vector_foreach(&remote->refspecs, i, spec) {
1305
2000
  if (spec->push)
1306
2001
  continue;
1307
2002
 
1308
- /* Every refspec is a problem refspec for an in-memory remote */
1309
- if (!remote->name) {
1310
- if (callback(spec->string, payload) < 0) {
1311
- error = GIT_EUSER;
1312
- goto cleanup;
1313
- }
2003
+ /* Does the dst part of the refspec follow the expected format? */
2004
+ if (strcmp(git_buf_cstr(&base), spec->string)) {
2005
+ char *dup;
1314
2006
 
1315
- continue;
1316
- }
2007
+ dup = git__strdup(spec->string);
2008
+ GIT_ERROR_CHECK_ALLOC(dup);
1317
2009
 
1318
- /* Does the dst part of the refspec follow the extected standard format? */
1319
- if (strcmp(git_buf_cstr(&base), spec->string)) {
1320
- if (callback(spec->string, payload) < 0) {
1321
- error = GIT_EUSER;
1322
- goto cleanup;
1323
- }
2010
+ if ((error = git_vector_insert(problems, dup)) < 0)
2011
+ break;
1324
2012
 
1325
2013
  continue;
1326
2014
  }
1327
2015
 
1328
2016
  /* If we do want to move it to the new section */
1329
- if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0)
1330
- goto cleanup;
1331
2017
 
1332
- if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1333
- goto cleanup;
2018
+ git_buf_clear(&val);
2019
+ git_buf_clear(&var);
1334
2020
 
1335
- if (git_repository_config__weakptr(&config, remote->repo) < 0)
1336
- goto cleanup;
2021
+ if (default_fetchspec_for_name(&val, new_name) < 0 ||
2022
+ git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
2023
+ {
2024
+ error = -1;
2025
+ break;
2026
+ }
1337
2027
 
1338
- if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0)
1339
- goto cleanup;
2028
+ if ((error = git_config_set_string(
2029
+ config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
2030
+ break;
1340
2031
  }
1341
2032
 
1342
- error = 0;
2033
+ git_buf_dispose(&base);
2034
+ git_buf_dispose(&var);
2035
+ git_buf_dispose(&val);
2036
+
2037
+ if (error < 0) {
2038
+ char *str;
2039
+ git_vector_foreach(problems, i, str)
2040
+ git__free(str);
2041
+
2042
+ git_vector_free(problems);
2043
+ }
1343
2044
 
1344
- cleanup:
1345
- git_buf_free(&base);
1346
- git_buf_free(&var);
1347
- git_buf_free(&val);
1348
2045
  return error;
1349
2046
  }
1350
2047
 
1351
- int git_remote_rename(
1352
- git_remote *remote,
1353
- const char *new_name,
1354
- git_remote_rename_problem_cb callback,
1355
- void *payload)
2048
+ int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
1356
2049
  {
1357
2050
  int error;
2051
+ git_vector problem_refspecs = GIT_VECTOR_INIT;
2052
+ git_remote *remote = NULL;
1358
2053
 
1359
- assert(remote && new_name);
2054
+ assert(out && repo && name && new_name);
1360
2055
 
1361
- if (!remote->name) {
1362
- giterr_set(GITERR_INVALID, "Can't rename an in-memory remote.");
1363
- return GIT_EINVALIDSPEC;
1364
- }
1365
-
1366
- if ((error = ensure_remote_name_is_valid(new_name)) < 0)
2056
+ if ((error = git_remote_lookup(&remote, repo, name)) < 0)
1367
2057
  return error;
1368
2058
 
1369
- if (remote->repo) {
1370
- if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1371
- return error;
2059
+ if ((error = ensure_remote_name_is_valid(new_name)) < 0)
2060
+ goto cleanup;
1372
2061
 
1373
- if (!remote->name) {
1374
- if ((error = rename_fetch_refspecs(
1375
- remote,
1376
- new_name,
1377
- callback,
1378
- payload)) < 0)
1379
- return error;
2062
+ if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
2063
+ goto cleanup;
1380
2064
 
1381
- remote->name = git__strdup(new_name);
2065
+ if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
2066
+ goto cleanup;
1382
2067
 
1383
- if (!remote->name) return 0;
1384
- return git_remote_save(remote);
1385
- }
2068
+ if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
2069
+ goto cleanup;
1386
2070
 
1387
- if ((error = rename_remote_config_section(
1388
- remote->repo,
1389
- remote->name,
1390
- new_name)) < 0)
1391
- return error;
1392
-
1393
- if ((error = update_branch_remote_config_entry(
1394
- remote->repo,
1395
- remote->name,
1396
- new_name)) < 0)
1397
- return error;
1398
-
1399
- if ((error = rename_remote_references(
1400
- remote->repo,
1401
- remote->name,
1402
- new_name)) < 0)
1403
- return error;
1404
-
1405
- if ((error = rename_fetch_refspecs(
1406
- remote,
1407
- new_name,
1408
- callback,
1409
- payload)) < 0)
1410
- return error;
1411
- }
2071
+ if ((error = rename_remote_references(repo, name, new_name)) < 0)
2072
+ goto cleanup;
1412
2073
 
1413
- git__free(remote->name);
1414
- remote->name = git__strdup(new_name);
2074
+ if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
2075
+ goto cleanup;
1415
2076
 
1416
- return 0;
1417
- }
2077
+ out->count = problem_refspecs.length;
2078
+ out->strings = (char **) problem_refspecs.contents;
1418
2079
 
1419
- int git_remote_update_fetchhead(git_remote *remote)
1420
- {
1421
- return remote->update_fetchhead;
1422
- }
2080
+ cleanup:
2081
+ if (error < 0)
2082
+ git_vector_free(&problem_refspecs);
1423
2083
 
1424
- void git_remote_set_update_fetchhead(git_remote *remote, int value)
1425
- {
1426
- remote->update_fetchhead = value;
2084
+ git_remote_free(remote);
2085
+ return error;
1427
2086
  }
1428
2087
 
1429
2088
  int git_remote_is_valid_name(
@@ -1439,10 +2098,10 @@ int git_remote_is_valid_name(
1439
2098
  git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
1440
2099
  error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
1441
2100
 
1442
- git_buf_free(&buf);
1443
- git_refspec__free(&refspec);
2101
+ git_buf_dispose(&buf);
2102
+ git_refspec__dispose(&refspec);
1444
2103
 
1445
- giterr_clear();
2104
+ git_error_clear();
1446
2105
  return error == 0;
1447
2106
  }
1448
2107
 
@@ -1451,7 +2110,7 @@ git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refnam
1451
2110
  git_refspec *spec;
1452
2111
  size_t i;
1453
2112
 
1454
- git_vector_foreach(&remote->refspecs, i, spec) {
2113
+ git_vector_foreach(&remote->active_refspecs, i, spec) {
1455
2114
  if (spec->push)
1456
2115
  continue;
1457
2116
 
@@ -1467,7 +2126,7 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re
1467
2126
  git_refspec *spec;
1468
2127
  size_t i;
1469
2128
 
1470
- git_vector_foreach(&remote->refspecs, i, spec) {
2129
+ git_vector_foreach(&remote->active_refspecs, i, spec) {
1471
2130
  if (spec->push)
1472
2131
  continue;
1473
2132
 
@@ -1478,29 +2137,17 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re
1478
2137
  return NULL;
1479
2138
  }
1480
2139
 
1481
- void git_remote_clear_refspecs(git_remote *remote)
1482
- {
1483
- git_refspec *spec;
1484
- size_t i;
1485
-
1486
- git_vector_foreach(&remote->refspecs, i, spec) {
1487
- git_refspec__free(spec);
1488
- git__free(spec);
1489
- }
1490
- git_vector_clear(&remote->refspecs);
1491
- }
1492
-
1493
- int git_remote_add_fetch(git_remote *remote, const char *refspec)
2140
+ int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
1494
2141
  {
1495
- return add_refspec(remote, refspec, true);
2142
+ return write_add_refspec(repo, remote, refspec, true);
1496
2143
  }
1497
2144
 
1498
- int git_remote_add_push(git_remote *remote, const char *refspec)
2145
+ int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
1499
2146
  {
1500
- return add_refspec(remote, refspec, false);
2147
+ return write_add_refspec(repo, remote, refspec, false);
1501
2148
  }
1502
2149
 
1503
- static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
2150
+ static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
1504
2151
  {
1505
2152
  size_t i;
1506
2153
  git_vector refspecs;
@@ -1529,44 +2176,415 @@ static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
1529
2176
  return 0;
1530
2177
 
1531
2178
  on_error:
1532
- git_vector_foreach(&refspecs, i, dup)
1533
- git__free(dup);
1534
- git_vector_free(&refspecs);
2179
+ git_vector_free_deep(&refspecs);
1535
2180
 
1536
2181
  return -1;
1537
2182
  }
1538
2183
 
1539
- int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote)
2184
+ int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
1540
2185
  {
1541
2186
  return copy_refspecs(array, remote, false);
1542
2187
  }
1543
2188
 
1544
- int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote)
2189
+ int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
1545
2190
  {
1546
2191
  return copy_refspecs(array, remote, true);
1547
2192
  }
1548
2193
 
1549
- size_t git_remote_refspec_count(git_remote *remote)
2194
+ size_t git_remote_refspec_count(const git_remote *remote)
1550
2195
  {
1551
2196
  return remote->refspecs.length;
1552
2197
  }
1553
2198
 
1554
- const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n)
2199
+ const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1555
2200
  {
1556
2201
  return git_vector_get(&remote->refspecs, n);
1557
2202
  }
1558
2203
 
1559
- int git_remote_remove_refspec(git_remote *remote, size_t n)
2204
+ int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
2205
+ {
2206
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2207
+ opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
2208
+ return 0;
2209
+ }
2210
+
2211
+ /* asserts a branch.<foo>.remote format */
2212
+ static const char *name_offset(size_t *len_out, const char *name)
1560
2213
  {
2214
+ size_t prefix_len;
2215
+ const char *dot;
2216
+
2217
+ prefix_len = strlen("remote.");
2218
+ dot = strchr(name + prefix_len, '.');
2219
+
2220
+ assert(dot);
2221
+
2222
+ *len_out = dot - name - prefix_len;
2223
+ return name + prefix_len;
2224
+ }
2225
+
2226
+ static int remove_branch_config_related_entries(
2227
+ git_repository *repo,
2228
+ const char *remote_name)
2229
+ {
2230
+ int error;
2231
+ git_config *config;
2232
+ git_config_entry *entry;
2233
+ git_config_iterator *iter;
2234
+ git_buf buf = GIT_BUF_INIT;
2235
+
2236
+ if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2237
+ return error;
2238
+
2239
+ if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
2240
+ return error;
2241
+
2242
+ /* find any branches with us as upstream and remove that config */
2243
+ while ((error = git_config_next(&entry, iter)) == 0) {
2244
+ const char *branch;
2245
+ size_t branch_len;
2246
+
2247
+ if (strcmp(remote_name, entry->value))
2248
+ continue;
2249
+
2250
+ branch = name_offset(&branch_len, entry->name);
2251
+
2252
+ git_buf_clear(&buf);
2253
+ if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
2254
+ break;
2255
+
2256
+ if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
2257
+ if (error != GIT_ENOTFOUND)
2258
+ break;
2259
+ git_error_clear();
2260
+ }
2261
+
2262
+ git_buf_clear(&buf);
2263
+ if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
2264
+ break;
2265
+
2266
+ if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
2267
+ if (error != GIT_ENOTFOUND)
2268
+ break;
2269
+ git_error_clear();
2270
+ }
2271
+ }
2272
+
2273
+ if (error == GIT_ITEROVER)
2274
+ error = 0;
2275
+
2276
+ git_buf_dispose(&buf);
2277
+ git_config_iterator_free(iter);
2278
+ return error;
2279
+ }
2280
+
2281
+ static int remove_refs(git_repository *repo, const git_refspec *spec)
2282
+ {
2283
+ git_reference_iterator *iter = NULL;
2284
+ git_vector refs;
2285
+ const char *name;
2286
+ char *dup;
2287
+ int error;
2288
+ size_t i;
2289
+
2290
+ if ((error = git_vector_init(&refs, 8, NULL)) < 0)
2291
+ return error;
2292
+
2293
+ if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2294
+ goto cleanup;
2295
+
2296
+ while ((error = git_reference_next_name(&name, iter)) == 0) {
2297
+ if (!git_refspec_dst_matches(spec, name))
2298
+ continue;
2299
+
2300
+ dup = git__strdup(name);
2301
+ if (!dup) {
2302
+ error = -1;
2303
+ goto cleanup;
2304
+ }
2305
+
2306
+ if ((error = git_vector_insert(&refs, dup)) < 0)
2307
+ goto cleanup;
2308
+ }
2309
+ if (error == GIT_ITEROVER)
2310
+ error = 0;
2311
+ if (error < 0)
2312
+ goto cleanup;
2313
+
2314
+ git_vector_foreach(&refs, i, name) {
2315
+ if ((error = git_reference_remove(repo, name)) < 0)
2316
+ break;
2317
+ }
2318
+
2319
+ cleanup:
2320
+ git_reference_iterator_free(iter);
2321
+ git_vector_foreach(&refs, i, dup) {
2322
+ git__free(dup);
2323
+ }
2324
+ git_vector_free(&refs);
2325
+ return error;
2326
+ }
2327
+
2328
+ static int remove_remote_tracking(git_repository *repo, const char *remote_name)
2329
+ {
2330
+ git_remote *remote;
2331
+ int error;
2332
+ size_t i, count;
2333
+
2334
+ /* we want to use what's on the config, regardless of changes to the instance in memory */
2335
+ if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
2336
+ return error;
2337
+
2338
+ count = git_remote_refspec_count(remote);
2339
+ for (i = 0; i < count; i++) {
2340
+ const git_refspec *refspec = git_remote_get_refspec(remote, i);
2341
+
2342
+ /* shouldn't ever actually happen */
2343
+ if (refspec == NULL)
2344
+ continue;
2345
+
2346
+ if ((error = remove_refs(repo, refspec)) < 0)
2347
+ break;
2348
+ }
2349
+
2350
+ git_remote_free(remote);
2351
+ return error;
2352
+ }
2353
+
2354
+ int git_remote_delete(git_repository *repo, const char *name)
2355
+ {
2356
+ int error;
2357
+
2358
+ assert(repo && name);
2359
+
2360
+ if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
2361
+ (error = remove_remote_tracking(repo, name)) < 0 ||
2362
+ (error = rename_remote_config_section(repo, name, NULL)) < 0)
2363
+ return error;
2364
+
2365
+ return 0;
2366
+ }
2367
+
2368
+ int git_remote_default_branch(git_buf *out, git_remote *remote)
2369
+ {
2370
+ const git_remote_head **heads;
2371
+ const git_remote_head *guess = NULL;
2372
+ const git_oid *head_id;
2373
+ size_t heads_len, i;
2374
+ int error;
2375
+
2376
+ assert(out);
2377
+
2378
+ if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2379
+ return error;
2380
+
2381
+ if (heads_len == 0)
2382
+ return GIT_ENOTFOUND;
2383
+
2384
+ if (strcmp(heads[0]->name, GIT_HEAD_FILE))
2385
+ return GIT_ENOTFOUND;
2386
+
2387
+ git_buf_sanitize(out);
2388
+ /* the first one must be HEAD so if that has the symref info, we're done */
2389
+ if (heads[0]->symref_target)
2390
+ return git_buf_puts(out, heads[0]->symref_target);
2391
+
2392
+ /*
2393
+ * If there's no symref information, we have to look over them
2394
+ * and guess. We return the first match unless the master
2395
+ * branch is a candidate. Then we return the master branch.
2396
+ */
2397
+ head_id = &heads[0]->oid;
2398
+
2399
+ for (i = 1; i < heads_len; i++) {
2400
+ if (git_oid_cmp(head_id, &heads[i]->oid))
2401
+ continue;
2402
+
2403
+ if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
2404
+ continue;
2405
+
2406
+ if (!guess) {
2407
+ guess = heads[i];
2408
+ continue;
2409
+ }
2410
+
2411
+ if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
2412
+ guess = heads[i];
2413
+ break;
2414
+ }
2415
+ }
2416
+
2417
+ if (!guess)
2418
+ return GIT_ENOTFOUND;
2419
+
2420
+ return git_buf_puts(out, guess->name);
2421
+ }
2422
+
2423
+ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2424
+ {
2425
+ size_t i;
2426
+ int error;
2427
+ git_push *push;
1561
2428
  git_refspec *spec;
2429
+ const git_remote_callbacks *cbs = NULL;
2430
+ git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
1562
2431
 
1563
2432
  assert(remote);
1564
2433
 
1565
- spec = git_vector_get(&remote->refspecs, n);
1566
- if (spec) {
1567
- git_refspec__free(spec);
1568
- git__free(spec);
2434
+ if (!remote->repo) {
2435
+ git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2436
+ return -1;
2437
+ }
2438
+
2439
+ if (opts) {
2440
+ cbs = &opts->callbacks;
2441
+ conn.custom_headers = &opts->custom_headers;
2442
+ conn.proxy = &opts->proxy_opts;
2443
+ }
2444
+
2445
+ if (!git_remote_connected(remote) &&
2446
+ (error = git_remote__connect(remote, GIT_DIRECTION_PUSH, cbs, &conn)) < 0)
2447
+ goto cleanup;
2448
+
2449
+ free_refspecs(&remote->active_refspecs);
2450
+ if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
2451
+ goto cleanup;
2452
+
2453
+ if (remote->push) {
2454
+ git_push_free(remote->push);
2455
+ remote->push = NULL;
1569
2456
  }
1570
2457
 
1571
- return git_vector_remove(&remote->refspecs, n);
2458
+ if ((error = git_push_new(&remote->push, remote)) < 0)
2459
+ return error;
2460
+
2461
+ push = remote->push;
2462
+
2463
+ if (opts && (error = git_push_set_options(push, opts)) < 0)
2464
+ goto cleanup;
2465
+
2466
+ if (refspecs && refspecs->count > 0) {
2467
+ for (i = 0; i < refspecs->count; i++) {
2468
+ if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
2469
+ goto cleanup;
2470
+ }
2471
+ } else {
2472
+ git_vector_foreach(&remote->refspecs, i, spec) {
2473
+ if (!spec->push)
2474
+ continue;
2475
+ if ((error = git_push_add_refspec(push, spec->string)) < 0)
2476
+ goto cleanup;
2477
+ }
2478
+ }
2479
+
2480
+ if ((error = git_push_finish(push, cbs)) < 0)
2481
+ goto cleanup;
2482
+
2483
+ if (cbs && cbs->push_update_reference &&
2484
+ (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
2485
+ goto cleanup;
2486
+
2487
+ cleanup:
2488
+ return error;
2489
+ }
2490
+
2491
+ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2492
+ {
2493
+ int error;
2494
+ const git_remote_callbacks *cbs = NULL;
2495
+ const git_strarray *custom_headers = NULL;
2496
+ const git_proxy_options *proxy = NULL;
2497
+
2498
+ assert(remote);
2499
+
2500
+ if (!remote->repo) {
2501
+ git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2502
+ return -1;
2503
+ }
2504
+
2505
+ if (opts) {
2506
+ GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2507
+ cbs = &opts->callbacks;
2508
+ custom_headers = &opts->custom_headers;
2509
+ GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
2510
+ proxy = &opts->proxy_opts;
2511
+ }
2512
+
2513
+ assert(remote);
2514
+
2515
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
2516
+ return error;
2517
+
2518
+ if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2519
+ return error;
2520
+
2521
+ error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
2522
+
2523
+ git_remote_disconnect(remote);
2524
+ return error;
2525
+ }
2526
+
2527
+ #define PREFIX "url"
2528
+ #define SUFFIX_FETCH "insteadof"
2529
+ #define SUFFIX_PUSH "pushinsteadof"
2530
+
2531
+ char *apply_insteadof(git_config *config, const char *url, int direction)
2532
+ {
2533
+ size_t match_length, prefix_length, suffix_length;
2534
+ char *replacement = NULL;
2535
+ const char *regexp;
2536
+
2537
+ git_buf result = GIT_BUF_INIT;
2538
+ git_config_entry *entry;
2539
+ git_config_iterator *iter;
2540
+
2541
+ assert(config);
2542
+ assert(url);
2543
+ assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
2544
+
2545
+ /* Add 1 to prefix/suffix length due to the additional escaped dot */
2546
+ prefix_length = strlen(PREFIX) + 1;
2547
+ if (direction == GIT_DIRECTION_FETCH) {
2548
+ regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
2549
+ suffix_length = strlen(SUFFIX_FETCH) + 1;
2550
+ } else {
2551
+ regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
2552
+ suffix_length = strlen(SUFFIX_PUSH) + 1;
2553
+ }
2554
+
2555
+ if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
2556
+ return NULL;
2557
+
2558
+ match_length = 0;
2559
+ while (git_config_next(&entry, iter) == 0) {
2560
+ size_t n, replacement_length;
2561
+
2562
+ /* Check if entry value is a prefix of URL */
2563
+ if (git__prefixcmp(url, entry->value))
2564
+ continue;
2565
+ /* Check if entry value is longer than previous
2566
+ * prefixes */
2567
+ if ((n = strlen(entry->value)) <= match_length)
2568
+ continue;
2569
+
2570
+ git__free(replacement);
2571
+ match_length = n;
2572
+
2573
+ /* Cut off prefix and suffix of the value */
2574
+ replacement_length =
2575
+ strlen(entry->name) - (prefix_length + suffix_length);
2576
+ replacement = git__strndup(entry->name + prefix_length,
2577
+ replacement_length);
2578
+ }
2579
+
2580
+ git_config_iterator_free(iter);
2581
+
2582
+ if (match_length == 0)
2583
+ return git__strdup(url);
2584
+
2585
+ git_buf_printf(&result, "%s%s", replacement, url + match_length);
2586
+
2587
+ git__free(replacement);
2588
+
2589
+ return result.ptr;
1572
2590
  }