rugged 0.19.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (453) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/README.md +151 -25
  4. data/ext/rugged/extconf.rb +48 -27
  5. data/ext/rugged/rugged.c +107 -35
  6. data/ext/rugged/rugged.h +44 -8
  7. data/ext/rugged/rugged_blame.c +292 -0
  8. data/ext/rugged/rugged_blob.c +84 -31
  9. data/ext/rugged/rugged_branch.c +90 -223
  10. data/ext/rugged/rugged_branch_collection.c +445 -0
  11. data/ext/rugged/rugged_commit.c +190 -9
  12. data/ext/rugged/rugged_config.c +1 -1
  13. data/ext/rugged/rugged_cred.c +125 -0
  14. data/ext/rugged/rugged_diff.c +267 -94
  15. data/ext/rugged/rugged_diff_delta.c +14 -3
  16. data/ext/rugged/rugged_diff_hunk.c +31 -28
  17. data/ext/rugged/rugged_diff_line.c +21 -17
  18. data/ext/rugged/rugged_index.c +326 -6
  19. data/ext/rugged/rugged_note.c +39 -34
  20. data/ext/rugged/rugged_object.c +9 -9
  21. data/ext/rugged/rugged_patch.c +245 -0
  22. data/ext/rugged/rugged_reference.c +67 -332
  23. data/ext/rugged/rugged_reference_collection.c +490 -0
  24. data/ext/rugged/rugged_remote.c +447 -351
  25. data/ext/rugged/rugged_remote_collection.c +285 -0
  26. data/ext/rugged/rugged_repo.c +752 -203
  27. data/ext/rugged/rugged_revwalk.c +119 -27
  28. data/ext/rugged/rugged_settings.c +48 -1
  29. data/ext/rugged/rugged_signature.c +30 -16
  30. data/ext/rugged/rugged_tag.c +86 -191
  31. data/ext/rugged/rugged_tag_collection.c +279 -0
  32. data/ext/rugged/rugged_tree.c +159 -22
  33. data/lib/rugged/branch.rb +8 -17
  34. data/lib/rugged/credentials.rb +43 -0
  35. data/lib/rugged/diff/delta.rb +1 -2
  36. data/lib/rugged/diff/hunk.rb +4 -9
  37. data/lib/rugged/diff/line.rb +23 -3
  38. data/lib/rugged/diff.rb +3 -1
  39. data/lib/rugged/patch.rb +26 -0
  40. data/lib/rugged/reference.rb +1 -3
  41. data/lib/rugged/remote.rb +0 -9
  42. data/lib/rugged/repository.rb +70 -13
  43. data/lib/rugged/tag.rb +23 -18
  44. data/lib/rugged/tree.rb +7 -0
  45. data/lib/rugged/version.rb +1 -1
  46. data/lib/rugged.rb +8 -1
  47. data/vendor/libgit2/AUTHORS +75 -0
  48. data/vendor/libgit2/CMakeLists.txt +490 -0
  49. data/vendor/libgit2/COPYING +920 -0
  50. data/vendor/libgit2/Makefile.embed +25 -7
  51. data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +16 -0
  52. data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
  53. data/vendor/libgit2/cmake/Modules/FindIconv.cmake +43 -0
  54. data/vendor/libgit2/cmake/Modules/FindLIBSSH2.cmake +44 -0
  55. data/vendor/libgit2/deps/http-parser/LICENSE-MIT +23 -0
  56. data/vendor/libgit2/deps/regex/regex.c +10 -3
  57. data/vendor/libgit2/include/git2/attr.h +2 -1
  58. data/vendor/libgit2/include/git2/blame.h +213 -0
  59. data/vendor/libgit2/include/git2/blob.h +57 -29
  60. data/vendor/libgit2/include/git2/branch.h +56 -44
  61. data/vendor/libgit2/include/git2/buffer.h +112 -0
  62. data/vendor/libgit2/include/git2/checkout.h +72 -37
  63. data/vendor/libgit2/include/git2/cherrypick.h +87 -0
  64. data/vendor/libgit2/include/git2/clone.h +153 -56
  65. data/vendor/libgit2/include/git2/commit.h +82 -12
  66. data/vendor/libgit2/include/git2/common.h +31 -19
  67. data/vendor/libgit2/include/git2/config.h +124 -19
  68. data/vendor/libgit2/include/git2/cred_helpers.h +1 -1
  69. data/vendor/libgit2/include/git2/diff.h +636 -494
  70. data/vendor/libgit2/include/git2/errors.h +48 -15
  71. data/vendor/libgit2/include/git2/filter.h +149 -0
  72. data/vendor/libgit2/include/git2/graph.h +14 -0
  73. data/vendor/libgit2/include/git2/index.h +95 -54
  74. data/vendor/libgit2/include/git2/indexer.h +15 -9
  75. data/vendor/libgit2/include/git2/merge.h +402 -39
  76. data/vendor/libgit2/include/git2/message.h +9 -14
  77. data/vendor/libgit2/include/git2/net.h +5 -0
  78. data/vendor/libgit2/include/git2/notes.h +6 -6
  79. data/vendor/libgit2/include/git2/object.h +34 -2
  80. data/vendor/libgit2/include/git2/odb.h +77 -14
  81. data/vendor/libgit2/include/git2/odb_backend.h +50 -6
  82. data/vendor/libgit2/include/git2/oid.h +4 -8
  83. data/vendor/libgit2/include/git2/pack.h +58 -4
  84. data/vendor/libgit2/include/git2/patch.h +277 -0
  85. data/vendor/libgit2/include/git2/pathspec.h +263 -0
  86. data/vendor/libgit2/include/git2/push.h +55 -5
  87. data/vendor/libgit2/include/git2/reflog.h +11 -8
  88. data/vendor/libgit2/include/git2/refs.h +219 -33
  89. data/vendor/libgit2/include/git2/refspec.h +3 -4
  90. data/vendor/libgit2/include/git2/remote.h +216 -76
  91. data/vendor/libgit2/include/git2/repository.h +85 -40
  92. data/vendor/libgit2/include/git2/reset.h +15 -4
  93. data/vendor/libgit2/include/git2/revert.h +86 -0
  94. data/vendor/libgit2/include/git2/revparse.h +27 -16
  95. data/vendor/libgit2/include/git2/revwalk.h +44 -6
  96. data/vendor/libgit2/include/git2/signature.h +17 -3
  97. data/vendor/libgit2/include/git2/stash.h +8 -12
  98. data/vendor/libgit2/include/git2/status.h +67 -18
  99. data/vendor/libgit2/include/git2/submodule.h +100 -85
  100. data/vendor/libgit2/include/git2/sys/commit.h +38 -4
  101. data/vendor/libgit2/include/git2/sys/config.h +44 -3
  102. data/vendor/libgit2/include/git2/sys/diff.h +91 -0
  103. data/vendor/libgit2/include/git2/sys/filter.h +301 -0
  104. data/vendor/libgit2/include/git2/sys/index.h +0 -2
  105. data/vendor/libgit2/include/git2/sys/mempack.h +85 -0
  106. data/vendor/libgit2/include/git2/sys/odb_backend.h +33 -11
  107. data/vendor/libgit2/include/git2/sys/refdb_backend.h +51 -5
  108. data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
  109. data/vendor/libgit2/include/git2/sys/refs.h +2 -2
  110. data/vendor/libgit2/include/git2/sys/repository.h +19 -1
  111. data/vendor/libgit2/include/git2/transport.h +216 -75
  112. data/vendor/libgit2/include/git2/tree.h +32 -11
  113. data/vendor/libgit2/include/git2/types.h +124 -10
  114. data/vendor/libgit2/include/git2/version.h +4 -2
  115. data/vendor/libgit2/include/git2.h +41 -40
  116. data/vendor/libgit2/libgit2.pc.in +10 -0
  117. data/vendor/libgit2/src/array.h +16 -8
  118. data/vendor/libgit2/src/attr.c +140 -402
  119. data/vendor/libgit2/src/attr.h +1 -33
  120. data/vendor/libgit2/src/attr_file.c +298 -135
  121. data/vendor/libgit2/src/attr_file.h +61 -22
  122. data/vendor/libgit2/src/attrcache.c +449 -0
  123. data/vendor/libgit2/src/attrcache.h +38 -6
  124. data/vendor/libgit2/src/bitvec.h +75 -0
  125. data/vendor/libgit2/src/blame.c +488 -0
  126. data/vendor/libgit2/src/blame.h +93 -0
  127. data/vendor/libgit2/src/blame_git.c +624 -0
  128. data/vendor/libgit2/src/blame_git.h +20 -0
  129. data/vendor/libgit2/src/blob.c +137 -92
  130. data/vendor/libgit2/src/blob.h +9 -0
  131. data/vendor/libgit2/src/branch.c +175 -156
  132. data/vendor/libgit2/src/buf_text.c +29 -14
  133. data/vendor/libgit2/src/buf_text.h +5 -4
  134. data/vendor/libgit2/src/buffer.c +158 -15
  135. data/vendor/libgit2/src/buffer.h +33 -20
  136. data/vendor/libgit2/src/cc-compat.h +8 -2
  137. data/vendor/libgit2/src/checkout.c +1081 -287
  138. data/vendor/libgit2/src/checkout.h +1 -1
  139. data/vendor/libgit2/src/cherrypick.c +226 -0
  140. data/vendor/libgit2/src/clone.c +297 -245
  141. data/vendor/libgit2/src/{compress.h → clone.h} +4 -8
  142. data/vendor/libgit2/src/commit.c +313 -101
  143. data/vendor/libgit2/src/commit.h +6 -3
  144. data/vendor/libgit2/src/commit_list.c +3 -3
  145. data/vendor/libgit2/src/commit_list.h +1 -1
  146. data/vendor/libgit2/src/common.h +74 -1
  147. data/vendor/libgit2/src/config.c +570 -145
  148. data/vendor/libgit2/src/config.h +39 -6
  149. data/vendor/libgit2/src/config_cache.c +32 -18
  150. data/vendor/libgit2/src/config_file.c +711 -424
  151. data/vendor/libgit2/src/config_file.h +4 -3
  152. data/vendor/libgit2/src/crlf.c +149 -109
  153. data/vendor/libgit2/src/date.c +35 -7
  154. data/vendor/libgit2/src/delta.c +1 -1
  155. data/vendor/libgit2/src/diff.c +719 -414
  156. data/vendor/libgit2/src/diff.h +52 -7
  157. data/vendor/libgit2/src/diff_driver.c +183 -85
  158. data/vendor/libgit2/src/diff_driver.h +1 -1
  159. data/vendor/libgit2/src/diff_file.c +65 -84
  160. data/vendor/libgit2/src/diff_file.h +12 -10
  161. data/vendor/libgit2/src/diff_patch.c +274 -333
  162. data/vendor/libgit2/src/diff_patch.h +10 -9
  163. data/vendor/libgit2/src/diff_print.c +381 -179
  164. data/vendor/libgit2/src/diff_stats.c +336 -0
  165. data/vendor/libgit2/src/diff_tform.c +393 -215
  166. data/vendor/libgit2/src/diff_xdiff.c +117 -42
  167. data/vendor/libgit2/src/errors.c +59 -4
  168. data/vendor/libgit2/src/fetch.c +40 -34
  169. data/vendor/libgit2/src/fetch.h +2 -5
  170. data/vendor/libgit2/src/fetchhead.c +14 -7
  171. data/vendor/libgit2/src/filebuf.c +13 -24
  172. data/vendor/libgit2/src/filebuf.h +3 -3
  173. data/vendor/libgit2/src/fileops.c +104 -296
  174. data/vendor/libgit2/src/fileops.h +23 -94
  175. data/vendor/libgit2/src/filter.c +642 -43
  176. data/vendor/libgit2/src/filter.h +7 -66
  177. data/vendor/libgit2/src/fnmatch.c +46 -3
  178. data/vendor/libgit2/src/fnmatch.h +24 -3
  179. data/vendor/libgit2/src/global.c +158 -42
  180. data/vendor/libgit2/src/global.h +9 -0
  181. data/vendor/libgit2/src/graph.c +34 -20
  182. data/vendor/libgit2/src/hash/hash_generic.h +0 -1
  183. data/vendor/libgit2/src/hash/hash_openssl.h +0 -1
  184. data/vendor/libgit2/src/hash/hash_win32.c +14 -29
  185. data/vendor/libgit2/src/hash.h +0 -2
  186. data/vendor/libgit2/src/hashsig.c +97 -117
  187. data/vendor/libgit2/src/ident.c +125 -0
  188. data/vendor/libgit2/src/ignore.c +159 -110
  189. data/vendor/libgit2/src/ignore.h +13 -3
  190. data/vendor/libgit2/src/index.c +803 -445
  191. data/vendor/libgit2/src/index.h +43 -6
  192. data/vendor/libgit2/src/indexer.c +475 -157
  193. data/vendor/libgit2/src/iterator.c +198 -55
  194. data/vendor/libgit2/src/iterator.h +28 -4
  195. data/vendor/libgit2/src/map.h +1 -0
  196. data/vendor/libgit2/src/merge.c +849 -142
  197. data/vendor/libgit2/src/merge.h +11 -4
  198. data/vendor/libgit2/src/merge_file.c +183 -78
  199. data/vendor/libgit2/src/merge_file.h +0 -57
  200. data/vendor/libgit2/src/message.c +4 -28
  201. data/vendor/libgit2/src/mwindow.c +117 -8
  202. data/vendor/libgit2/src/mwindow.h +9 -1
  203. data/vendor/libgit2/src/netops.c +164 -59
  204. data/vendor/libgit2/src/netops.h +37 -1
  205. data/vendor/libgit2/src/notes.c +9 -18
  206. data/vendor/libgit2/src/notes.h +1 -1
  207. data/vendor/libgit2/src/object.c +78 -2
  208. data/vendor/libgit2/src/odb.c +191 -59
  209. data/vendor/libgit2/src/odb.h +2 -1
  210. data/vendor/libgit2/src/odb_loose.c +66 -51
  211. data/vendor/libgit2/src/odb_mempack.c +182 -0
  212. data/vendor/libgit2/src/odb_pack.c +151 -61
  213. data/vendor/libgit2/src/oid.c +30 -19
  214. data/vendor/libgit2/src/oid.h +13 -10
  215. data/vendor/libgit2/src/pack-objects.c +198 -147
  216. data/vendor/libgit2/src/pack-objects.h +7 -0
  217. data/vendor/libgit2/src/pack.c +272 -101
  218. data/vendor/libgit2/src/pack.h +15 -1
  219. data/vendor/libgit2/src/path.c +359 -117
  220. data/vendor/libgit2/src/path.h +110 -20
  221. data/vendor/libgit2/src/pathspec.c +583 -57
  222. data/vendor/libgit2/src/pathspec.h +36 -15
  223. data/vendor/libgit2/src/pool.c +4 -5
  224. data/vendor/libgit2/src/posix.c +45 -2
  225. data/vendor/libgit2/src/posix.h +13 -5
  226. data/vendor/libgit2/src/pqueue.c +73 -119
  227. data/vendor/libgit2/src/pqueue.h +35 -82
  228. data/vendor/libgit2/src/push.c +116 -48
  229. data/vendor/libgit2/src/push.h +5 -0
  230. data/vendor/libgit2/src/refdb.c +45 -6
  231. data/vendor/libgit2/src/refdb.h +13 -3
  232. data/vendor/libgit2/src/refdb_fs.c +1130 -551
  233. data/vendor/libgit2/src/reflog.c +36 -327
  234. data/vendor/libgit2/src/reflog.h +6 -1
  235. data/vendor/libgit2/src/refs.c +345 -142
  236. data/vendor/libgit2/src/refs.h +9 -2
  237. data/vendor/libgit2/src/refspec.c +90 -62
  238. data/vendor/libgit2/src/refspec.h +7 -24
  239. data/vendor/libgit2/src/remote.c +815 -415
  240. data/vendor/libgit2/src/remote.h +3 -4
  241. data/vendor/libgit2/src/repository.c +360 -207
  242. data/vendor/libgit2/src/repository.h +16 -10
  243. data/vendor/libgit2/src/reset.c +28 -13
  244. data/vendor/libgit2/src/revert.c +228 -0
  245. data/vendor/libgit2/src/revparse.c +29 -30
  246. data/vendor/libgit2/src/revwalk.c +141 -96
  247. data/vendor/libgit2/src/revwalk.h +6 -1
  248. data/vendor/libgit2/src/settings.c +140 -0
  249. data/vendor/libgit2/src/sha1_lookup.c +71 -0
  250. data/vendor/libgit2/src/sha1_lookup.h +5 -0
  251. data/vendor/libgit2/src/signature.c +38 -10
  252. data/vendor/libgit2/src/sortedcache.c +378 -0
  253. data/vendor/libgit2/src/sortedcache.h +178 -0
  254. data/vendor/libgit2/src/stash.c +98 -116
  255. data/vendor/libgit2/src/status.c +88 -60
  256. data/vendor/libgit2/src/status.h +2 -2
  257. data/vendor/libgit2/src/strmap.c +32 -0
  258. data/vendor/libgit2/src/strmap.h +14 -1
  259. data/vendor/libgit2/src/strnlen.h +23 -0
  260. data/vendor/libgit2/src/submodule.c +1073 -615
  261. data/vendor/libgit2/src/submodule.h +89 -21
  262. data/vendor/libgit2/src/sysdir.c +252 -0
  263. data/vendor/libgit2/src/sysdir.h +101 -0
  264. data/vendor/libgit2/src/tag.c +31 -20
  265. data/vendor/libgit2/src/thread-utils.h +98 -17
  266. data/vendor/libgit2/src/trace.h +0 -2
  267. data/vendor/libgit2/src/transport.c +76 -6
  268. data/vendor/libgit2/src/transports/cred.c +164 -61
  269. data/vendor/libgit2/src/transports/git.c +41 -48
  270. data/vendor/libgit2/src/transports/http.c +65 -109
  271. data/vendor/libgit2/src/transports/local.c +88 -65
  272. data/vendor/libgit2/src/transports/smart.c +91 -19
  273. data/vendor/libgit2/src/transports/smart.h +13 -5
  274. data/vendor/libgit2/src/transports/smart_pkt.c +24 -14
  275. data/vendor/libgit2/src/transports/smart_protocol.c +268 -113
  276. data/vendor/libgit2/src/transports/ssh.c +284 -186
  277. data/vendor/libgit2/src/transports/winhttp.c +279 -198
  278. data/vendor/libgit2/src/tree-cache.c +21 -23
  279. data/vendor/libgit2/src/tree-cache.h +1 -0
  280. data/vendor/libgit2/src/tree.c +109 -92
  281. data/vendor/libgit2/src/tree.h +2 -3
  282. data/vendor/libgit2/src/unix/map.c +7 -1
  283. data/vendor/libgit2/src/unix/posix.h +0 -1
  284. data/vendor/libgit2/src/userdiff.h +208 -0
  285. data/vendor/libgit2/src/util.c +16 -112
  286. data/vendor/libgit2/src/util.h +107 -3
  287. data/vendor/libgit2/src/vector.c +72 -17
  288. data/vendor/libgit2/src/vector.h +32 -5
  289. data/vendor/libgit2/src/win32/dir.c +15 -40
  290. data/vendor/libgit2/src/win32/dir.h +3 -2
  291. data/vendor/libgit2/src/win32/error.c +5 -31
  292. data/vendor/libgit2/src/win32/findfile.c +47 -66
  293. data/vendor/libgit2/src/win32/findfile.h +1 -12
  294. data/vendor/libgit2/src/win32/git2.rc +40 -0
  295. data/vendor/libgit2/src/win32/map.c +7 -1
  296. data/vendor/libgit2/src/win32/mingw-compat.h +3 -0
  297. data/vendor/libgit2/src/win32/posix.h +17 -11
  298. data/vendor/libgit2/src/win32/posix_w32.c +424 -292
  299. data/vendor/libgit2/src/win32/precompiled.h +6 -2
  300. data/vendor/libgit2/src/win32/pthread.c +141 -18
  301. data/vendor/libgit2/src/win32/pthread.h +50 -8
  302. data/vendor/libgit2/src/win32/reparse.h +57 -0
  303. data/vendor/libgit2/src/win32/utf-conv.c +117 -60
  304. data/vendor/libgit2/src/win32/utf-conv.h +81 -6
  305. data/vendor/libgit2/src/win32/version.h +21 -4
  306. data/vendor/libgit2/src/win32/w32_util.c +139 -0
  307. data/vendor/libgit2/src/win32/w32_util.h +54 -0
  308. data/vendor/libgit2/src/zstream.c +156 -0
  309. data/vendor/libgit2/src/zstream.h +39 -0
  310. metadata +84 -167
  311. data/Rakefile +0 -61
  312. data/ext/rugged/rugged_diff_patch.c +0 -169
  313. data/lib/rugged/diff/patch.rb +0 -28
  314. data/test/blob_test.rb +0 -341
  315. data/test/branch_test.rb +0 -199
  316. data/test/commit_test.rb +0 -104
  317. data/test/config_test.rb +0 -45
  318. data/test/coverage/cover.rb +0 -133
  319. data/test/diff_test.rb +0 -777
  320. data/test/errors_test.rb +0 -34
  321. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  322. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  323. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  324. data/test/fixtures/archive.tar.gz +0 -0
  325. data/test/fixtures/attr/attr0 +0 -1
  326. data/test/fixtures/attr/attr1 +0 -29
  327. data/test/fixtures/attr/attr2 +0 -21
  328. data/test/fixtures/attr/attr3 +0 -4
  329. data/test/fixtures/attr/binfile +0 -1
  330. data/test/fixtures/attr/dir/file +0 -0
  331. data/test/fixtures/attr/file +0 -1
  332. data/test/fixtures/attr/gitattributes +0 -29
  333. data/test/fixtures/attr/gitignore +0 -2
  334. data/test/fixtures/attr/ign +0 -1
  335. data/test/fixtures/attr/macro_bad +0 -1
  336. data/test/fixtures/attr/macro_test +0 -1
  337. data/test/fixtures/attr/root_test1 +0 -1
  338. data/test/fixtures/attr/root_test2 +0 -6
  339. data/test/fixtures/attr/root_test3 +0 -19
  340. data/test/fixtures/attr/root_test4.txt +0 -14
  341. data/test/fixtures/attr/sub/abc +0 -37
  342. data/test/fixtures/attr/sub/dir/file +0 -0
  343. data/test/fixtures/attr/sub/file +0 -1
  344. data/test/fixtures/attr/sub/ign/file +0 -1
  345. data/test/fixtures/attr/sub/ign/sub/file +0 -1
  346. data/test/fixtures/attr/sub/sub/dir +0 -0
  347. data/test/fixtures/attr/sub/sub/file +0 -1
  348. data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
  349. data/test/fixtures/attr/sub/subdir_test1 +0 -2
  350. data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
  351. data/test/fixtures/diff/another.txt +0 -38
  352. data/test/fixtures/diff/readme.txt +0 -36
  353. data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
  354. data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
  355. data/test/fixtures/mergedrepo/one.txt +0 -10
  356. data/test/fixtures/mergedrepo/two.txt +0 -12
  357. data/test/fixtures/status/current_file +0 -1
  358. data/test/fixtures/status/ignored_file +0 -1
  359. data/test/fixtures/status/modified_file +0 -2
  360. data/test/fixtures/status/new_file +0 -1
  361. data/test/fixtures/status/staged_changes +0 -2
  362. data/test/fixtures/status/staged_changes_modified_file +0 -3
  363. data/test/fixtures/status/staged_delete_modified_file +0 -1
  364. data/test/fixtures/status/staged_new_file +0 -1
  365. data/test/fixtures/status/staged_new_file_modified_file +0 -2
  366. data/test/fixtures/status/subdir/current_file +0 -1
  367. data/test/fixtures/status/subdir/modified_file +0 -2
  368. data/test/fixtures/status/subdir/new_file +0 -1
  369. data/test/fixtures/status/subdir.txt +0 -2
  370. data/test/fixtures/status//350/277/231 +0 -1
  371. data/test/fixtures/testrepo.git/HEAD +0 -1
  372. data/test/fixtures/testrepo.git/config +0 -13
  373. data/test/fixtures/testrepo.git/description +0 -1
  374. data/test/fixtures/testrepo.git/index +0 -0
  375. data/test/fixtures/testrepo.git/info/exclude +0 -6
  376. data/test/fixtures/testrepo.git/logs/HEAD +0 -3
  377. data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
  378. data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
  379. data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
  380. data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
  381. data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
  382. data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
  383. data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
  384. data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
  385. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
  386. data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
  387. data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
  388. data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
  389. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  390. data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
  391. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
  392. data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
  393. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  394. data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
  395. data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -0
  396. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  397. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  398. data/test/fixtures/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
  399. data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
  400. data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
  401. data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
  402. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
  403. data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
  404. data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
  405. data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
  406. data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  407. data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
  408. data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
  409. data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
  410. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
  411. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
  412. data/test/fixtures/testrepo.git/packed-refs +0 -2
  413. data/test/fixtures/testrepo.git/refs/heads/master +0 -1
  414. data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
  415. data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
  416. data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
  417. data/test/fixtures/text_file.md +0 -464
  418. data/test/fixtures/unsymlinked.git/HEAD +0 -1
  419. data/test/fixtures/unsymlinked.git/config +0 -6
  420. data/test/fixtures/unsymlinked.git/description +0 -1
  421. data/test/fixtures/unsymlinked.git/info/exclude +0 -2
  422. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  423. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  424. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  425. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  426. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  427. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  428. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  429. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  430. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  431. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
  432. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  433. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  434. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  435. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  436. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
  437. data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
  438. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
  439. data/test/index_test.rb +0 -333
  440. data/test/lib_test.rb +0 -127
  441. data/test/note_test.rb +0 -158
  442. data/test/object_test.rb +0 -43
  443. data/test/reference_test.rb +0 -207
  444. data/test/remote_test.rb +0 -324
  445. data/test/repo_pack_test.rb +0 -24
  446. data/test/repo_reset_test.rb +0 -82
  447. data/test/repo_test.rb +0 -402
  448. data/test/tag_test.rb +0 -68
  449. data/test/test_helper.rb +0 -92
  450. data/test/tree_test.rb +0 -91
  451. data/test/walker_test.rb +0 -88
  452. data/vendor/libgit2/src/amiga/map.c +0 -48
  453. data/vendor/libgit2/src/compress.c +0 -53
@@ -10,6 +10,7 @@
10
10
  #include "git2/oid.h"
11
11
  #include "git2/net.h"
12
12
 
13
+ #include "common.h"
13
14
  #include "config.h"
14
15
  #include "repository.h"
15
16
  #include "remote.h"
@@ -18,7 +19,7 @@
18
19
  #include "refspec.h"
19
20
  #include "fetchhead.h"
20
21
 
21
- #include <regex.h>
22
+ static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
22
23
 
23
24
  static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
24
25
  {
@@ -44,7 +45,7 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
44
45
 
45
46
  static int download_tags_value(git_remote *remote, git_config *cfg)
46
47
  {
47
- const char *val;
48
+ const git_config_entry *ce;
48
49
  git_buf buf = GIT_BUF_INIT;
49
50
  int error;
50
51
 
@@ -52,16 +53,14 @@ static int download_tags_value(git_remote *remote, git_config *cfg)
52
53
  if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
53
54
  return -1;
54
55
 
55
- error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
56
+ error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
56
57
  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;
61
58
 
62
- if (error == GIT_ENOTFOUND) {
63
- giterr_clear();
64
- error = 0;
59
+ if (!error && ce && ce->value) {
60
+ if (!strcmp(ce->value, "--no-tags"))
61
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
62
+ else if (!strcmp(ce->value, "--tags"))
63
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
65
64
  }
66
65
 
67
66
  return error;
@@ -74,13 +73,39 @@ static int ensure_remote_name_is_valid(const char *name)
74
73
  if (!git_remote_is_valid_name(name)) {
75
74
  giterr_set(
76
75
  GITERR_CONFIG,
77
- "'%s' is not a valid remote name.", name);
76
+ "'%s' is not a valid remote name.", name ? name : "(null)");
78
77
  error = GIT_EINVALIDSPEC;
79
78
  }
80
79
 
81
80
  return error;
82
81
  }
83
82
 
83
+ static int get_check_cert(int *out, git_repository *repo)
84
+ {
85
+ git_config *cfg;
86
+ const char *val;
87
+ int error = 0;
88
+
89
+ assert(out && repo);
90
+
91
+ /* By default, we *DO* want to verify the certificate. */
92
+ *out = 1;
93
+
94
+ /* Go through the possible sources for SSL verification settings, from
95
+ * most specific to least specific. */
96
+
97
+ /* GIT_SSL_NO_VERIFY environment variable */
98
+ if ((val = getenv("GIT_SSL_NO_VERIFY")) != NULL)
99
+ return git_config_parse_bool(out, val);
100
+
101
+ /* http.sslVerify config setting */
102
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
103
+ return error;
104
+
105
+ *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
106
+ return 0;
107
+ }
108
+
84
109
  static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
85
110
  {
86
111
  git_remote *remote;
@@ -94,9 +119,11 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
94
119
  GITERR_CHECK_ALLOC(remote);
95
120
 
96
121
  remote->repo = repo;
97
- remote->check_cert = 1;
98
122
  remote->update_fetchhead = 1;
99
123
 
124
+ if (get_check_cert(&remote->check_cert, repo) < 0)
125
+ goto on_error;
126
+
100
127
  if (git_vector_init(&remote->refs, 32, NULL) < 0)
101
128
  goto on_error;
102
129
 
@@ -183,7 +210,33 @@ on_error:
183
210
  return -1;
184
211
  }
185
212
 
186
- int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url)
213
+ int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
214
+ {
215
+ git_remote *remote = NULL;
216
+ int error;
217
+
218
+ if ((error = ensure_remote_name_is_valid(name)) < 0)
219
+ return error;
220
+
221
+ if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
222
+ return error;
223
+
224
+ if (create_internal(&remote, repo, name, url, fetch) < 0)
225
+ goto on_error;
226
+
227
+ if (git_remote_save(remote) < 0)
228
+ goto on_error;
229
+
230
+ *out = remote;
231
+
232
+ return 0;
233
+
234
+ on_error:
235
+ git_remote_free(remote);
236
+ return -1;
237
+ }
238
+
239
+ int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url, const char *fetch)
187
240
  {
188
241
  int error;
189
242
  git_remote *remote;
@@ -195,6 +248,62 @@ int git_remote_create_inmemory(git_remote **out, git_repository *repo, const cha
195
248
  return 0;
196
249
  }
197
250
 
251
+ int git_remote_dup(git_remote **dest, git_remote *source)
252
+ {
253
+ int error = 0;
254
+ git_strarray refspecs = { 0 };
255
+ git_remote *remote = git__calloc(1, sizeof(git_remote));
256
+ GITERR_CHECK_ALLOC(remote);
257
+
258
+ if (source->name != NULL) {
259
+ remote->name = git__strdup(source->name);
260
+ GITERR_CHECK_ALLOC(remote->name);
261
+ }
262
+
263
+ if (source->url != NULL) {
264
+ remote->url = git__strdup(source->url);
265
+ GITERR_CHECK_ALLOC(remote->url);
266
+ }
267
+
268
+ if (source->pushurl != NULL) {
269
+ remote->pushurl = git__strdup(source->pushurl);
270
+ GITERR_CHECK_ALLOC(remote->pushurl);
271
+ }
272
+
273
+ remote->repo = source->repo;
274
+ remote->download_tags = source->download_tags;
275
+ remote->check_cert = source->check_cert;
276
+ remote->update_fetchhead = source->update_fetchhead;
277
+
278
+ if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
279
+ git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
280
+ git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
281
+ error = -1;
282
+ goto cleanup;
283
+ }
284
+
285
+ if ((error = git_remote_get_fetch_refspecs(&refspecs, source)) < 0 ||
286
+ (error = git_remote_set_fetch_refspecs(remote, &refspecs)) < 0)
287
+ goto cleanup;
288
+
289
+ git_strarray_free(&refspecs);
290
+
291
+ if ((error = git_remote_get_push_refspecs(&refspecs, source)) < 0 ||
292
+ (error = git_remote_set_push_refspecs(remote, &refspecs)) < 0)
293
+ goto cleanup;
294
+
295
+ *dest = remote;
296
+
297
+ cleanup:
298
+
299
+ git_strarray_free(&refspecs);
300
+
301
+ if (error < 0)
302
+ git__free(remote);
303
+
304
+ return error;
305
+ }
306
+
198
307
  struct refspec_cb_data {
199
308
  git_remote *remote;
200
309
  int fetch;
@@ -202,13 +311,13 @@ struct refspec_cb_data {
202
311
 
203
312
  static int refspec_cb(const git_config_entry *entry, void *payload)
204
313
  {
205
- const struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
206
-
314
+ struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
207
315
  return add_refspec(data->remote, entry->value, data->fetch);
208
316
  }
209
317
 
210
318
  static int get_optional_config(
211
- git_config *config, git_buf *buf, git_config_foreach_cb cb, void *payload)
319
+ bool *found, git_config *config, git_buf *buf,
320
+ git_config_foreach_cb cb, void *payload)
212
321
  {
213
322
  int error = 0;
214
323
  const char *key = git_buf_cstr(buf);
@@ -217,18 +326,18 @@ static int get_optional_config(
217
326
  return -1;
218
327
 
219
328
  if (cb != NULL)
220
- error = git_config_get_multivar(config, key, NULL, cb, payload);
329
+ error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
221
330
  else
222
331
  error = git_config_get_string(payload, config, key);
223
332
 
333
+ if (found)
334
+ *found = !error;
335
+
224
336
  if (error == GIT_ENOTFOUND) {
225
337
  giterr_clear();
226
338
  error = 0;
227
339
  }
228
340
 
229
- if (error < 0)
230
- error = -1;
231
-
232
341
  return error;
233
342
  }
234
343
 
@@ -239,82 +348,97 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
239
348
  const char *val;
240
349
  int error = 0;
241
350
  git_config *config;
242
- struct refspec_cb_data data;
351
+ struct refspec_cb_data data = { NULL };
352
+ bool optional_setting_found = false, found;
243
353
 
244
354
  assert(out && repo && name);
245
355
 
246
356
  if ((error = ensure_remote_name_is_valid(name)) < 0)
247
357
  return error;
248
358
 
249
- if (git_repository_config__weakptr(&config, repo) < 0)
250
- return -1;
359
+ if ((error = git_repository_config_snapshot(&config, repo)) < 0)
360
+ return error;
251
361
 
252
362
  remote = git__malloc(sizeof(git_remote));
253
363
  GITERR_CHECK_ALLOC(remote);
254
364
 
255
365
  memset(remote, 0x0, sizeof(git_remote));
256
- remote->check_cert = 1;
257
366
  remote->update_fetchhead = 1;
258
367
  remote->name = git__strdup(name);
259
368
  GITERR_CHECK_ALLOC(remote->name);
260
369
 
261
- if ((git_vector_init(&remote->refs, 32, NULL) < 0) ||
262
- (git_vector_init(&remote->refspecs, 2, NULL))) {
263
- error = -1;
370
+ if ((error = get_check_cert(&remote->check_cert, repo)) < 0)
264
371
  goto cleanup;
265
- }
266
372
 
267
- if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
373
+ if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
374
+ git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
375
+ git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
268
376
  error = -1;
269
377
  goto cleanup;
270
378
  }
271
379
 
272
- if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
380
+ if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
273
381
  goto cleanup;
274
382
 
275
- if (strlen(val) == 0) {
276
- giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name);
277
- error = -1;
383
+ if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
278
384
  goto cleanup;
279
- }
385
+
386
+ optional_setting_found |= found;
280
387
 
281
388
  remote->repo = repo;
282
- remote->url = git__strdup(val);
283
- GITERR_CHECK_ALLOC(remote->url);
389
+
390
+ if (found && strlen(val) > 0) {
391
+ remote->url = git__strdup(val);
392
+ GITERR_CHECK_ALLOC(remote->url);
393
+ }
284
394
 
285
395
  val = NULL;
286
396
  git_buf_clear(&buf);
287
397
  git_buf_printf(&buf, "remote.%s.pushurl", name);
288
398
 
289
- if ((error = get_optional_config(config, &buf, NULL, (void *)&val)) < 0)
399
+ if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
400
+ goto cleanup;
401
+
402
+ optional_setting_found |= found;
403
+
404
+ if (!optional_setting_found) {
405
+ error = GIT_ENOTFOUND;
406
+ giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name);
290
407
  goto cleanup;
408
+ }
291
409
 
292
- if (val) {
410
+ if (found && strlen(val) > 0) {
293
411
  remote->pushurl = git__strdup(val);
294
412
  GITERR_CHECK_ALLOC(remote->pushurl);
295
413
  }
296
414
 
297
415
  data.remote = remote;
298
416
  data.fetch = true;
417
+
299
418
  git_buf_clear(&buf);
300
419
  git_buf_printf(&buf, "remote.%s.fetch", name);
301
420
 
302
- if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0)
421
+ if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
303
422
  goto cleanup;
304
423
 
305
424
  data.fetch = false;
306
425
  git_buf_clear(&buf);
307
426
  git_buf_printf(&buf, "remote.%s.push", name);
308
427
 
309
- if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0)
428
+ if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
310
429
  goto cleanup;
311
430
 
312
431
  if (download_tags_value(remote, config) < 0)
313
432
  goto cleanup;
314
433
 
434
+ /* Move the data over to where the matching functions can find them */
435
+ if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
436
+ goto cleanup;
437
+
315
438
  *out = remote;
316
439
 
317
440
  cleanup:
441
+ git_config_free(config);
318
442
  git_buf_free(&buf);
319
443
 
320
444
  if (error < 0)
@@ -326,20 +450,22 @@ cleanup:
326
450
  static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
327
451
  {
328
452
  git_buf name = GIT_BUF_INIT;
329
- int push;
453
+ unsigned int push;
330
454
  const char *dir;
331
455
  size_t i;
332
456
  int error = 0;
457
+ const char *cname;
333
458
 
334
459
  push = direction == GIT_DIRECTION_PUSH;
335
460
  dir = push ? "push" : "fetch";
336
461
 
337
462
  if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
338
463
  return -1;
464
+ cname = git_buf_cstr(&name);
339
465
 
340
466
  /* Clear out the existing config */
341
467
  while (!error)
342
- error = git_config_delete_entry(config, git_buf_cstr(&name));
468
+ error = git_config_delete_multivar(config, cname, ".*");
343
469
 
344
470
  if (error != GIT_ENOTFOUND)
345
471
  return error;
@@ -350,8 +476,11 @@ static int update_config_refspec(const git_remote *remote, git_config *config, i
350
476
  if (spec->push != push)
351
477
  continue;
352
478
 
479
+ // "$^" is a unmatcheable regexp: it will not match anything at all, so
480
+ // all values will be considered new and we will not replace any
481
+ // present value.
353
482
  if ((error = git_config_set_multivar(
354
- config, git_buf_cstr(&name), "", spec->string)) < 0) {
483
+ config, cname, "$^", spec->string)) < 0) {
355
484
  goto cleanup;
356
485
  }
357
486
  }
@@ -368,57 +497,46 @@ cleanup:
368
497
  int git_remote_save(const git_remote *remote)
369
498
  {
370
499
  int error;
371
- git_config *config;
500
+ git_config *cfg;
372
501
  const char *tagopt = NULL;
373
502
  git_buf buf = GIT_BUF_INIT;
503
+ const git_config_entry *existing;
374
504
 
375
505
  assert(remote);
376
506
 
377
507
  if (!remote->name) {
378
- giterr_set(GITERR_INVALID, "Can't save an in-memory remote.");
508
+ giterr_set(GITERR_INVALID, "Can't save an anonymous remote.");
379
509
  return GIT_EINVALIDSPEC;
380
510
  }
381
511
 
382
512
  if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
383
513
  return error;
384
514
 
385
- if (git_repository_config__weakptr(&config, remote->repo) < 0)
386
- return -1;
515
+ if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
516
+ return error;
387
517
 
388
- if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
389
- return -1;
518
+ if ((error = git_buf_printf(&buf, "remote.%s.url", remote->name)) < 0)
519
+ return error;
390
520
 
391
- if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
392
- git_buf_free(&buf);
393
- return -1;
394
- }
521
+ /* after this point, buffer is allocated so end with cleanup */
522
+
523
+ if ((error = git_config_set_string(
524
+ cfg, git_buf_cstr(&buf), remote->url)) < 0)
525
+ goto cleanup;
395
526
 
396
527
  git_buf_clear(&buf);
397
- if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
398
- return -1;
528
+ if ((error = git_buf_printf(&buf, "remote.%s.pushurl", remote->name)) < 0)
529
+ goto cleanup;
399
530
 
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
- }
531
+ if ((error = git_config__update_entry(
532
+ cfg, git_buf_cstr(&buf), remote->pushurl, true, false)) < 0)
533
+ goto cleanup;
416
534
 
417
- if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
418
- goto on_error;
535
+ if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
536
+ goto cleanup;
419
537
 
420
- if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
421
- goto on_error;
538
+ if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
539
+ goto cleanup;
422
540
 
423
541
  /*
424
542
  * What action to take depends on the old and new values. This
@@ -434,31 +552,26 @@ int git_remote_save(const git_remote *remote)
434
552
  */
435
553
 
436
554
  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;
555
+ if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
556
+ goto cleanup;
443
557
 
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
- }
558
+ if ((error = git_config__lookup_entry(
559
+ &existing, cfg, git_buf_cstr(&buf), false)) < 0)
560
+ goto cleanup;
454
561
 
455
- git_buf_free(&buf);
562
+ if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL)
563
+ tagopt = "--tags";
564
+ else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE)
565
+ tagopt = "--no-tags";
566
+ else if (existing != NULL)
567
+ tagopt = NULL;
456
568
 
457
- return 0;
569
+ error = git_config__update_entry(
570
+ cfg, git_buf_cstr(&buf), tagopt, true, false);
458
571
 
459
- on_error:
572
+ cleanup:
460
573
  git_buf_free(&buf);
461
- return -1;
574
+ return error;
462
575
  }
463
576
 
464
577
  const char *git_remote_name(const git_remote *remote)
@@ -467,6 +580,12 @@ const char *git_remote_name(const git_remote *remote)
467
580
  return remote->name;
468
581
  }
469
582
 
583
+ git_repository *git_remote_owner(const git_remote *remote)
584
+ {
585
+ assert(remote);
586
+ return remote->repo;
587
+ }
588
+
470
589
  const char *git_remote_url(const git_remote *remote)
471
590
  {
472
591
  assert(remote);
@@ -509,6 +628,8 @@ const char* git_remote__urlfordirection(git_remote *remote, int direction)
509
628
  {
510
629
  assert(remote);
511
630
 
631
+ assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
632
+
512
633
  if (direction == GIT_DIRECTION_FETCH) {
513
634
  return remote->url;
514
635
  }
@@ -525,28 +646,32 @@ int git_remote_connect(git_remote *remote, git_direction direction)
525
646
  git_transport *t;
526
647
  const char *url;
527
648
  int flags = GIT_TRANSPORTFLAGS_NONE;
649
+ int error;
528
650
 
529
651
  assert(remote);
530
652
 
531
653
  t = remote->transport;
532
654
 
533
655
  url = git_remote__urlfordirection(remote, direction);
534
- if (url == NULL )
656
+ if (url == NULL) {
657
+ giterr_set(GITERR_INVALID,
658
+ "Malformed remote '%s' - missing URL", remote->name);
535
659
  return -1;
660
+ }
536
661
 
537
662
  /* A transport could have been supplied in advance with
538
663
  * git_remote_set_transport */
539
- if (!t && git_transport_new(&t, remote, url) < 0)
540
- return -1;
664
+ if (!t && (error = git_transport_new(&t, remote, url)) < 0)
665
+ return error;
541
666
 
542
667
  if (t->set_callbacks &&
543
- t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload) < 0)
668
+ (error = t->set_callbacks(t, remote->callbacks.sideband_progress, NULL, remote->callbacks.payload)) < 0)
544
669
  goto on_error;
545
670
 
546
671
  if (!remote->check_cert)
547
672
  flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT;
548
673
 
549
- if (t->connect(t, url, remote->cred_acquire_cb, remote->cred_acquire_payload, direction, flags) < 0)
674
+ if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) != 0)
550
675
  goto on_error;
551
676
 
552
677
  remote->transport = t;
@@ -559,20 +684,22 @@ on_error:
559
684
  if (t == remote->transport)
560
685
  remote->transport = NULL;
561
686
 
562
- return -1;
687
+ return error;
563
688
  }
564
689
 
565
- int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
690
+ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
566
691
  {
567
692
  assert(remote);
568
693
 
569
- return remote->transport->ls(remote->transport, list_cb, payload);
694
+ return remote->transport->ls(out, size, remote->transport);
570
695
  }
571
696
 
572
697
  int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
573
698
  {
574
699
  git_config *cfg;
575
- const char *val;
700
+ const git_config_entry *ce;
701
+ const char *val = NULL;
702
+ int error;
576
703
 
577
704
  assert(remote);
578
705
 
@@ -581,112 +708,76 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur
581
708
 
582
709
  *proxy_url = NULL;
583
710
 
584
- if (git_repository_config__weakptr(&cfg, remote->repo) < 0)
585
- return -1;
711
+ if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
712
+ return error;
586
713
 
587
714
  /* Go through the possible sources for proxy configuration, from most specific
588
715
  * to least specific. */
589
716
 
590
717
  /* remote.<name>.proxy config setting */
591
- if (remote->name && 0 != *(remote->name)) {
718
+ if (remote->name && remote->name[0]) {
592
719
  git_buf buf = GIT_BUF_INIT;
593
720
 
594
- if (git_buf_printf(&buf, "remote.%s.proxy", remote->name) < 0)
595
- return -1;
721
+ if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
722
+ return error;
596
723
 
597
- if (!git_config_get_string(&val, cfg, git_buf_cstr(&buf)) &&
598
- val && ('\0' != *val)) {
599
- git_buf_free(&buf);
724
+ error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
725
+ git_buf_free(&buf);
600
726
 
601
- *proxy_url = git__strdup(val);
602
- GITERR_CHECK_ALLOC(*proxy_url);
603
- return 0;
604
- }
727
+ if (error < 0)
728
+ return error;
605
729
 
606
- git_buf_free(&buf);
730
+ if (ce && ce->value) {
731
+ val = ce->value;
732
+ goto found;
733
+ }
607
734
  }
608
735
 
609
736
  /* 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;
737
+ if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
738
+ return error;
739
+ if (ce && ce->value) {
740
+ val = ce->value;
741
+ goto found;
615
742
  }
616
743
 
617
744
  /* HTTP_PROXY / HTTPS_PROXY environment variables */
618
745
  val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
619
746
 
620
- if (val && ('\0' != *val)) {
747
+ found:
748
+ if (val && val[0]) {
621
749
  *proxy_url = git__strdup(val);
622
750
  GITERR_CHECK_ALLOC(*proxy_url);
623
- return 0;
624
751
  }
625
752
 
626
753
  return 0;
627
754
  }
628
755
 
629
- static int store_refs(git_remote_head *head, void *payload)
630
- {
631
- git_vector *refs = (git_vector *)payload;
632
-
633
- return git_vector_insert(refs, head);
634
- }
635
-
636
- static int dwim_refspecs(git_vector *refspecs, git_vector *refs)
756
+ /* DWIM `refspecs` based on `refs` and append the output to `out` */
757
+ static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
637
758
  {
638
- git_buf buf = GIT_BUF_INIT;
759
+ size_t i;
639
760
  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
761
 
650
762
  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
- }
763
+ if (git_refspec__dwim_one(out, spec, refs) < 0)
764
+ return -1;
765
+ }
677
766
 
678
- if (git_buf_puts(&buf, spec->dst) < 0)
679
- return -1;
767
+ return 0;
768
+ }
680
769
 
681
- git__free(spec->dst);
682
- spec->dst = git_buf_detach(&buf);
683
- }
770
+ static void free_refspecs(git_vector *vec)
771
+ {
772
+ size_t i;
773
+ git_refspec *spec;
684
774
 
685
- spec->dwim = 1;
775
+ git_vector_foreach(vec, i, spec) {
776
+ git_refspec__free(spec);
777
+ git__free(spec);
686
778
  }
687
779
 
688
- git_buf_free(&buf);
689
- return 0;
780
+ git_vector_clear(vec);
690
781
  }
691
782
 
692
783
  static int remote_head_cmp(const void *_a, const void *_b)
@@ -697,32 +788,82 @@ static int remote_head_cmp(const void *_a, const void *_b)
697
788
  return git__strcmp_cb(a->name, b->name);
698
789
  }
699
790
 
700
- int git_remote_download(
701
- git_remote *remote,
702
- git_transfer_progress_callback progress_cb,
703
- void *progress_payload)
791
+ static int ls_to_vector(git_vector *out, git_remote *remote)
792
+ {
793
+ git_remote_head **heads;
794
+ size_t heads_len, i;
795
+
796
+ if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
797
+ return -1;
798
+
799
+ if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
800
+ return -1;
801
+
802
+ for (i = 0; i < heads_len; i++) {
803
+ if (git_vector_insert(out, heads[i]) < 0)
804
+ return -1;
805
+ }
806
+
807
+ return 0;
808
+ }
809
+
810
+ int git_remote_download(git_remote *remote)
704
811
  {
705
812
  int error;
706
813
  git_vector refs;
707
814
 
708
815
  assert(remote);
709
816
 
710
- if (git_vector_init(&refs, 16, remote_head_cmp) < 0)
817
+ if (ls_to_vector(&refs, remote) < 0)
711
818
  return -1;
712
819
 
713
- if (git_remote_ls(remote, store_refs, &refs) < 0) {
714
- return -1;
715
- }
820
+ free_refspecs(&remote->active_refspecs);
716
821
 
717
- error = dwim_refspecs(&remote->refspecs, &refs);
822
+ error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &refs);
718
823
  git_vector_free(&refs);
824
+
719
825
  if (error < 0)
720
- return -1;
826
+ return error;
721
827
 
722
828
  if ((error = git_fetch_negotiate(remote)) < 0)
723
829
  return error;
724
830
 
725
- return git_fetch_download_pack(remote, progress_cb, progress_payload);
831
+ return git_fetch_download_pack(remote);
832
+ }
833
+
834
+ int git_remote_fetch(
835
+ git_remote *remote,
836
+ const git_signature *signature,
837
+ const char *reflog_message)
838
+ {
839
+ int error;
840
+ git_buf reflog_msg_buf = GIT_BUF_INIT;
841
+
842
+ /* Connect and download everything */
843
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) != 0)
844
+ return error;
845
+
846
+ error = git_remote_download(remote);
847
+
848
+ /* We don't need to be connected anymore */
849
+ git_remote_disconnect(remote);
850
+
851
+ /* If the download failed, return the error */
852
+ if (error != 0)
853
+ return error;
854
+
855
+ /* Default reflog message */
856
+ if (reflog_message)
857
+ git_buf_sets(&reflog_msg_buf, reflog_message);
858
+ else {
859
+ git_buf_printf(&reflog_msg_buf, "fetch %s",
860
+ remote->name ? remote->name : remote->url);
861
+ }
862
+
863
+ /* Create "remote/foo" branches for all remote branches */
864
+ error = git_remote_update_tips(remote, signature, git_buf_cstr(&reflog_msg_buf));
865
+ git_buf_free(&reflog_msg_buf);
866
+ return error;
726
867
  }
727
868
 
728
869
  static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
@@ -747,19 +888,32 @@ static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *upda
747
888
  static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref)
748
889
  {
749
890
  git_reference *resolved_ref = NULL;
750
- git_reference *tracking_ref = NULL;
751
891
  git_buf remote_name = GIT_BUF_INIT;
892
+ git_buf upstream_name = GIT_BUF_INIT;
893
+ git_repository *repo;
894
+ const char *ref_name;
752
895
  int error = 0;
753
896
 
754
897
  assert(out && spec && ref);
755
898
 
756
899
  *out = NULL;
757
900
 
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 */
901
+ repo = git_reference_owner(ref);
902
+
903
+ error = git_reference_resolve(&resolved_ref, ref);
904
+
905
+ /* If we're in an unborn branch, let's pretend nothing happened */
906
+ if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REF_SYMBOLIC) {
907
+ ref_name = git_reference_symbolic_target(ref);
908
+ error = 0;
909
+ } else {
910
+ ref_name = git_reference_name(resolved_ref);
911
+ }
912
+
913
+ if ((!git_reference__is_branch(ref_name)) ||
914
+ (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
915
+ (error = git_refspec_rtransform(&remote_name, spec, upstream_name.ptr)) < 0) {
916
+ /* Not an error if there is no upstream */
763
917
  if (error == GIT_ENOTFOUND)
764
918
  error = 0;
765
919
 
@@ -769,9 +923,9 @@ static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vec
769
923
  error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
770
924
 
771
925
  cleanup:
772
- git_reference_free(tracking_ref);
773
926
  git_reference_free(resolved_ref);
774
927
  git_buf_free(&remote_name);
928
+ git_buf_free(&upstream_name);
775
929
  return error;
776
930
  }
777
931
 
@@ -840,7 +994,12 @@ cleanup:
840
994
  return error;
841
995
  }
842
996
 
843
- static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs)
997
+ static int update_tips_for_spec(
998
+ git_remote *remote,
999
+ git_refspec *spec,
1000
+ git_vector *refs,
1001
+ const git_signature *signature,
1002
+ const char *log_message)
844
1003
  {
845
1004
  int error = 0, autotag;
846
1005
  unsigned int i = 0;
@@ -873,7 +1032,7 @@ static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vecto
873
1032
  continue;
874
1033
 
875
1034
  if (git_refspec_src_matches(spec, head->name) && spec->dst) {
876
- if (git_refspec_transform_r(&refname, spec, head->name) < 0)
1035
+ if (git_refspec_transform(&refname, spec, head->name) < 0)
877
1036
  goto on_error;
878
1037
  } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
879
1038
 
@@ -907,7 +1066,8 @@ static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vecto
907
1066
  continue;
908
1067
 
909
1068
  /* In autotag mode, don't overwrite any locally-existing tags */
910
- error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
1069
+ error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
1070
+ signature, log_message);
911
1071
  if (error < 0 && error != GIT_EEXISTS)
912
1072
  goto on_error;
913
1073
 
@@ -936,43 +1096,43 @@ on_error:
936
1096
 
937
1097
  }
938
1098
 
939
- int git_remote_update_tips(git_remote *remote)
1099
+ int git_remote_update_tips(
1100
+ git_remote *remote,
1101
+ const git_signature *signature,
1102
+ const char *reflog_message)
940
1103
  {
941
1104
  git_refspec *spec, tagspec;
942
1105
  git_vector refs;
943
1106
  int error;
944
1107
  size_t i;
945
1108
 
946
-
947
1109
  if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
948
1110
  return -1;
949
1111
 
950
- if (git_vector_init(&refs, 16, NULL) < 0)
951
- return -1;
952
1112
 
953
- if ((error = git_remote_ls(remote, store_refs, &refs)) < 0)
1113
+ if ((error = ls_to_vector(&refs, remote)) < 0)
954
1114
  goto out;
955
1115
 
956
1116
  if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
957
- error = update_tips_for_spec(remote, &tagspec, &refs);
1117
+ error = update_tips_for_spec(remote, &tagspec, &refs, signature, reflog_message);
958
1118
  goto out;
959
1119
  }
960
1120
 
961
- git_vector_foreach(&remote->refspecs, i, spec) {
1121
+ git_vector_foreach(&remote->active_refspecs, i, spec) {
962
1122
  if (spec->push)
963
1123
  continue;
964
1124
 
965
- if ((error = update_tips_for_spec(remote, spec, &refs)) < 0)
1125
+ if ((error = update_tips_for_spec(remote, spec, &refs, signature, reflog_message)) < 0)
966
1126
  goto out;
967
1127
  }
968
1128
 
969
1129
  out:
970
- git_refspec__free(&tagspec);
971
1130
  git_vector_free(&refs);
1131
+ git_refspec__free(&tagspec);
972
1132
  return error;
973
1133
  }
974
1134
 
975
- int git_remote_connected(git_remote *remote)
1135
+ int git_remote_connected(const git_remote *remote)
976
1136
  {
977
1137
  assert(remote);
978
1138
 
@@ -1001,9 +1161,6 @@ void git_remote_disconnect(git_remote *remote)
1001
1161
 
1002
1162
  void git_remote_free(git_remote *remote)
1003
1163
  {
1004
- git_refspec *spec;
1005
- size_t i;
1006
-
1007
1164
  if (remote == NULL)
1008
1165
  return;
1009
1166
 
@@ -1016,82 +1173,60 @@ void git_remote_free(git_remote *remote)
1016
1173
 
1017
1174
  git_vector_free(&remote->refs);
1018
1175
 
1019
- git_vector_foreach(&remote->refspecs, i, spec) {
1020
- git_refspec__free(spec);
1021
- git__free(spec);
1022
- }
1176
+ free_refspecs(&remote->refspecs);
1023
1177
  git_vector_free(&remote->refspecs);
1024
1178
 
1179
+ free_refspecs(&remote->active_refspecs);
1180
+ git_vector_free(&remote->active_refspecs);
1181
+
1025
1182
  git__free(remote->url);
1026
1183
  git__free(remote->pushurl);
1027
1184
  git__free(remote->name);
1028
1185
  git__free(remote);
1029
1186
  }
1030
1187
 
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_)
1188
+ static int remote_list_cb(const git_config_entry *entry, void *payload)
1037
1189
  {
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;
1190
+ git_vector *list = payload;
1191
+ const char *name = entry->name + strlen("remote.");
1192
+ size_t namelen = strlen(name);
1193
+ char *remote_name;
1042
1194
 
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);
1195
+ /* we know name matches "remote.<stuff>.(push)?url" */
1046
1196
 
1047
- if (git_vector_insert(data->list, remote_name) < 0)
1048
- return -1;
1049
- }
1197
+ if (!strcmp(&name[namelen - 4], ".url"))
1198
+ remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1199
+ else
1200
+ remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
1201
+ GITERR_CHECK_ALLOC(remote_name);
1050
1202
 
1051
- return 0;
1203
+ return git_vector_insert(list, remote_name);
1052
1204
  }
1053
1205
 
1054
1206
  int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1055
1207
  {
1056
- git_config *cfg;
1057
- git_vector list;
1058
- regex_t preg;
1059
- struct cb_data data;
1060
1208
  int error;
1209
+ git_config *cfg;
1210
+ git_vector list = GIT_VECTOR_INIT;
1061
1211
 
1062
- if (git_repository_config__weakptr(&cfg, repo) < 0)
1063
- return -1;
1212
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1213
+ return error;
1064
1214
 
1065
- if (git_vector_init(&list, 4, NULL) < 0)
1066
- return -1;
1215
+ if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
1216
+ return error;
1067
1217
 
1068
- if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
1069
- giterr_set(GITERR_OS, "Remote catch regex failed to compile");
1070
- return -1;
1071
- }
1218
+ error = git_config_foreach_match(
1219
+ cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
1072
1220
 
1073
- data.list = &list;
1074
- data.preg = &preg;
1075
- error = git_config_foreach(cfg, remote_list_cb, &data);
1076
- regfree(&preg);
1077
1221
  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
-
1222
+ git_vector_free_deep(&list);
1090
1223
  return error;
1091
1224
  }
1092
1225
 
1093
- remotes_list->strings = (char **)list.contents;
1094
- remotes_list->count = list.length;
1226
+ git_vector_uniq(&list, git__free);
1227
+
1228
+ remotes_list->strings =
1229
+ (char **)git_vector_detach(&remotes_list->count, NULL, &list);
1095
1230
 
1096
1231
  return 0;
1097
1232
  }
@@ -1103,7 +1238,7 @@ void git_remote_check_cert(git_remote *remote, int check)
1103
1238
  remote->check_cert = check;
1104
1239
  }
1105
1240
 
1106
- int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
1241
+ int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks)
1107
1242
  {
1108
1243
  assert(remote && callbacks);
1109
1244
 
@@ -1112,23 +1247,19 @@ int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks
1112
1247
  memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
1113
1248
 
1114
1249
  if (remote->transport && remote->transport->set_callbacks)
1115
- remote->transport->set_callbacks(remote->transport,
1116
- remote->callbacks.progress,
1250
+ return remote->transport->set_callbacks(remote->transport,
1251
+ remote->callbacks.sideband_progress,
1117
1252
  NULL,
1118
1253
  remote->callbacks.payload);
1119
1254
 
1120
1255
  return 0;
1121
1256
  }
1122
1257
 
1123
- void git_remote_set_cred_acquire_cb(
1124
- git_remote *remote,
1125
- git_cred_acquire_cb cred_acquire_cb,
1126
- void *payload)
1258
+ const git_remote_callbacks *git_remote_get_callbacks(git_remote *remote)
1127
1259
  {
1128
1260
  assert(remote);
1129
1261
 
1130
- remote->cred_acquire_cb = cred_acquire_cb;
1131
- remote->cred_acquire_payload = payload;
1262
+ return &remote->callbacks;
1132
1263
  }
1133
1264
 
1134
1265
  int git_remote_set_transport(git_remote *remote, git_transport *transport)
@@ -1152,7 +1283,7 @@ const git_transfer_progress* git_remote_stats(git_remote *remote)
1152
1283
  return &remote->stats;
1153
1284
  }
1154
1285
 
1155
- git_remote_autotag_option_t git_remote_autotag(git_remote *remote)
1286
+ git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1156
1287
  {
1157
1288
  return remote->download_tags;
1158
1289
  }
@@ -1174,13 +1305,14 @@ static int rename_remote_config_section(
1174
1305
  if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1175
1306
  goto cleanup;
1176
1307
 
1177
- if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0)
1178
- goto cleanup;
1308
+ if (new_name &&
1309
+ (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1310
+ goto cleanup;
1179
1311
 
1180
1312
  error = git_config_rename_section(
1181
1313
  repo,
1182
1314
  git_buf_cstr(&old_section_name),
1183
- git_buf_cstr(&new_section_name));
1315
+ new_name ? git_buf_cstr(&new_section_name) : NULL);
1184
1316
 
1185
1317
  cleanup:
1186
1318
  git_buf_free(&old_section_name);
@@ -1189,8 +1321,7 @@ cleanup:
1189
1321
  return error;
1190
1322
  }
1191
1323
 
1192
- struct update_data
1193
- {
1324
+ struct update_data {
1194
1325
  git_config *config;
1195
1326
  const char *old_remote_name;
1196
1327
  const char *new_remote_name;
@@ -1206,9 +1337,7 @@ static int update_config_entries_cb(
1206
1337
  return 0;
1207
1338
 
1208
1339
  return git_config_set_string(
1209
- data->config,
1210
- entry->name,
1211
- data->new_remote_name);
1340
+ data->config, entry->name, data->new_remote_name);
1212
1341
  }
1213
1342
 
1214
1343
  static int update_branch_remote_config_entry(
@@ -1216,41 +1345,77 @@ static int update_branch_remote_config_entry(
1216
1345
  const char *old_name,
1217
1346
  const char *new_name)
1218
1347
  {
1219
- git_config *config;
1220
- struct update_data data;
1348
+ int error;
1349
+ struct update_data data = { NULL };
1221
1350
 
1222
- if (git_repository_config__weakptr(&config, repo) < 0)
1223
- return -1;
1351
+ if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1352
+ return error;
1224
1353
 
1225
- data.config = config;
1226
1354
  data.old_remote_name = old_name;
1227
1355
  data.new_remote_name = new_name;
1228
1356
 
1229
1357
  return git_config_foreach_match(
1230
- config,
1231
- "branch\\..+\\.remote",
1232
- update_config_entries_cb, &data);
1358
+ data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
1233
1359
  }
1234
1360
 
1235
1361
  static int rename_one_remote_reference(
1236
- git_reference *reference,
1362
+ git_reference *reference_in,
1237
1363
  const char *old_remote_name,
1238
1364
  const char *new_remote_name)
1239
1365
  {
1240
- int error = -1;
1366
+ int error;
1367
+ git_reference *ref = NULL, *dummy = NULL;
1368
+ git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
1241
1369
  git_buf new_name = GIT_BUF_INIT;
1370
+ git_buf log_message = GIT_BUF_INIT;
1371
+ size_t pfx_len;
1372
+ const char *target;
1242
1373
 
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;
1374
+ if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1375
+ return error;
1376
+
1377
+ pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1378
+ git_buf_puts(&new_name, namespace.ptr);
1379
+ if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
1380
+ goto cleanup;
1381
+
1382
+ if ((error = git_buf_printf(&log_message,
1383
+ "renamed remote %s to %s",
1384
+ old_remote_name, new_remote_name)) < 0)
1385
+ goto cleanup;
1386
+
1387
+ if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1388
+ NULL, git_buf_cstr(&log_message))) < 0)
1389
+ goto cleanup;
1390
+
1391
+ if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1392
+ goto cleanup;
1393
+
1394
+ /* Handle refs like origin/HEAD -> origin/master */
1395
+ target = git_reference_symbolic_target(ref);
1396
+ if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1397
+ goto cleanup;
1398
+
1399
+ if (git__prefixcmp(target, old_namespace.ptr))
1400
+ goto cleanup;
1401
+
1402
+ git_buf_clear(&new_name);
1403
+ git_buf_puts(&new_name, namespace.ptr);
1404
+ if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1405
+ goto cleanup;
1406
+
1407
+ error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
1408
+ NULL, git_buf_cstr(&log_message));
1249
1409
 
1250
- error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0);
1251
- git_reference_free(reference);
1410
+ git_reference_free(dummy);
1252
1411
 
1412
+ cleanup:
1413
+ git_reference_free(reference_in);
1414
+ git_reference_free(ref);
1415
+ git_buf_free(&namespace);
1416
+ git_buf_free(&old_namespace);
1253
1417
  git_buf_free(&new_name);
1418
+ git_buf_free(&log_message);
1254
1419
  return error;
1255
1420
  }
1256
1421
 
@@ -1259,171 +1424,150 @@ static int rename_remote_references(
1259
1424
  const char *old_name,
1260
1425
  const char *new_name)
1261
1426
  {
1262
- int error = -1;
1427
+ int error;
1428
+ git_buf buf = GIT_BUF_INIT;
1263
1429
  git_reference *ref;
1264
1430
  git_reference_iterator *iter;
1265
1431
 
1266
- if (git_reference_iterator_new(&iter, repo) < 0)
1267
- return -1;
1432
+ if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
1433
+ return error;
1268
1434
 
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
- }
1435
+ error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1436
+ git_buf_free(&buf);
1274
1437
 
1275
- if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) {
1276
- git_reference_iterator_free(iter);
1277
- return error;
1278
- }
1438
+ if (error < 0)
1439
+ return error;
1440
+
1441
+ while ((error = git_reference_next(&ref, iter)) == 0) {
1442
+ if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1443
+ break;
1279
1444
  }
1280
1445
 
1281
1446
  git_reference_iterator_free(iter);
1282
1447
 
1283
- if (error == GIT_ITEROVER)
1284
- return 0;
1285
-
1286
- return error;
1448
+ return (error == GIT_ITEROVER) ? 0 : error;
1287
1449
  }
1288
1450
 
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)
1451
+ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
1294
1452
  {
1295
1453
  git_config *config;
1296
1454
  git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1297
1455
  const git_refspec *spec;
1298
1456
  size_t i;
1299
- int error = -1;
1457
+ int error = 0;
1300
1458
 
1301
- if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0)
1302
- goto cleanup;
1459
+ if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
1460
+ return error;
1461
+
1462
+ if ((error = git_vector_init(problems, 1, NULL)) < 0)
1463
+ return error;
1464
+
1465
+ if ((error = git_buf_printf(
1466
+ &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
1467
+ return error;
1303
1468
 
1304
1469
  git_vector_foreach(&remote->refspecs, i, spec) {
1305
1470
  if (spec->push)
1306
1471
  continue;
1307
1472
 
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
- }
1473
+ /* Does the dst part of the refspec follow the expected format? */
1474
+ if (strcmp(git_buf_cstr(&base), spec->string)) {
1475
+ char *dup;
1314
1476
 
1315
- continue;
1316
- }
1477
+ dup = git__strdup(spec->string);
1478
+ GITERR_CHECK_ALLOC(dup);
1317
1479
 
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
- }
1480
+ if ((error = git_vector_insert(problems, dup)) < 0)
1481
+ break;
1324
1482
 
1325
1483
  continue;
1326
1484
  }
1327
1485
 
1328
1486
  /* 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
1487
 
1332
- if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1333
- goto cleanup;
1488
+ git_buf_clear(&val);
1489
+ git_buf_clear(&var);
1334
1490
 
1335
- if (git_repository_config__weakptr(&config, remote->repo) < 0)
1336
- goto cleanup;
1491
+ if (git_buf_printf(
1492
+ &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
1493
+ git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1494
+ {
1495
+ error = -1;
1496
+ break;
1497
+ }
1337
1498
 
1338
- if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0)
1339
- goto cleanup;
1499
+ if ((error = git_config_set_string(
1500
+ config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
1501
+ break;
1340
1502
  }
1341
1503
 
1342
- error = 0;
1343
-
1344
- cleanup:
1345
1504
  git_buf_free(&base);
1346
1505
  git_buf_free(&var);
1347
1506
  git_buf_free(&val);
1507
+
1508
+ if (error < 0) {
1509
+ char *str;
1510
+ git_vector_foreach(problems, i, str)
1511
+ git__free(str);
1512
+
1513
+ git_vector_free(problems);
1514
+ }
1515
+
1348
1516
  return error;
1349
1517
  }
1350
1518
 
1351
- int git_remote_rename(
1352
- git_remote *remote,
1353
- const char *new_name,
1354
- git_remote_rename_problem_cb callback,
1355
- void *payload)
1519
+ int git_remote_rename(git_strarray *out, git_remote *remote, const char *new_name)
1356
1520
  {
1357
1521
  int error;
1522
+ git_vector problem_refspecs;
1523
+ char *tmp, *dup;
1358
1524
 
1359
- assert(remote && new_name);
1525
+ assert(out && remote && new_name);
1360
1526
 
1361
1527
  if (!remote->name) {
1362
- giterr_set(GITERR_INVALID, "Can't rename an in-memory remote.");
1528
+ giterr_set(GITERR_INVALID, "Can't rename an anonymous remote.");
1363
1529
  return GIT_EINVALIDSPEC;
1364
1530
  }
1365
1531
 
1366
1532
  if ((error = ensure_remote_name_is_valid(new_name)) < 0)
1367
1533
  return error;
1368
1534
 
1369
- if (remote->repo) {
1370
- if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1371
- return error;
1535
+ if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1536
+ return error;
1537
+
1538
+ if ((error = rename_remote_config_section(remote->repo, remote->name, new_name)) < 0)
1539
+ return error;
1372
1540
 
1373
- if (!remote->name) {
1374
- if ((error = rename_fetch_refspecs(
1375
- remote,
1376
- new_name,
1377
- callback,
1378
- payload)) < 0)
1379
- return error;
1541
+ if ((error = update_branch_remote_config_entry(remote->repo, remote->name, new_name)) < 0)
1542
+ return error;
1380
1543
 
1381
- remote->name = git__strdup(new_name);
1544
+ if ((error = rename_remote_references(remote->repo, remote->name, new_name)) < 0)
1545
+ return error;
1382
1546
 
1383
- if (!remote->name) return 0;
1384
- return git_remote_save(remote);
1385
- }
1547
+ if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
1548
+ return error;
1386
1549
 
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
- }
1550
+ out->count = problem_refspecs.length;
1551
+ out->strings = (char **) problem_refspecs.contents;
1412
1552
 
1413
- git__free(remote->name);
1414
- remote->name = git__strdup(new_name);
1553
+ dup = git__strdup(new_name);
1554
+ GITERR_CHECK_ALLOC(dup);
1555
+
1556
+ tmp = remote->name;
1557
+ remote->name = dup;
1558
+ git__free(tmp);
1415
1559
 
1416
1560
  return 0;
1417
1561
  }
1418
1562
 
1419
1563
  int git_remote_update_fetchhead(git_remote *remote)
1420
1564
  {
1421
- return remote->update_fetchhead;
1565
+ return (remote->update_fetchhead != 0);
1422
1566
  }
1423
1567
 
1424
1568
  void git_remote_set_update_fetchhead(git_remote *remote, int value)
1425
1569
  {
1426
- remote->update_fetchhead = value;
1570
+ remote->update_fetchhead = (value != 0);
1427
1571
  }
1428
1572
 
1429
1573
  int git_remote_is_valid_name(
@@ -1451,7 +1595,7 @@ git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refnam
1451
1595
  git_refspec *spec;
1452
1596
  size_t i;
1453
1597
 
1454
- git_vector_foreach(&remote->refspecs, i, spec) {
1598
+ git_vector_foreach(&remote->active_refspecs, i, spec) {
1455
1599
  if (spec->push)
1456
1600
  continue;
1457
1601
 
@@ -1467,7 +1611,7 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re
1467
1611
  git_refspec *spec;
1468
1612
  size_t i;
1469
1613
 
1470
- git_vector_foreach(&remote->refspecs, i, spec) {
1614
+ git_vector_foreach(&remote->active_refspecs, i, spec) {
1471
1615
  if (spec->push)
1472
1616
  continue;
1473
1617
 
@@ -1490,17 +1634,71 @@ void git_remote_clear_refspecs(git_remote *remote)
1490
1634
  git_vector_clear(&remote->refspecs);
1491
1635
  }
1492
1636
 
1637
+ static int add_and_dwim(git_remote *remote, const char *str, int push)
1638
+ {
1639
+ git_refspec *spec;
1640
+ git_vector *vec;
1641
+
1642
+ if (add_refspec(remote, str, !push) < 0)
1643
+ return -1;
1644
+
1645
+ vec = &remote->refspecs;
1646
+ spec = git_vector_get(vec, vec->length - 1);
1647
+ return git_refspec__dwim_one(&remote->active_refspecs, spec, &remote->refs);
1648
+ }
1649
+
1493
1650
  int git_remote_add_fetch(git_remote *remote, const char *refspec)
1494
1651
  {
1495
- return add_refspec(remote, refspec, true);
1652
+ return add_and_dwim(remote, refspec, false);
1496
1653
  }
1497
1654
 
1498
1655
  int git_remote_add_push(git_remote *remote, const char *refspec)
1499
1656
  {
1500
- return add_refspec(remote, refspec, false);
1657
+ return add_and_dwim(remote, refspec, true);
1501
1658
  }
1502
1659
 
1503
- static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
1660
+ static int set_refspecs(git_remote *remote, git_strarray *array, int push)
1661
+ {
1662
+ git_vector *vec = &remote->refspecs;
1663
+ git_refspec *spec;
1664
+ size_t i;
1665
+
1666
+ /* Start by removing any refspecs of the same type */
1667
+ for (i = 0; i < vec->length; i++) {
1668
+ spec = git_vector_get(vec, i);
1669
+ if (spec->push != push)
1670
+ continue;
1671
+
1672
+ git_refspec__free(spec);
1673
+ git__free(spec);
1674
+ git_vector_remove(vec, i);
1675
+ i--;
1676
+ }
1677
+
1678
+ /* And now we add the new ones */
1679
+
1680
+ for (i = 0; i < array->count; i++) {
1681
+ if (add_refspec(remote, array->strings[i], !push) < 0)
1682
+ return -1;
1683
+ }
1684
+
1685
+ free_refspecs(&remote->active_refspecs);
1686
+ git_vector_clear(&remote->active_refspecs);
1687
+
1688
+ return dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs);
1689
+ }
1690
+
1691
+ int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array)
1692
+ {
1693
+ return set_refspecs(remote, array, false);
1694
+ }
1695
+
1696
+ int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array)
1697
+ {
1698
+ return set_refspecs(remote, array, true);
1699
+ }
1700
+
1701
+ static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
1504
1702
  {
1505
1703
  size_t i;
1506
1704
  git_vector refspecs;
@@ -1529,44 +1727,246 @@ static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
1529
1727
  return 0;
1530
1728
 
1531
1729
  on_error:
1532
- git_vector_foreach(&refspecs, i, dup)
1533
- git__free(dup);
1534
- git_vector_free(&refspecs);
1730
+ git_vector_free_deep(&refspecs);
1535
1731
 
1536
1732
  return -1;
1537
1733
  }
1538
1734
 
1539
- int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote)
1735
+ int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
1540
1736
  {
1541
1737
  return copy_refspecs(array, remote, false);
1542
1738
  }
1543
1739
 
1544
- int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote)
1740
+ int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
1545
1741
  {
1546
1742
  return copy_refspecs(array, remote, true);
1547
1743
  }
1548
1744
 
1549
- size_t git_remote_refspec_count(git_remote *remote)
1745
+ size_t git_remote_refspec_count(const git_remote *remote)
1550
1746
  {
1551
1747
  return remote->refspecs.length;
1552
1748
  }
1553
1749
 
1554
- const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n)
1750
+ const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1555
1751
  {
1556
1752
  return git_vector_get(&remote->refspecs, n);
1557
1753
  }
1558
1754
 
1559
- int git_remote_remove_refspec(git_remote *remote, size_t n)
1755
+ int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
1560
1756
  {
1561
- git_refspec *spec;
1757
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1758
+ opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
1759
+ return 0;
1760
+ }
1761
+
1762
+ /* asserts a branch.<foo>.remote format */
1763
+ static const char *name_offset(size_t *len_out, const char *name)
1764
+ {
1765
+ size_t prefix_len;
1766
+ const char *dot;
1767
+
1768
+ prefix_len = strlen("remote.");
1769
+ dot = strchr(name + prefix_len, '.');
1770
+
1771
+ assert(dot);
1772
+
1773
+ *len_out = dot - name - prefix_len;
1774
+ return name + prefix_len;
1775
+ }
1776
+
1777
+ static int remove_branch_config_related_entries(
1778
+ git_repository *repo,
1779
+ const char *remote_name)
1780
+ {
1781
+ int error;
1782
+ git_config *config;
1783
+ git_config_entry *entry;
1784
+ git_config_iterator *iter;
1785
+ git_buf buf = GIT_BUF_INIT;
1786
+
1787
+ if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1788
+ return error;
1789
+
1790
+ if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
1791
+ return error;
1792
+
1793
+ /* find any branches with us as upstream and remove that config */
1794
+ while ((error = git_config_next(&entry, iter)) == 0) {
1795
+ const char *branch;
1796
+ size_t branch_len;
1797
+
1798
+ if (strcmp(remote_name, entry->value))
1799
+ continue;
1800
+
1801
+ branch = name_offset(&branch_len, entry->name);
1802
+
1803
+ git_buf_clear(&buf);
1804
+ if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
1805
+ break;
1806
+
1807
+ if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
1808
+ break;
1809
+
1810
+ git_buf_clear(&buf);
1811
+ if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
1812
+ break;
1813
+
1814
+ if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
1815
+ break;
1816
+ }
1817
+
1818
+ if (error == GIT_ITEROVER)
1819
+ error = 0;
1820
+
1821
+ git_buf_free(&buf);
1822
+ git_config_iterator_free(iter);
1823
+ return error;
1824
+ }
1825
+
1826
+ static int remove_refs(git_repository *repo, const git_refspec *spec)
1827
+ {
1828
+ git_reference_iterator *iter = NULL;
1829
+ git_vector refs;
1830
+ const char *name;
1831
+ char *dup;
1832
+ int error;
1833
+ size_t i;
1834
+
1835
+ if ((error = git_vector_init(&refs, 8, NULL)) < 0)
1836
+ return error;
1837
+
1838
+ if ((error = git_reference_iterator_new(&iter, repo)) < 0)
1839
+ goto cleanup;
1840
+
1841
+ while ((error = git_reference_next_name(&name, iter)) == 0) {
1842
+ if (!git_refspec_dst_matches(spec, name))
1843
+ continue;
1844
+
1845
+ dup = git__strdup(name);
1846
+ if (!dup) {
1847
+ error = -1;
1848
+ goto cleanup;
1849
+ }
1850
+
1851
+ if ((error = git_vector_insert(&refs, dup)) < 0)
1852
+ goto cleanup;
1853
+ }
1854
+ if (error == GIT_ITEROVER)
1855
+ error = 0;
1856
+ if (error < 0)
1857
+ goto cleanup;
1858
+
1859
+ git_vector_foreach(&refs, i, name) {
1860
+ if ((error = git_reference_remove(repo, name)) < 0)
1861
+ break;
1862
+ }
1863
+
1864
+ cleanup:
1865
+ git_reference_iterator_free(iter);
1866
+ git_vector_foreach(&refs, i, dup) {
1867
+ git__free(dup);
1868
+ }
1869
+ git_vector_free(&refs);
1870
+ return error;
1871
+ }
1872
+
1873
+ static int remove_remote_tracking(git_repository *repo, const char *remote_name)
1874
+ {
1875
+ git_remote *remote;
1876
+ int error;
1877
+ size_t i, count;
1878
+
1879
+ /* we want to use what's on the config, regardless of changes to the instance in memory */
1880
+ if ((error = git_remote_load(&remote, repo, remote_name)) < 0)
1881
+ return error;
1882
+
1883
+ count = git_remote_refspec_count(remote);
1884
+ for (i = 0; i < count; i++) {
1885
+ const git_refspec *refspec = git_remote_get_refspec(remote, i);
1886
+
1887
+ /* shouldn't ever actually happen */
1888
+ if (refspec == NULL)
1889
+ continue;
1890
+
1891
+ if ((error = remove_refs(repo, refspec)) < 0)
1892
+ break;
1893
+ }
1894
+
1895
+ git_remote_free(remote);
1896
+ return error;
1897
+ }
1898
+
1899
+ int git_remote_delete(git_remote *remote)
1900
+ {
1901
+ int error;
1902
+ git_repository *repo;
1562
1903
 
1563
1904
  assert(remote);
1564
1905
 
1565
- spec = git_vector_get(&remote->refspecs, n);
1566
- if (spec) {
1567
- git_refspec__free(spec);
1568
- git__free(spec);
1906
+ if (!remote->name) {
1907
+ giterr_set(GITERR_INVALID, "Can't delete an anonymous remote.");
1908
+ return -1;
1909
+ }
1910
+
1911
+ repo = git_remote_owner(remote);
1912
+
1913
+ if ((error = remove_branch_config_related_entries(repo,
1914
+ git_remote_name(remote))) < 0)
1915
+ return error;
1916
+
1917
+ if ((error = remove_remote_tracking(repo, git_remote_name(remote))) < 0)
1918
+ return error;
1919
+
1920
+ if ((error = rename_remote_config_section(
1921
+ repo, git_remote_name(remote), NULL)) < 0)
1922
+ return error;
1923
+
1924
+ return 0;
1925
+ }
1926
+
1927
+ int git_remote_default_branch(git_buf *out, git_remote *remote)
1928
+ {
1929
+ const git_remote_head **heads;
1930
+ const git_remote_head *guess = NULL;
1931
+ const git_oid *head_id;
1932
+ size_t heads_len, i;
1933
+ int error;
1934
+
1935
+ if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
1936
+ return error;
1937
+
1938
+ if (heads_len == 0)
1939
+ return GIT_ENOTFOUND;
1940
+
1941
+ git_buf_sanitize(out);
1942
+ /* the first one must be HEAD so if that has the symref info, we're done */
1943
+ if (heads[0]->symref_target)
1944
+ return git_buf_puts(out, heads[0]->symref_target);
1945
+
1946
+ /*
1947
+ * If there's no symref information, we have to look over them
1948
+ * and guess. We return the first match unless the master
1949
+ * branch is a candidate. Then we return the master branch.
1950
+ */
1951
+ head_id = &heads[0]->oid;
1952
+
1953
+ for (i = 1; i < heads_len; i++) {
1954
+ if (git_oid_cmp(head_id, &heads[i]->oid))
1955
+ continue;
1956
+
1957
+ if (!guess) {
1958
+ guess = heads[i];
1959
+ continue;
1960
+ }
1961
+
1962
+ if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
1963
+ guess = heads[i];
1964
+ break;
1965
+ }
1569
1966
  }
1570
1967
 
1571
- return git_vector_remove(&remote->refspecs, n);
1968
+ if (!guess)
1969
+ return GIT_ENOTFOUND;
1970
+
1971
+ return git_buf_puts(out, guess->name);
1572
1972
  }