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,25 +5,24 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
- #include "common.h"
8
+ #include "submodule.h"
9
+
9
10
  #include "git2/config.h"
10
11
  #include "git2/sys/config.h"
11
12
  #include "git2/types.h"
12
- #include "git2/repository.h"
13
13
  #include "git2/index.h"
14
- #include "git2/submodule.h"
15
14
  #include "buffer.h"
16
15
  #include "buf_text.h"
17
16
  #include "vector.h"
18
17
  #include "posix.h"
19
- #include "config_file.h"
18
+ #include "config_backend.h"
20
19
  #include "config.h"
21
20
  #include "repository.h"
22
- #include "submodule.h"
23
21
  #include "tree.h"
24
22
  #include "iterator.h"
25
23
  #include "path.h"
26
24
  #include "index.h"
25
+ #include "worktree.h"
27
26
 
28
27
  #define GIT_MODULES_FILE ".gitmodules"
29
28
 
@@ -32,6 +31,8 @@ static git_cvar_map _sm_update_map[] = {
32
31
  {GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
33
32
  {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
34
33
  {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
34
+ {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
35
+ {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
35
36
  };
36
37
 
37
38
  static git_cvar_map _sm_ignore_map[] = {
@@ -39,49 +40,39 @@ static git_cvar_map _sm_ignore_map[] = {
39
40
  {GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
40
41
  {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
41
42
  {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
43
+ {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
44
+ {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
42
45
  };
43
46
 
44
- static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
45
- {
46
- khint_t h;
47
-
48
- for (h = 0; *s; ++s)
49
- if (s[1] != '\0' || *s != '/')
50
- h = (h << 5) - h + *s;
51
-
52
- return h;
53
- }
54
-
55
- static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b)
56
- {
57
- size_t alen = a ? strlen(a) : 0;
58
- size_t blen = b ? strlen(b) : 0;
59
-
60
- if (alen > 0 && a[alen - 1] == '/')
61
- alen--;
62
- if (blen > 0 && b[blen - 1] == '/')
63
- blen--;
64
-
65
- return (alen == blen && strncmp(a, b, alen) == 0);
66
- }
47
+ static git_cvar_map _sm_recurse_map[] = {
48
+ {GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
49
+ {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
50
+ {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
51
+ };
67
52
 
68
- __KHASH_IMPL(
69
- str, static kh_inline, const char *, void *, 1,
70
- str_hash_no_trailing_slash, str_equal_no_trailing_slash);
53
+ enum {
54
+ CACHE_OK = 0,
55
+ CACHE_REFRESH = 1,
56
+ CACHE_FLUSH = 2
57
+ };
58
+ enum {
59
+ GITMODULES_EXISTING = 0,
60
+ GITMODULES_CREATE = 1,
61
+ };
71
62
 
72
- static int load_submodule_config(git_repository *repo);
73
- static git_config_backend *open_gitmodules(git_repository *, bool, const git_oid *);
74
- static int lookup_head_remote(git_buf *url, git_repository *repo);
75
- static int submodule_get(git_submodule **, git_repository *, const char *, const char *);
76
- static void submodule_release(git_submodule *sm, int decr);
77
- static int submodule_load_from_index(git_repository *, const git_index_entry *);
78
- static int submodule_load_from_head(git_repository*, const char*, const git_oid*);
79
- static int submodule_load_from_config(const git_config_entry *, void *);
80
- static int submodule_load_from_wd_lite(git_submodule *, const char *, void *);
81
- static int submodule_update_config(git_submodule *, const char *, const char *, bool, bool);
82
- static void submodule_mode_mismatch(git_repository *, const char *, unsigned int);
83
- static int submodule_index_status(unsigned int *status, git_submodule *sm);
84
- static int submodule_wd_status(unsigned int *status, git_submodule *sm);
63
+ static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
64
+ static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
65
+ static int gitmodules_snapshot(git_config **snap, git_repository *repo);
66
+ static int get_url_base(git_buf *url, git_repository *repo);
67
+ static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
68
+ static int lookup_default_remote(git_remote **remote, git_repository *repo);
69
+ static int submodule_load_each(const git_config_entry *entry, void *payload);
70
+ static int submodule_read_config(git_submodule *sm, git_config *cfg);
71
+ static int submodule_load_from_wd_lite(git_submodule *);
72
+ static void submodule_get_index_status(unsigned int *, git_submodule *);
73
+ static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
74
+ static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie);
75
+ static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id);
85
76
 
86
77
  static int submodule_cmp(const void *a, const void *b)
87
78
  {
@@ -99,110 +90,629 @@ static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
99
90
  * PUBLIC APIS
100
91
  */
101
92
 
93
+ static void submodule_set_lookup_error(int error, const char *name)
94
+ {
95
+ if (!error)
96
+ return;
97
+
98
+ git_error_set(GIT_ERROR_SUBMODULE, (error == GIT_ENOTFOUND) ?
99
+ "no submodule named '%s'" :
100
+ "submodule '%s' has not been added yet", name);
101
+ }
102
+
103
+ typedef struct {
104
+ const char *path;
105
+ char *name;
106
+ } fbp_data;
107
+
108
+ static int find_by_path(const git_config_entry *entry, void *payload)
109
+ {
110
+ fbp_data *data = payload;
111
+
112
+ if (!strcmp(entry->value, data->path)) {
113
+ const char *fdot, *ldot;
114
+ fdot = strchr(entry->name, '.');
115
+ ldot = strrchr(entry->name, '.');
116
+ data->name = git__strndup(fdot + 1, ldot - fdot - 1);
117
+ GIT_ERROR_CHECK_ALLOC(data->name);
118
+ }
119
+
120
+ return 0;
121
+ }
122
+
123
+ /*
124
+ * Checks to see if the submodule shares its name with a file or directory that
125
+ * already exists on the index. If so, the submodule cannot be added.
126
+ */
127
+ static int is_path_occupied(bool *occupied, git_repository *repo, const char *path)
128
+ {
129
+ int error = 0;
130
+ git_index *index;
131
+ git_buf dir = GIT_BUF_INIT;
132
+ *occupied = false;
133
+
134
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0)
135
+ goto out;
136
+
137
+ if ((error = git_index_find(NULL, index, path)) != GIT_ENOTFOUND) {
138
+ if (!error) {
139
+ git_error_set(GIT_ERROR_SUBMODULE,
140
+ "File '%s' already exists in the index", path);
141
+ *occupied = true;
142
+ }
143
+ goto out;
144
+ }
145
+
146
+ if ((error = git_buf_sets(&dir, path)) < 0)
147
+ goto out;
148
+
149
+ if ((error = git_path_to_dir(&dir)) < 0)
150
+ goto out;
151
+
152
+ if ((error = git_index_find_prefix(NULL, index, dir.ptr)) != GIT_ENOTFOUND) {
153
+ if (!error) {
154
+ git_error_set(GIT_ERROR_SUBMODULE,
155
+ "Directory '%s' already exists in the index", path);
156
+ *occupied = true;
157
+ }
158
+ goto out;
159
+ }
160
+
161
+ error = 0;
162
+
163
+ out:
164
+ git_buf_dispose(&dir);
165
+ return error;
166
+ }
167
+
168
+ /**
169
+ * Release the name map returned by 'load_submodule_names'.
170
+ */
171
+ static void free_submodule_names(git_strmap *names)
172
+ {
173
+ const char *key;
174
+ char *value;
175
+
176
+ if (names == NULL)
177
+ return;
178
+
179
+ git_strmap_foreach(names, key, value, {
180
+ git__free((char *) key);
181
+ git__free(value);
182
+ });
183
+ git_strmap_free(names);
184
+
185
+ return;
186
+ }
187
+
188
+ /**
189
+ * Map submodule paths to names.
190
+ * TODO: for some use-cases, this might need case-folding on a
191
+ * case-insensitive filesystem
192
+ */
193
+ static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg)
194
+ {
195
+ const char *key = "submodule\\..*\\.path";
196
+ git_config_iterator *iter = NULL;
197
+ git_config_entry *entry;
198
+ git_buf buf = GIT_BUF_INIT;
199
+ git_strmap *names;
200
+ int rval, isvalid;
201
+ int error = 0;
202
+
203
+ *out = NULL;
204
+
205
+ if ((error = git_strmap_alloc(&names)) < 0)
206
+ goto out;
207
+
208
+ if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
209
+ goto out;
210
+
211
+ while ((error = git_config_next(&entry, iter)) == 0) {
212
+ const char *fdot, *ldot;
213
+ fdot = strchr(entry->name, '.');
214
+ ldot = strrchr(entry->name, '.');
215
+
216
+ if (git_strmap_exists(names, entry->value)) {
217
+ git_error_set(GIT_ERROR_SUBMODULE,
218
+ "duplicated submodule path '%s'", entry->value);
219
+ error = -1;
220
+ goto out;
221
+ }
222
+
223
+ git_buf_clear(&buf);
224
+ git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
225
+ isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0);
226
+ if (isvalid < 0) {
227
+ error = isvalid;
228
+ goto out;
229
+ }
230
+ if (!isvalid)
231
+ continue;
232
+
233
+ git_strmap_insert(names, git__strdup(entry->value), git_buf_detach(&buf), &rval);
234
+ if (rval < 0) {
235
+ git_error_set(GIT_ERROR_NOMEMORY, "error inserting submodule into hash table");
236
+ error = -1;
237
+ goto out;
238
+ }
239
+ }
240
+ if (error == GIT_ITEROVER)
241
+ error = 0;
242
+
243
+ *out = names;
244
+ names = NULL;
245
+
246
+ out:
247
+ free_submodule_names(names);
248
+ git_buf_dispose(&buf);
249
+ git_config_iterator_free(iter);
250
+ return error;
251
+ }
252
+
102
253
  int git_submodule_lookup(
103
- git_submodule **sm_ptr, /* NULL if user only wants to test existence */
254
+ git_submodule **out, /* NULL if user only wants to test existence */
104
255
  git_repository *repo,
105
- const char *name) /* trailing slash is allowed */
256
+ const char *name) /* trailing slash is allowed */
106
257
  {
107
258
  int error;
108
- khiter_t pos;
259
+ unsigned int location;
260
+ git_submodule *sm;
109
261
 
110
262
  assert(repo && name);
111
263
 
112
- if ((error = load_submodule_config(repo)) < 0)
264
+ if (repo->is_bare) {
265
+ git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
266
+ return -1;
267
+ }
268
+
269
+ if (repo->submodule_cache != NULL) {
270
+ size_t pos = git_strmap_lookup_index(repo->submodule_cache, name);
271
+ if (git_strmap_valid_index(repo->submodule_cache, pos)) {
272
+ if (out) {
273
+ *out = git_strmap_value_at(repo->submodule_cache, pos);
274
+ GIT_REFCOUNT_INC(*out);
275
+ }
276
+ return 0;
277
+ }
278
+ }
279
+
280
+ if ((error = submodule_alloc(&sm, repo, name)) < 0)
113
281
  return error;
114
282
 
115
- pos = git_strmap_lookup_index(repo->submodules, name);
283
+ if ((error = git_submodule_reload(sm, false)) < 0) {
284
+ git_submodule_free(sm);
285
+ return error;
286
+ }
287
+
288
+ if ((error = git_submodule_location(&location, sm)) < 0) {
289
+ git_submodule_free(sm);
290
+ return error;
291
+ }
292
+
293
+ /* If it's not configured or we're looking by path */
294
+ if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
295
+ git_config_backend *mods;
296
+ const char *pattern = "submodule\\..*\\.path";
297
+ git_buf path = GIT_BUF_INIT;
298
+ fbp_data data = { NULL, NULL };
299
+
300
+ git_buf_puts(&path, name);
301
+ while (path.ptr[path.size-1] == '/') {
302
+ path.ptr[--path.size] = '\0';
303
+ }
304
+ data.path = path.ptr;
305
+
306
+ mods = open_gitmodules(repo, GITMODULES_EXISTING);
307
+
308
+ if (mods)
309
+ error = git_config_backend_foreach_match(mods, pattern, find_by_path, &data);
310
+
311
+ git_config_backend_free(mods);
312
+
313
+ if (error < 0) {
314
+ git_submodule_free(sm);
315
+ git_buf_dispose(&path);
316
+ return error;
317
+ }
318
+
319
+ if (data.name) {
320
+ git__free(sm->name);
321
+ sm->name = data.name;
322
+ sm->path = git_buf_detach(&path);
323
+
324
+ /* Try to load again with the right name */
325
+ if ((error = git_submodule_reload(sm, false)) < 0) {
326
+ git_submodule_free(sm);
327
+ return error;
328
+ }
329
+ }
330
+
331
+ git_buf_dispose(&path);
332
+ }
116
333
 
117
- if (!git_strmap_valid_index(repo->submodules, pos)) {
334
+ if ((error = git_submodule_location(&location, sm)) < 0) {
335
+ git_submodule_free(sm);
336
+ return error;
337
+ }
338
+
339
+ /* If we still haven't found it, do the WD check */
340
+ if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
341
+ git_submodule_free(sm);
118
342
  error = GIT_ENOTFOUND;
119
343
 
120
- /* check if a plausible submodule exists at path */
344
+ /* If it's not configured, we still check if there's a repo at the path */
121
345
  if (git_repository_workdir(repo)) {
122
346
  git_buf path = GIT_BUF_INIT;
123
-
124
- if (git_buf_joinpath(&path, git_repository_workdir(repo), name) < 0)
347
+ if (git_buf_join3(&path,
348
+ '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
125
349
  return -1;
126
350
 
127
- if (git_path_contains_dir(&path, DOT_GIT))
351
+ if (git_path_exists(path.ptr))
128
352
  error = GIT_EEXISTS;
129
353
 
130
- git_buf_free(&path);
354
+ git_buf_dispose(&path);
131
355
  }
132
356
 
133
- giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
134
- "No submodule named '%s'" :
135
- "Submodule '%s' has not been added yet", name);
357
+ submodule_set_lookup_error(error, name);
358
+ return error;
359
+ }
360
+
361
+ if (out)
362
+ *out = sm;
363
+ else
364
+ git_submodule_free(sm);
365
+
366
+ return 0;
367
+ }
368
+
369
+ int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags)
370
+ {
371
+ git_buf buf = GIT_BUF_INIT;
372
+ int error, isvalid;
373
+
374
+ if (flags == 0)
375
+ flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS;
376
+
377
+ /* Avoid allocating a new string if we can avoid it */
378
+ if (strchr(name, '\\') != NULL) {
379
+ if ((error = git_path_normalize_slashes(&buf, name)) < 0)
380
+ return error;
381
+ } else {
382
+ git_buf_attach_notowned(&buf, name, strlen(name));
383
+ }
384
+
385
+ isvalid = git_path_isvalid(repo, buf.ptr, 0, flags);
386
+ git_buf_dispose(&buf);
387
+
388
+ return isvalid;
389
+ }
390
+
391
+ static void submodule_free_dup(void *sm)
392
+ {
393
+ git_submodule_free(sm);
394
+ }
395
+
396
+ static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
397
+ {
398
+ int error = 0;
399
+ size_t pos;
400
+ git_submodule *sm = NULL;
136
401
 
402
+ pos = git_strmap_lookup_index(map, name);
403
+ if (git_strmap_valid_index(map, pos)) {
404
+ sm = git_strmap_value_at(map, pos);
405
+ goto done;
406
+ }
407
+
408
+ /* if the submodule doesn't exist yet in the map, create it */
409
+ if ((error = submodule_alloc(&sm, repo, name)) < 0)
410
+ return error;
411
+
412
+ pos = git_strmap_put(map, sm->name, &error);
413
+ /* nobody can beat us to adding it */
414
+ assert(error != 0);
415
+ if (error < 0) {
416
+ git_submodule_free(sm);
137
417
  return error;
138
418
  }
139
419
 
140
- if (sm_ptr)
141
- *sm_ptr = git_strmap_value_at(repo->submodules, pos);
420
+ git_strmap_set_value_at(map, pos, sm);
142
421
 
422
+ done:
423
+ GIT_REFCOUNT_INC(sm);
424
+ *out = sm;
143
425
  return 0;
144
426
  }
145
427
 
428
+ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg)
429
+ {
430
+ int error;
431
+ git_iterator *i = NULL;
432
+ const git_index_entry *entry;
433
+ git_strmap *names;
434
+
435
+ if ((error = load_submodule_names(&names, git_index_owner(idx), cfg)))
436
+ goto done;
437
+
438
+ if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
439
+ goto done;
440
+
441
+ while (!(error = git_iterator_advance(&entry, i))) {
442
+ size_t pos = git_strmap_lookup_index(map, entry->path);
443
+ git_submodule *sm;
444
+
445
+ if (git_strmap_valid_index(map, pos)) {
446
+ sm = git_strmap_value_at(map, pos);
447
+
448
+ if (S_ISGITLINK(entry->mode))
449
+ submodule_update_from_index_entry(sm, entry);
450
+ else
451
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
452
+ } else if (S_ISGITLINK(entry->mode)) {
453
+ size_t name_pos;
454
+ const char *name;
455
+
456
+ name_pos = git_strmap_lookup_index(names, entry->path);
457
+ if (git_strmap_valid_index(names, name_pos)) {
458
+ name = git_strmap_value_at(names, name_pos);
459
+ } else {
460
+ name = entry->path;
461
+ }
462
+
463
+ if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
464
+ submodule_update_from_index_entry(sm, entry);
465
+ git_submodule_free(sm);
466
+ }
467
+ }
468
+ }
469
+
470
+ if (error == GIT_ITEROVER)
471
+ error = 0;
472
+
473
+ done:
474
+ git_iterator_free(i);
475
+ free_submodule_names(names);
476
+
477
+ return error;
478
+ }
479
+
480
+ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg)
481
+ {
482
+ int error;
483
+ git_iterator *i = NULL;
484
+ const git_index_entry *entry;
485
+ git_strmap *names;
486
+
487
+ if ((error = load_submodule_names(&names, git_tree_owner(head), cfg)))
488
+ goto done;
489
+
490
+ if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
491
+ goto done;
492
+
493
+ while (!(error = git_iterator_advance(&entry, i))) {
494
+ size_t pos = git_strmap_lookup_index(map, entry->path);
495
+ git_submodule *sm;
496
+
497
+ if (git_strmap_valid_index(map, pos)) {
498
+ sm = git_strmap_value_at(map, pos);
499
+
500
+ if (S_ISGITLINK(entry->mode))
501
+ submodule_update_from_head_data(sm, entry->mode, &entry->id);
502
+ else
503
+ sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
504
+ } else if (S_ISGITLINK(entry->mode)) {
505
+ size_t name_pos;
506
+ const char *name;
507
+
508
+ name_pos = git_strmap_lookup_index(names, entry->path);
509
+ if (git_strmap_valid_index(names, name_pos)) {
510
+ name = git_strmap_value_at(names, name_pos);
511
+ } else {
512
+ name = entry->path;
513
+ }
514
+
515
+ if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
516
+ submodule_update_from_head_data(
517
+ sm, entry->mode, &entry->id);
518
+ git_submodule_free(sm);
519
+ }
520
+ }
521
+ }
522
+
523
+ if (error == GIT_ITEROVER)
524
+ error = 0;
525
+
526
+ done:
527
+ git_iterator_free(i);
528
+ free_submodule_names(names);
529
+
530
+ return error;
531
+ }
532
+
533
+ /* If have_sm is true, sm is populated, otherwise map an repo are. */
534
+ typedef struct {
535
+ git_config *mods;
536
+ git_strmap *map;
537
+ git_repository *repo;
538
+ } lfc_data;
539
+
540
+ int git_submodule__map(git_repository *repo, git_strmap *map)
541
+ {
542
+ int error = 0;
543
+ git_index *idx = NULL;
544
+ git_tree *head = NULL;
545
+ const char *wd = NULL;
546
+ git_buf path = GIT_BUF_INIT;
547
+ git_submodule *sm;
548
+ git_config *mods = NULL;
549
+
550
+ assert(repo && map);
551
+
552
+ /* get sources that we will need to check */
553
+ if (git_repository_index(&idx, repo) < 0)
554
+ git_error_clear();
555
+ if (git_repository_head_tree(&head, repo) < 0)
556
+ git_error_clear();
557
+
558
+ wd = git_repository_workdir(repo);
559
+ if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
560
+ goto cleanup;
561
+
562
+ /* add submodule information from .gitmodules */
563
+ if (wd) {
564
+ lfc_data data = { 0 };
565
+ data.map = map;
566
+ data.repo = repo;
567
+
568
+ if ((error = gitmodules_snapshot(&mods, repo)) < 0) {
569
+ if (error == GIT_ENOTFOUND)
570
+ error = 0;
571
+ goto cleanup;
572
+ }
573
+
574
+ data.mods = mods;
575
+ if ((error = git_config_foreach(
576
+ mods, submodule_load_each, &data)) < 0)
577
+ goto cleanup;
578
+ }
579
+ /* add back submodule information from index */
580
+ if (mods && idx) {
581
+ if ((error = submodules_from_index(map, idx, mods)) < 0)
582
+ goto cleanup;
583
+ }
584
+ /* add submodule information from HEAD */
585
+ if (mods && head) {
586
+ if ((error = submodules_from_head(map, head, mods)) < 0)
587
+ goto cleanup;
588
+ }
589
+ /* shallow scan submodules in work tree as needed */
590
+ if (wd) {
591
+ git_strmap_foreach_value(map, sm, {
592
+ submodule_load_from_wd_lite(sm);
593
+ });
594
+ }
595
+
596
+ cleanup:
597
+ git_config_free(mods);
598
+ /* TODO: if we got an error, mark submodule config as invalid? */
599
+ git_index_free(idx);
600
+ git_tree_free(head);
601
+ git_buf_dispose(&path);
602
+ return error;
603
+ }
604
+
146
605
  int git_submodule_foreach(
147
606
  git_repository *repo,
148
- int (*callback)(git_submodule *sm, const char *name, void *payload),
607
+ git_submodule_cb callback,
149
608
  void *payload)
150
609
  {
151
- int error;
610
+ git_vector snapshot = GIT_VECTOR_INIT;
611
+ git_strmap *submodules;
152
612
  git_submodule *sm;
153
- git_vector seen = GIT_VECTOR_INIT;
154
- git_vector_set_cmp(&seen, submodule_cmp);
613
+ int error;
614
+ size_t i;
155
615
 
156
- assert(repo && callback);
616
+ if (repo->is_bare) {
617
+ git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
618
+ return -1;
619
+ }
157
620
 
158
- if ((error = load_submodule_config(repo)) < 0)
621
+ if ((error = git_strmap_alloc(&submodules)) < 0)
159
622
  return error;
160
623
 
161
- git_strmap_foreach_value(repo->submodules, sm, {
162
- /* Usually the following will not come into play - it just prevents
163
- * us from issuing a callback twice for a submodule where the name
164
- * and path are not the same.
165
- */
166
- if (sm->refcount > 1) {
167
- if (git_vector_bsearch(NULL, &seen, sm) != GIT_ENOTFOUND)
168
- continue;
169
- if ((error = git_vector_insert(&seen, sm)) < 0)
624
+ if ((error = git_submodule__map(repo, submodules)) < 0)
625
+ goto done;
626
+
627
+ if (!(error = git_vector_init(
628
+ &snapshot, git_strmap_num_entries(submodules), submodule_cmp))) {
629
+
630
+ git_strmap_foreach_value(submodules, sm, {
631
+ if ((error = git_vector_insert(&snapshot, sm)) < 0)
170
632
  break;
171
- }
633
+ GIT_REFCOUNT_INC(sm);
634
+ });
635
+ }
636
+
637
+ if (error < 0)
638
+ goto done;
172
639
 
173
- if (callback(sm, sm->name, payload)) {
174
- giterr_clear();
175
- error = GIT_EUSER;
640
+ git_vector_uniq(&snapshot, submodule_free_dup);
641
+
642
+ git_vector_foreach(&snapshot, i, sm) {
643
+ if ((error = callback(sm, sm->name, payload)) != 0) {
644
+ git_error_set_after_callback(error);
176
645
  break;
177
646
  }
178
- });
647
+ }
179
648
 
180
- git_vector_free(&seen);
649
+ done:
650
+ git_vector_foreach(&snapshot, i, sm)
651
+ git_submodule_free(sm);
652
+ git_vector_free(&snapshot);
653
+
654
+ git_strmap_foreach_value(submodules, sm, {
655
+ git_submodule_free(sm);
656
+ });
657
+ git_strmap_free(submodules);
181
658
 
182
659
  return error;
183
660
  }
184
661
 
185
- void git_submodule_config_free(git_repository *repo)
662
+ static int submodule_repo_init(
663
+ git_repository **out,
664
+ git_repository *parent_repo,
665
+ const char *path,
666
+ const char *url,
667
+ bool use_gitlink)
186
668
  {
187
- git_strmap *smcfg;
188
- git_submodule *sm;
669
+ int error = 0;
670
+ git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
671
+ git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
672
+ git_repository *subrepo = NULL;
189
673
 
190
- assert(repo);
674
+ error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
675
+ if (error < 0)
676
+ goto cleanup;
191
677
 
192
- smcfg = repo->submodules;
193
- repo->submodules = NULL;
678
+ initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT;
679
+ initopt.origin_url = url;
194
680
 
195
- if (smcfg == NULL)
196
- return;
681
+ /* init submodule repository and add origin remote as needed */
197
682
 
198
- git_strmap_foreach_value(smcfg, sm, {
199
- submodule_release(sm,1);
200
- });
201
- git_strmap_free(smcfg);
683
+ /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
684
+ * gitlink in the sub-repo workdir directory to that repository
685
+ *
686
+ * Old style: sub-repo goes directly into repo/<name>/.git/
687
+ */
688
+ if (use_gitlink) {
689
+ error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
690
+ if (error < 0)
691
+ goto cleanup;
692
+ error = git_buf_joinpath(&repodir, repodir.ptr, path);
693
+ if (error < 0)
694
+ goto cleanup;
695
+
696
+ initopt.workdir_path = workdir.ptr;
697
+ initopt.flags |=
698
+ GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
699
+ GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
700
+
701
+ error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
702
+ } else
703
+ error = git_repository_init_ext(&subrepo, workdir.ptr, &initopt);
704
+
705
+ cleanup:
706
+ git_buf_dispose(&workdir);
707
+ git_buf_dispose(&repodir);
708
+
709
+ *out = subrepo;
710
+
711
+ return error;
202
712
  }
203
713
 
204
714
  int git_submodule_add_setup(
205
- git_submodule **submodule,
715
+ git_submodule **out,
206
716
  git_repository *repo,
207
717
  const char *url,
208
718
  const char *path,
@@ -210,62 +720,56 @@ int git_submodule_add_setup(
210
720
  {
211
721
  int error = 0;
212
722
  git_config_backend *mods = NULL;
213
- git_submodule *sm;
723
+ git_submodule *sm = NULL;
214
724
  git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
215
- git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
216
725
  git_repository *subrepo = NULL;
726
+ bool path_occupied;
217
727
 
218
728
  assert(repo && url && path);
219
729
 
220
730
  /* see if there is already an entry for this submodule */
221
731
 
222
- if (git_submodule_lookup(&sm, repo, path) < 0)
223
- giterr_clear();
732
+ if (git_submodule_lookup(NULL, repo, path) < 0)
733
+ git_error_clear();
224
734
  else {
225
- giterr_set(GITERR_SUBMODULE,
226
- "Attempt to add a submodule that already exists");
735
+ git_error_set(GIT_ERROR_SUBMODULE,
736
+ "attempt to add submodule '%s' that already exists", path);
227
737
  return GIT_EEXISTS;
228
738
  }
229
739
 
230
- /* resolve parameters */
231
-
232
- if (url[0] == '.' && (url[1] == '/' || (url[1] == '.' && url[2] == '/'))) {
233
- if (!(error = lookup_head_remote(&real_url, repo)))
234
- error = git_path_apply_relative(&real_url, url);
235
- } else if (strchr(url, ':') != NULL || url[0] == '/') {
236
- error = git_buf_sets(&real_url, url);
237
- } else {
238
- giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
239
- error = -1;
240
- }
241
- if (error)
242
- goto cleanup;
243
-
244
740
  /* validate and normalize path */
245
741
 
246
742
  if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
247
743
  path += strlen(git_repository_workdir(repo));
248
744
 
249
745
  if (git_path_root(path) >= 0) {
250
- giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path");
746
+ git_error_set(GIT_ERROR_SUBMODULE, "submodule path must be a relative path");
251
747
  error = -1;
252
748
  goto cleanup;
253
749
  }
254
750
 
751
+ if ((error = is_path_occupied(&path_occupied, repo, path)) < 0)
752
+ goto cleanup;
753
+
754
+ if (path_occupied) {
755
+ error = GIT_EEXISTS;
756
+ goto cleanup;
757
+ }
758
+
255
759
  /* update .gitmodules */
256
760
 
257
- if ((mods = open_gitmodules(repo, true, NULL)) == NULL) {
258
- giterr_set(GITERR_SUBMODULE,
259
- "Adding submodules to a bare repository is not supported (for now)");
761
+ if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
762
+ git_error_set(GIT_ERROR_SUBMODULE,
763
+ "adding submodules to a bare repository is not supported");
260
764
  return -1;
261
765
  }
262
766
 
263
767
  if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 ||
264
- (error = git_config_file_set_string(mods, name.ptr, path)) < 0)
768
+ (error = git_config_backend_set_string(mods, name.ptr, path)) < 0)
265
769
  goto cleanup;
266
770
 
267
771
  if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
268
- (error = git_config_file_set_string(mods, name.ptr, real_url.ptr)) < 0)
772
+ (error = git_config_backend_set_string(mods, name.ptr, url)) < 0)
269
773
  goto cleanup;
270
774
 
271
775
  git_buf_clear(&name);
@@ -276,58 +780,66 @@ int git_submodule_add_setup(
276
780
  if (error < 0)
277
781
  goto cleanup;
278
782
 
279
- /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
280
- * gitlink in the sub-repo workdir directory to that repository
281
- *
282
- * Old style: sub-repo goes directly into repo/<name>/.git/
783
+ /* if the repo does not already exist, then init a new repo and add it.
784
+ * Otherwise, just add the existing repo.
283
785
  */
786
+ if (!(git_path_exists(name.ptr) &&
787
+ git_path_contains(&name, DOT_GIT))) {
284
788
 
285
- initopt.flags = GIT_REPOSITORY_INIT_MKPATH |
286
- GIT_REPOSITORY_INIT_NO_REINIT;
287
- initopt.origin_url = real_url.ptr;
288
-
289
- if (git_path_exists(name.ptr) &&
290
- git_path_contains(&name, DOT_GIT))
291
- {
292
- /* repo appears to already exist - reinit? */
293
- }
294
- else if (use_gitlink) {
295
- git_buf repodir = GIT_BUF_INIT;
789
+ /* resolve the actual URL to use */
790
+ if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
791
+ goto cleanup;
296
792
 
297
- error = git_buf_join_n(
298
- &repodir, '/', 3, git_repository_path(repo), "modules", path);
299
- if (error < 0)
793
+ if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
300
794
  goto cleanup;
795
+ }
301
796
 
302
- initopt.workdir_path = name.ptr;
303
- initopt.flags |= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
797
+ if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
798
+ goto cleanup;
304
799
 
305
- error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
800
+ error = git_submodule_init(sm, false);
306
801
 
307
- git_buf_free(&repodir);
308
- }
309
- else {
310
- error = git_repository_init_ext(&subrepo, name.ptr, &initopt);
802
+ cleanup:
803
+ if (error && sm) {
804
+ git_submodule_free(sm);
805
+ sm = NULL;
311
806
  }
312
- if (error < 0)
313
- goto cleanup;
807
+ if (out != NULL)
808
+ *out = sm;
314
809
 
315
- /* add submodule to hash and "reload" it */
810
+ git_config_backend_free(mods);
811
+ git_repository_free(subrepo);
812
+ git_buf_dispose(&real_url);
813
+ git_buf_dispose(&name);
316
814
 
317
- if (!(error = submodule_get(&sm, repo, path, NULL)) &&
318
- !(error = git_submodule_reload(sm)))
319
- error = git_submodule_init(sm, false);
815
+ return error;
816
+ }
320
817
 
321
- cleanup:
322
- if (submodule != NULL)
323
- *submodule = !error ? sm : NULL;
818
+ int git_submodule_repo_init(
819
+ git_repository **out,
820
+ const git_submodule *sm,
821
+ int use_gitlink)
822
+ {
823
+ int error;
824
+ git_repository *sub_repo = NULL;
825
+ const char *configured_url;
826
+ git_config *cfg = NULL;
827
+ git_buf buf = GIT_BUF_INIT;
324
828
 
325
- if (mods != NULL)
326
- git_config_file_free(mods);
327
- git_repository_free(subrepo);
328
- git_buf_free(&real_url);
329
- git_buf_free(&name);
829
+ assert(out && sm);
830
+
831
+ /* get the configured remote url of the submodule */
832
+ if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
833
+ (error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
834
+ (error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
835
+ (error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
836
+ goto done;
837
+
838
+ *out = sub_repo;
330
839
 
840
+ done:
841
+ git_config_free(cfg);
842
+ git_buf_dispose(&buf);
331
843
  return error;
332
844
  }
333
845
 
@@ -338,7 +850,7 @@ int git_submodule_add_finalize(git_submodule *sm)
338
850
 
339
851
  assert(sm);
340
852
 
341
- if ((error = git_repository_index__weakptr(&index, sm->owner)) < 0 ||
853
+ if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
342
854
  (error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0)
343
855
  return error;
344
856
 
@@ -348,7 +860,7 @@ int git_submodule_add_finalize(git_submodule *sm)
348
860
  int git_submodule_add_to_index(git_submodule *sm, int write_index)
349
861
  {
350
862
  int error;
351
- git_repository *repo, *sm_repo = NULL;
863
+ git_repository *sm_repo = NULL;
352
864
  git_index *index;
353
865
  git_buf path = GIT_BUF_INIT;
354
866
  git_commit *head;
@@ -357,44 +869,43 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
357
869
 
358
870
  assert(sm);
359
871
 
360
- repo = sm->owner;
361
-
362
872
  /* force reload of wd OID by git_submodule_open */
363
873
  sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;
364
874
 
365
- if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
875
+ if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
366
876
  (error = git_buf_joinpath(
367
- &path, git_repository_workdir(repo), sm->path)) < 0 ||
877
+ &path, git_repository_workdir(sm->repo), sm->path)) < 0 ||
368
878
  (error = git_submodule_open(&sm_repo, sm)) < 0)
369
879
  goto cleanup;
370
880
 
371
881
  /* read stat information for submodule working directory */
372
882
  if (p_stat(path.ptr, &st) < 0) {
373
- giterr_set(GITERR_SUBMODULE,
374
- "Cannot add submodule without working directory");
883
+ git_error_set(GIT_ERROR_SUBMODULE,
884
+ "cannot add submodule without working directory");
375
885
  error = -1;
376
886
  goto cleanup;
377
887
  }
378
888
 
379
889
  memset(&entry, 0, sizeof(entry));
380
890
  entry.path = sm->path;
381
- git_index_entry__init_from_stat(&entry, &st);
891
+ git_index_entry__init_from_stat(
892
+ &entry, &st, !(git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE));
382
893
 
383
894
  /* calling git_submodule_open will have set sm->wd_oid if possible */
384
895
  if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
385
- giterr_set(GITERR_SUBMODULE,
386
- "Cannot add submodule without HEAD to index");
896
+ git_error_set(GIT_ERROR_SUBMODULE,
897
+ "cannot add submodule without HEAD to index");
387
898
  error = -1;
388
899
  goto cleanup;
389
900
  }
390
- git_oid_cpy(&entry.oid, &sm->wd_oid);
901
+ git_oid_cpy(&entry.id, &sm->wd_oid);
391
902
 
392
903
  if ((error = git_commit_lookup(&head, sm_repo, &sm->wd_oid)) < 0)
393
904
  goto cleanup;
394
905
 
395
- entry.ctime.seconds = git_commit_time(head);
906
+ entry.ctime.seconds = (int32_t)git_commit_time(head);
396
907
  entry.ctime.nanoseconds = 0;
397
- entry.mtime.seconds = git_commit_time(head);
908
+ entry.mtime.seconds = (int32_t)git_commit_time(head);
398
909
  entry.mtime.nanoseconds = 0;
399
910
 
400
911
  git_commit_free(head);
@@ -412,112 +923,135 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
412
923
 
413
924
  cleanup:
414
925
  git_repository_free(sm_repo);
415
- git_buf_free(&path);
926
+ git_buf_dispose(&path);
416
927
  return error;
417
928
  }
418
929
 
419
- int git_submodule_save(git_submodule *submodule)
930
+ const char *git_submodule_update_to_str(git_submodule_update_t update)
420
931
  {
421
- int error = 0;
422
- git_config_backend *mods;
423
- git_buf key = GIT_BUF_INIT;
932
+ int i;
933
+ for (i = 0; i < (int)ARRAY_SIZE(_sm_update_map); ++i)
934
+ if (_sm_update_map[i].map_value == (int)update)
935
+ return _sm_update_map[i].str_match;
936
+ return NULL;
937
+ }
938
+
939
+ git_repository *git_submodule_owner(git_submodule *submodule)
940
+ {
941
+ assert(submodule);
942
+ return submodule->repo;
943
+ }
424
944
 
945
+ const char *git_submodule_name(git_submodule *submodule)
946
+ {
425
947
  assert(submodule);
948
+ return submodule->name;
949
+ }
426
950
 
427
- mods = open_gitmodules(submodule->owner, true, NULL);
428
- if (!mods) {
429
- giterr_set(GITERR_SUBMODULE,
430
- "Adding submodules to a bare repository is not supported (for now)");
431
- return -1;
432
- }
951
+ const char *git_submodule_path(git_submodule *submodule)
952
+ {
953
+ assert(submodule);
954
+ return submodule->path;
955
+ }
433
956
 
434
- if ((error = git_buf_printf(&key, "submodule.%s.", submodule->name)) < 0)
435
- goto cleanup;
957
+ const char *git_submodule_url(git_submodule *submodule)
958
+ {
959
+ assert(submodule);
960
+ return submodule->url;
961
+ }
962
+
963
+ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
964
+ {
965
+ int error = 0;
966
+ git_buf normalized = GIT_BUF_INIT;
436
967
 
437
- /* save values for path, url, update, ignore, fetchRecurseSubmodules */
968
+ assert(out && repo && url);
438
969
 
439
- if ((error = submodule_config_key_trunc_puts(&key, "path")) < 0 ||
440
- (error = git_config_file_set_string(mods, key.ptr, submodule->path)) < 0)
441
- goto cleanup;
970
+ git_buf_sanitize(out);
442
971
 
443
- if ((error = submodule_config_key_trunc_puts(&key, "url")) < 0 ||
444
- (error = git_config_file_set_string(mods, key.ptr, submodule->url)) < 0)
445
- goto cleanup;
972
+ /* We do this in all platforms in case someone on Windows created the .gitmodules */
973
+ if (strchr(url, '\\')) {
974
+ if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
975
+ return error;
446
976
 
447
- if (!(error = submodule_config_key_trunc_puts(&key, "update")) &&
448
- submodule->update != GIT_SUBMODULE_UPDATE_DEFAULT)
449
- {
450
- const char *val = (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
451
- NULL : _sm_update_map[submodule->update].str_match;
452
- error = git_config_file_set_string(mods, key.ptr, val);
977
+ url = normalized.ptr;
453
978
  }
454
- if (error < 0)
455
- goto cleanup;
456
979
 
457
- if (!(error = submodule_config_key_trunc_puts(&key, "ignore")) &&
458
- submodule->ignore != GIT_SUBMODULE_IGNORE_DEFAULT)
459
- {
460
- const char *val = (submodule->ignore == GIT_SUBMODULE_IGNORE_NONE) ?
461
- NULL : _sm_ignore_map[submodule->ignore].str_match;
462
- error = git_config_file_set_string(mods, key.ptr, val);
463
- }
464
- if (error < 0)
465
- goto cleanup;
466
980
 
467
- if ((error = submodule_config_key_trunc_puts(
468
- &key, "fetchRecurseSubmodules")) < 0 ||
469
- (error = git_config_file_set_string(
470
- mods, key.ptr, submodule->fetch_recurse ? "true" : "false")) < 0)
981
+ if (git_path_is_relative(url)) {
982
+ if (!(error = get_url_base(out, repo)))
983
+ error = git_path_apply_relative(out, url);
984
+ } else if (strchr(url, ':') != NULL || url[0] == '/') {
985
+ error = git_buf_sets(out, url);
986
+ } else {
987
+ git_error_set(GIT_ERROR_SUBMODULE, "invalid format for submodule URL");
988
+ error = -1;
989
+ }
990
+
991
+ git_buf_dispose(&normalized);
992
+ return error;
993
+ }
994
+
995
+ static int write_var(git_repository *repo, const char *name, const char *var, const char *val)
996
+ {
997
+ git_buf key = GIT_BUF_INIT;
998
+ git_config_backend *mods;
999
+ int error;
1000
+
1001
+ mods = open_gitmodules(repo, GITMODULES_CREATE);
1002
+ if (!mods)
1003
+ return -1;
1004
+
1005
+ if ((error = git_buf_printf(&key, "submodule.%s.%s", name, var)) < 0)
471
1006
  goto cleanup;
472
1007
 
473
- /* update internal defaults */
1008
+ if (val)
1009
+ error = git_config_backend_set_string(mods, key.ptr, val);
1010
+ else
1011
+ error = git_config_backend_delete(mods, key.ptr);
474
1012
 
475
- submodule->ignore_default = submodule->ignore;
476
- submodule->update_default = submodule->update;
477
- submodule->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1013
+ git_buf_dispose(&key);
478
1014
 
479
1015
  cleanup:
480
- if (mods != NULL)
481
- git_config_file_free(mods);
482
- git_buf_free(&key);
483
-
1016
+ git_config_backend_free(mods);
484
1017
  return error;
485
1018
  }
486
1019
 
487
- git_repository *git_submodule_owner(git_submodule *submodule)
1020
+ static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
488
1021
  {
489
- assert(submodule);
490
- return submodule->owner;
491
- }
1022
+ git_cvar_t type;
1023
+ const char *val;
492
1024
 
493
- const char *git_submodule_name(git_submodule *submodule)
494
- {
495
- assert(submodule);
496
- return submodule->name;
497
- }
1025
+ if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
1026
+ git_error_set(GIT_ERROR_SUBMODULE, "invalid value for %s", var);
1027
+ return -1;
1028
+ }
498
1029
 
499
- const char *git_submodule_path(git_submodule *submodule)
500
- {
501
- assert(submodule);
502
- return submodule->path;
1030
+ if (type == GIT_CVAR_TRUE)
1031
+ val = "true";
1032
+
1033
+ return write_var(repo, name, var, val);
503
1034
  }
504
1035
 
505
- const char *git_submodule_url(git_submodule *submodule)
1036
+ const char *git_submodule_branch(git_submodule *submodule)
506
1037
  {
507
1038
  assert(submodule);
508
- return submodule->url;
1039
+ return submodule->branch;
509
1040
  }
510
1041
 
511
- int git_submodule_set_url(git_submodule *submodule, const char *url)
1042
+ int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
512
1043
  {
513
- assert(submodule && url);
514
1044
 
515
- git__free(submodule->url);
1045
+ assert(repo && name);
516
1046
 
517
- submodule->url = git__strdup(url);
518
- GITERR_CHECK_ALLOC(submodule->url);
1047
+ return write_var(repo, name, "branch", branch);
1048
+ }
519
1049
 
520
- return 0;
1050
+ int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
1051
+ {
1052
+ assert(repo && name && url);
1053
+
1054
+ return write_var(repo, name, "url", url);
521
1055
  }
522
1056
 
523
1057
  const git_oid *git_submodule_index_id(git_submodule *submodule)
@@ -544,14 +1078,15 @@ const git_oid *git_submodule_wd_id(git_submodule *submodule)
544
1078
  {
545
1079
  assert(submodule);
546
1080
 
1081
+ /* load unless we think we have a valid oid */
547
1082
  if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
548
1083
  git_repository *subrepo;
549
1084
 
550
1085
  /* calling submodule open grabs the HEAD OID if possible */
551
- if (!git_submodule_open(&subrepo, submodule))
1086
+ if (!git_submodule_open_bare(&subrepo, submodule))
552
1087
  git_repository_free(subrepo);
553
1088
  else
554
- giterr_clear();
1089
+ git_error_clear();
555
1090
  }
556
1091
 
557
1092
  if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)
@@ -563,551 +1098,906 @@ const git_oid *git_submodule_wd_id(git_submodule *submodule)
563
1098
  git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
564
1099
  {
565
1100
  assert(submodule);
566
- return submodule->ignore;
1101
+ return (submodule->ignore < GIT_SUBMODULE_IGNORE_NONE) ?
1102
+ GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
567
1103
  }
568
1104
 
569
- git_submodule_ignore_t git_submodule_set_ignore(
570
- git_submodule *submodule, git_submodule_ignore_t ignore)
1105
+ int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
571
1106
  {
572
- git_submodule_ignore_t old;
1107
+ assert(repo && name);
1108
+
1109
+ return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
1110
+ }
573
1111
 
1112
+ git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
1113
+ {
574
1114
  assert(submodule);
1115
+ return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1116
+ GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
1117
+ }
575
1118
 
576
- if (ignore == GIT_SUBMODULE_IGNORE_DEFAULT)
577
- ignore = submodule->ignore_default;
1119
+ int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
1120
+ {
1121
+ assert(repo && name);
578
1122
 
579
- old = submodule->ignore;
580
- submodule->ignore = ignore;
581
- return old;
1123
+ return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
582
1124
  }
583
1125
 
584
- git_submodule_update_t git_submodule_update(git_submodule *submodule)
1126
+ git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
1127
+ git_submodule *submodule)
585
1128
  {
586
1129
  assert(submodule);
587
- return submodule->update;
1130
+ return submodule->fetch_recurse;
588
1131
  }
589
1132
 
590
- git_submodule_update_t git_submodule_set_update(
591
- git_submodule *submodule, git_submodule_update_t update)
1133
+ int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
592
1134
  {
593
- git_submodule_update_t old;
1135
+ assert(repo && name);
594
1136
 
595
- assert(submodule);
1137
+ return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
1138
+ }
1139
+
1140
+ static int submodule_repo_create(
1141
+ git_repository **out,
1142
+ git_repository *parent_repo,
1143
+ const char *path)
1144
+ {
1145
+ int error = 0;
1146
+ git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
1147
+ git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
1148
+ git_repository *subrepo = NULL;
1149
+
1150
+ initopt.flags =
1151
+ GIT_REPOSITORY_INIT_MKPATH |
1152
+ GIT_REPOSITORY_INIT_NO_REINIT |
1153
+ GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
1154
+ GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
1155
+
1156
+ /* Workdir: path to sub-repo working directory */
1157
+ error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
1158
+ if (error < 0)
1159
+ goto cleanup;
1160
+
1161
+ initopt.workdir_path = workdir.ptr;
1162
+
1163
+ /**
1164
+ * Repodir: path to the sub-repo. sub-repo goes in:
1165
+ * <repo-dir>/modules/<name>/ with a gitlink in the
1166
+ * sub-repo workdir directory to that repository.
1167
+ */
1168
+ error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
1169
+ if (error < 0)
1170
+ goto cleanup;
1171
+ error = git_buf_joinpath(&repodir, repodir.ptr, path);
1172
+ if (error < 0)
1173
+ goto cleanup;
1174
+
1175
+ error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
1176
+
1177
+ cleanup:
1178
+ git_buf_dispose(&workdir);
1179
+ git_buf_dispose(&repodir);
596
1180
 
597
- if (update == GIT_SUBMODULE_UPDATE_DEFAULT)
598
- update = submodule->update_default;
1181
+ *out = subrepo;
599
1182
 
600
- old = submodule->update;
601
- submodule->update = update;
602
- return old;
1183
+ return error;
603
1184
  }
604
1185
 
605
- int git_submodule_fetch_recurse_submodules(
606
- git_submodule *submodule)
1186
+ /**
1187
+ * Callback to override sub-repository creation when
1188
+ * cloning a sub-repository.
1189
+ */
1190
+ static int git_submodule_update_repo_init_cb(
1191
+ git_repository **out,
1192
+ const char *path,
1193
+ int bare,
1194
+ void *payload)
607
1195
  {
608
- assert(submodule);
609
- return submodule->fetch_recurse;
1196
+ git_submodule *sm;
1197
+
1198
+ GIT_UNUSED(bare);
1199
+
1200
+ sm = payload;
1201
+
1202
+ return submodule_repo_create(out, sm->repo, path);
1203
+ }
1204
+
1205
+ int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
1206
+ {
1207
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1208
+ opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
1209
+ return 0;
610
1210
  }
611
1211
 
612
- int git_submodule_set_fetch_recurse_submodules(
613
- git_submodule *submodule,
614
- int fetch_recurse_submodules)
1212
+ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
615
1213
  {
616
- int old;
1214
+ int error;
1215
+ unsigned int submodule_status;
1216
+ git_config *config = NULL;
1217
+ const char *submodule_url;
1218
+ git_repository *sub_repo = NULL;
1219
+ git_remote *remote = NULL;
1220
+ git_object *target_commit = NULL;
1221
+ git_buf buf = GIT_BUF_INIT;
1222
+ git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
1223
+ git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
617
1224
 
618
- assert(submodule);
1225
+ assert(sm);
1226
+
1227
+ if (_update_options)
1228
+ memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
1229
+
1230
+ GIT_ERROR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
1231
+
1232
+ /* Copy over the remote callbacks */
1233
+ memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
1234
+
1235
+ /* Get the status of the submodule to determine if it is already initialized */
1236
+ if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
1237
+ goto done;
1238
+
1239
+ /*
1240
+ * If submodule work dir is not already initialized, check to see
1241
+ * what we need to do (initialize, clone, return error...)
1242
+ */
1243
+ if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
1244
+ /*
1245
+ * Work dir is not initialized, check to see if the submodule
1246
+ * info has been copied into .git/config
1247
+ */
1248
+ if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
1249
+ (error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
1250
+ goto done;
1251
+
1252
+ if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
1253
+ /*
1254
+ * If the error is not "not found" or if it is "not found" and we are not
1255
+ * initializing the submodule, then return error.
1256
+ */
1257
+ if (error != GIT_ENOTFOUND)
1258
+ goto done;
1259
+
1260
+ if (!init) {
1261
+ git_error_set(GIT_ERROR_SUBMODULE, "submodule is not initialized");
1262
+ error = GIT_ERROR;
1263
+ goto done;
1264
+ }
1265
+
1266
+ /* The submodule has not been initialized yet - initialize it now.*/
1267
+ if ((error = git_submodule_init(sm, 0)) < 0)
1268
+ goto done;
1269
+
1270
+ git_config_free(config);
1271
+ config = NULL;
1272
+
1273
+ if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
1274
+ (error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
1275
+ goto done;
1276
+ }
1277
+
1278
+ /** submodule is initialized - now clone it **/
1279
+ /* override repo creation */
1280
+ clone_options.repository_cb = git_submodule_update_repo_init_cb;
1281
+ clone_options.repository_cb_payload = sm;
1282
+
1283
+ /*
1284
+ * Do not perform checkout as part of clone, instead we
1285
+ * will checkout the specific commit manually.
1286
+ */
1287
+ clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
1288
+
1289
+ if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
1290
+ (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
1291
+ (error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
1292
+ goto done;
1293
+ } else {
1294
+ const git_oid *oid;
1295
+
1296
+ /**
1297
+ * Work dir is initialized - look up the commit in the parent repository's index,
1298
+ * update the workdir contents of the subrepository, and set the subrepository's
1299
+ * head to the new commit.
1300
+ */
1301
+ if ((error = git_submodule_open(&sub_repo, sm)) < 0)
1302
+ goto done;
1303
+
1304
+ if ((oid = git_submodule_index_id(sm)) == NULL) {
1305
+ git_error_set(GIT_ERROR_SUBMODULE, "could not get ID of submodule in index");
1306
+ error = -1;
1307
+ goto done;
1308
+ }
1309
+
1310
+ /* Look up the target commit in the submodule. */
1311
+ if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJECT_COMMIT)) < 0) {
1312
+ /* If it isn't found then fetch and try again. */
1313
+ if (error != GIT_ENOTFOUND || !update_options.allow_fetch ||
1314
+ (error = lookup_default_remote(&remote, sub_repo)) < 0 ||
1315
+ (error = git_remote_fetch(remote, NULL, &update_options.fetch_opts, NULL)) < 0 ||
1316
+ (error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJECT_COMMIT)) < 0)
1317
+ goto done;
1318
+ }
1319
+
1320
+ if ((error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
1321
+ (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
1322
+ goto done;
1323
+
1324
+ /* Invalidate the wd flags as the workdir has been updated. */
1325
+ sm->flags = sm->flags &
1326
+ ~(GIT_SUBMODULE_STATUS_IN_WD |
1327
+ GIT_SUBMODULE_STATUS__WD_OID_VALID |
1328
+ GIT_SUBMODULE_STATUS__WD_SCANNED);
1329
+ }
1330
+
1331
+ done:
1332
+ git_buf_dispose(&buf);
1333
+ git_config_free(config);
1334
+ git_object_free(target_commit);
1335
+ git_remote_free(remote);
1336
+ git_repository_free(sub_repo);
619
1337
 
620
- old = submodule->fetch_recurse;
621
- submodule->fetch_recurse = (fetch_recurse_submodules != 0);
622
- return old;
1338
+ return error;
623
1339
  }
624
1340
 
625
- int git_submodule_init(git_submodule *submodule, int overwrite)
1341
+ int git_submodule_init(git_submodule *sm, int overwrite)
626
1342
  {
627
1343
  int error;
1344
+ const char *val;
1345
+ git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
1346
+ git_config *cfg = NULL;
628
1347
 
629
- /* write "submodule.NAME.url" */
630
-
631
- if (!submodule->url) {
632
- giterr_set(GITERR_SUBMODULE,
633
- "No URL configured for submodule '%s'", submodule->name);
1348
+ if (!sm->url) {
1349
+ git_error_set(GIT_ERROR_SUBMODULE,
1350
+ "no URL configured for submodule '%s'", sm->name);
634
1351
  return -1;
635
1352
  }
636
1353
 
637
- error = submodule_update_config(
638
- submodule, "url", submodule->url, overwrite != 0, false);
639
- if (error < 0)
1354
+ if ((error = git_repository_config(&cfg, sm->repo)) < 0)
640
1355
  return error;
641
1356
 
1357
+ /* write "submodule.NAME.url" */
1358
+
1359
+ if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
1360
+ (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
1361
+ (error = git_config__update_entry(
1362
+ cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
1363
+ goto cleanup;
1364
+
642
1365
  /* write "submodule.NAME.update" if not default */
643
1366
 
644
- if (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT)
645
- error = submodule_update_config(
646
- submodule, "update", NULL, (overwrite != 0), false);
647
- else if (submodule->update != GIT_SUBMODULE_UPDATE_DEFAULT)
648
- error = submodule_update_config(
649
- submodule, "update",
650
- _sm_update_map[submodule->update].str_match,
651
- (overwrite != 0), false);
1367
+ val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1368
+ NULL : git_submodule_update_to_str(sm->update);
1369
+
1370
+ if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
1371
+ (error = git_config__update_entry(
1372
+ cfg, key.ptr, val, overwrite != 0, false)) < 0)
1373
+ goto cleanup;
1374
+
1375
+ /* success */
1376
+
1377
+ cleanup:
1378
+ git_config_free(cfg);
1379
+ git_buf_dispose(&key);
1380
+ git_buf_dispose(&effective_submodule_url);
652
1381
 
653
1382
  return error;
654
1383
  }
655
1384
 
656
- int git_submodule_sync(git_submodule *submodule)
1385
+ int git_submodule_sync(git_submodule *sm)
657
1386
  {
658
- if (!submodule->url) {
659
- giterr_set(GITERR_SUBMODULE,
660
- "No URL configured for submodule '%s'", submodule->name);
1387
+ int error = 0;
1388
+ git_config *cfg = NULL;
1389
+ git_buf key = GIT_BUF_INIT;
1390
+ git_repository *smrepo = NULL;
1391
+
1392
+ if (!sm->url) {
1393
+ git_error_set(GIT_ERROR_SUBMODULE,
1394
+ "no URL configured for submodule '%s'", sm->name);
661
1395
  return -1;
662
1396
  }
663
1397
 
664
1398
  /* copy URL over to config only if it already exists */
665
1399
 
666
- return submodule_update_config(
667
- submodule, "url", submodule->url, true, true);
1400
+ if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
1401
+ !(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
1402
+ error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
1403
+
1404
+ /* if submodule exists in the working directory, update remote url */
1405
+
1406
+ if (!error &&
1407
+ (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
1408
+ !(error = git_submodule_open(&smrepo, sm)))
1409
+ {
1410
+ git_buf remote_name = GIT_BUF_INIT;
1411
+
1412
+ if ((error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
1413
+ /* return error from reading submodule config */;
1414
+ else if ((error = lookup_head_remote_key(&remote_name, smrepo)) < 0) {
1415
+ git_error_clear();
1416
+ error = git_buf_sets(&key, "remote.origin.url");
1417
+ } else {
1418
+ error = git_buf_join3(
1419
+ &key, '.', "remote", remote_name.ptr, "url");
1420
+ git_buf_dispose(&remote_name);
1421
+ }
1422
+
1423
+ if (!error)
1424
+ error = git_config__update_entry(cfg, key.ptr, sm->url, true, false);
1425
+
1426
+ git_repository_free(smrepo);
1427
+ }
1428
+
1429
+ git_buf_dispose(&key);
1430
+
1431
+ return error;
668
1432
  }
669
1433
 
670
- int git_submodule_open(
671
- git_repository **subrepo,
672
- git_submodule *submodule)
1434
+ static int git_submodule__open(
1435
+ git_repository **subrepo, git_submodule *sm, bool bare)
673
1436
  {
674
1437
  int error;
675
1438
  git_buf path = GIT_BUF_INIT;
676
- git_repository *repo;
677
- const char *workdir;
678
-
679
- assert(submodule && subrepo);
1439
+ unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
1440
+ const char *wd;
680
1441
 
681
- repo = submodule->owner;
682
- workdir = git_repository_workdir(repo);
1442
+ assert(sm && subrepo);
683
1443
 
684
- if (!workdir) {
685
- giterr_set(GITERR_REPOSITORY,
686
- "Cannot open submodule repository in a bare repo");
687
- return GIT_ENOTFOUND;
688
- }
1444
+ if (git_repository__ensure_not_bare(
1445
+ sm->repo, "open submodule repository") < 0)
1446
+ return GIT_EBAREREPO;
689
1447
 
690
- if ((submodule->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0) {
691
- giterr_set(GITERR_REPOSITORY,
692
- "Cannot open submodule repository that is not checked out");
693
- return GIT_ENOTFOUND;
694
- }
1448
+ wd = git_repository_workdir(sm->repo);
695
1449
 
696
- if (git_buf_joinpath(&path, workdir, submodule->path) < 0)
1450
+ if (git_buf_joinpath(&path, wd, sm->path) < 0 ||
1451
+ git_buf_joinpath(&path, path.ptr, DOT_GIT) < 0)
697
1452
  return -1;
698
1453
 
699
- error = git_repository_open(subrepo, path.ptr);
1454
+ sm->flags = sm->flags &
1455
+ ~(GIT_SUBMODULE_STATUS_IN_WD |
1456
+ GIT_SUBMODULE_STATUS__WD_OID_VALID |
1457
+ GIT_SUBMODULE_STATUS__WD_SCANNED);
700
1458
 
701
- git_buf_free(&path);
1459
+ if (bare)
1460
+ flags |= GIT_REPOSITORY_OPEN_BARE;
702
1461
 
703
- /* if we have opened the submodule successfully, let's grab the HEAD OID */
1462
+ error = git_repository_open_ext(subrepo, path.ptr, flags, wd);
1463
+
1464
+ /* if we opened the submodule successfully, grab HEAD OID, etc. */
704
1465
  if (!error) {
705
- if (!git_reference_name_to_id(
706
- &submodule->wd_oid, *subrepo, GIT_HEAD_FILE))
707
- submodule->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
1466
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_WD |
1467
+ GIT_SUBMODULE_STATUS__WD_SCANNED;
1468
+
1469
+ if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
1470
+ sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
708
1471
  else
709
- giterr_clear();
1472
+ git_error_clear();
1473
+ } else if (git_path_exists(path.ptr)) {
1474
+ sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
1475
+ GIT_SUBMODULE_STATUS_IN_WD;
1476
+ } else {
1477
+ git_buf_rtruncate_at_char(&path, '/'); /* remove "/.git" */
1478
+
1479
+ if (git_path_isdir(path.ptr))
1480
+ sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
710
1481
  }
711
1482
 
1483
+ git_buf_dispose(&path);
1484
+
712
1485
  return error;
713
1486
  }
714
1487
 
715
- int git_submodule_reload_all(git_repository *repo)
1488
+ int git_submodule_open_bare(git_repository **subrepo, git_submodule *sm)
716
1489
  {
717
- assert(repo);
718
- git_submodule_config_free(repo);
719
- return load_submodule_config(repo);
1490
+ return git_submodule__open(subrepo, sm, true);
720
1491
  }
721
1492
 
722
- int git_submodule_reload(git_submodule *submodule)
1493
+ int git_submodule_open(git_repository **subrepo, git_submodule *sm)
723
1494
  {
724
- git_repository *repo;
725
- git_index *index;
726
- int error;
727
- size_t pos;
728
- git_tree *head;
729
- git_config_backend *mods;
1495
+ return git_submodule__open(subrepo, sm, false);
1496
+ }
730
1497
 
731
- assert(submodule);
1498
+ static void submodule_update_from_index_entry(
1499
+ git_submodule *sm, const git_index_entry *ie)
1500
+ {
1501
+ bool already_found = (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) != 0;
1502
+
1503
+ if (!S_ISGITLINK(ie->mode)) {
1504
+ if (!already_found)
1505
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
1506
+ } else {
1507
+ if (already_found)
1508
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
1509
+ else
1510
+ git_oid_cpy(&sm->index_oid, &ie->id);
1511
+
1512
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX |
1513
+ GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
1514
+ }
1515
+ }
732
1516
 
733
- /* refresh index data */
1517
+ static int submodule_update_index(git_submodule *sm)
1518
+ {
1519
+ git_index *index;
1520
+ const git_index_entry *ie;
734
1521
 
735
- repo = submodule->owner;
736
- if (git_repository_index__weakptr(&index, repo) < 0)
1522
+ if (git_repository_index__weakptr(&index, sm->repo) < 0)
737
1523
  return -1;
738
1524
 
739
- submodule->flags = submodule->flags &
1525
+ sm->flags = sm->flags &
740
1526
  ~(GIT_SUBMODULE_STATUS_IN_INDEX |
741
1527
  GIT_SUBMODULE_STATUS__INDEX_OID_VALID);
742
1528
 
743
- if (!git_index_find(&pos, index, submodule->path)) {
744
- const git_index_entry *entry = git_index_get_byindex(index, pos);
1529
+ if (!(ie = git_index_get_bypath(index, sm->path, 0)))
1530
+ return 0;
745
1531
 
746
- if (S_ISGITLINK(entry->mode)) {
747
- if ((error = submodule_load_from_index(repo, entry)) < 0)
748
- return error;
749
- } else {
750
- submodule_mode_mismatch(
751
- repo, entry->path, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE);
752
- }
1532
+ submodule_update_from_index_entry(sm, ie);
1533
+
1534
+ return 0;
1535
+ }
1536
+
1537
+ static void submodule_update_from_head_data(
1538
+ git_submodule *sm, mode_t mode, const git_oid *id)
1539
+ {
1540
+ if (!S_ISGITLINK(mode))
1541
+ sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
1542
+ else {
1543
+ git_oid_cpy(&sm->head_oid, id);
1544
+
1545
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD |
1546
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
753
1547
  }
1548
+ }
754
1549
 
755
- /* refresh HEAD tree data */
1550
+ static int submodule_update_head(git_submodule *submodule)
1551
+ {
1552
+ git_tree *head = NULL;
1553
+ git_tree_entry *te = NULL;
756
1554
 
757
- if (!(error = git_repository_head_tree(&head, repo))) {
758
- git_tree_entry *te;
1555
+ submodule->flags = submodule->flags &
1556
+ ~(GIT_SUBMODULE_STATUS_IN_HEAD |
1557
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
759
1558
 
760
- submodule->flags = submodule->flags &
761
- ~(GIT_SUBMODULE_STATUS_IN_HEAD |
762
- GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
1559
+ /* if we can't look up file in current head, then done */
1560
+ if (git_repository_head_tree(&head, submodule->repo) < 0 ||
1561
+ git_tree_entry_bypath(&te, head, submodule->path) < 0)
1562
+ git_error_clear();
1563
+ else
1564
+ submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te));
763
1565
 
764
- if (!(error = git_tree_entry_bypath(&te, head, submodule->path))) {
1566
+ git_tree_entry_free(te);
1567
+ git_tree_free(head);
1568
+ return 0;
1569
+ }
765
1570
 
766
- if (S_ISGITLINK(te->attr)) {
767
- error = submodule_load_from_head(repo, submodule->path, &te->oid);
768
- } else {
769
- submodule_mode_mismatch(
770
- repo, submodule->path,
771
- GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE);
772
- }
1571
+ int git_submodule_reload(git_submodule *sm, int force)
1572
+ {
1573
+ int error = 0, isvalid;
1574
+ git_config *mods;
773
1575
 
774
- git_tree_entry_free(te);
775
- }
776
- else if (error == GIT_ENOTFOUND) {
777
- giterr_clear();
778
- error = 0;
779
- }
1576
+ GIT_UNUSED(force);
1577
+
1578
+ assert(sm);
780
1579
 
781
- git_tree_free(head);
1580
+ isvalid = git_submodule_name_is_valid(sm->repo, sm->name, 0);
1581
+ if (isvalid <= 0) {
1582
+ /* This should come with a warning, but we've no API for that */
1583
+ return isvalid;
782
1584
  }
783
1585
 
784
- if (error < 0)
785
- return error;
1586
+ if (!git_repository_is_bare(sm->repo)) {
1587
+ /* refresh config data */
1588
+ if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
1589
+ return error;
1590
+ if (mods != NULL) {
1591
+ error = submodule_read_config(sm, mods);
1592
+ git_config_free(mods);
786
1593
 
787
- /* refresh config data */
1594
+ if (error < 0)
1595
+ return error;
1596
+ }
788
1597
 
789
- if ((mods = open_gitmodules(repo, false, NULL)) != NULL) {
790
- git_buf path = GIT_BUF_INIT;
1598
+ /* refresh wd data */
1599
+ sm->flags &=
1600
+ ~(GIT_SUBMODULE_STATUS_IN_WD |
1601
+ GIT_SUBMODULE_STATUS__WD_OID_VALID |
1602
+ GIT_SUBMODULE_STATUS__WD_FLAGS);
791
1603
 
792
- git_buf_sets(&path, "submodule\\.");
793
- git_buf_text_puts_escape_regex(&path, submodule->name);
794
- git_buf_puts(&path, ".*");
1604
+ error = submodule_load_from_wd_lite(sm);
1605
+ }
795
1606
 
796
- if (git_buf_oom(&path))
797
- error = -1;
1607
+ if (error == 0 && (error = submodule_update_index(sm)) == 0)
1608
+ error = submodule_update_head(sm);
1609
+
1610
+ return error;
1611
+ }
1612
+
1613
+ static void submodule_copy_oid_maybe(
1614
+ git_oid *tgt, const git_oid *src, bool valid)
1615
+ {
1616
+ if (tgt) {
1617
+ if (valid)
1618
+ memcpy(tgt, src, sizeof(*tgt));
798
1619
  else
799
- error = git_config_file_foreach_match(
800
- mods, path.ptr, submodule_load_from_config, repo);
1620
+ memset(tgt, 0, sizeof(*tgt));
1621
+ }
1622
+ }
1623
+
1624
+ int git_submodule__status(
1625
+ unsigned int *out_status,
1626
+ git_oid *out_head_id,
1627
+ git_oid *out_index_id,
1628
+ git_oid *out_wd_id,
1629
+ git_submodule *sm,
1630
+ git_submodule_ignore_t ign)
1631
+ {
1632
+ unsigned int status;
1633
+ git_repository *smrepo = NULL;
1634
+
1635
+ if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1636
+ ign = sm->ignore;
801
1637
 
802
- git_buf_free(&path);
803
- git_config_file_free(mods);
1638
+ /* only return location info if ignore == all */
1639
+ if (ign == GIT_SUBMODULE_IGNORE_ALL) {
1640
+ *out_status = (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS);
1641
+ return 0;
804
1642
  }
805
1643
 
806
- if (error < 0)
807
- return error;
1644
+ /* If the user has requested caching submodule state, performing these
1645
+ * expensive operations (especially `submodule_update_head`, which is
1646
+ * bottlenecked on `git_repository_head_tree`) eliminates much of the
1647
+ * advantage. We will, therefore, interpret the request for caching to
1648
+ * apply here to and skip them.
1649
+ */
808
1650
 
809
- /* refresh wd data */
1651
+ if (sm->repo->submodule_cache == NULL) {
1652
+ /* refresh the index OID */
1653
+ if (submodule_update_index(sm) < 0)
1654
+ return -1;
810
1655
 
811
- submodule->flags = submodule->flags &
812
- ~(GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_OID_VALID);
1656
+ /* refresh the HEAD OID */
1657
+ if (submodule_update_head(sm) < 0)
1658
+ return -1;
1659
+ }
813
1660
 
814
- error = submodule_load_from_wd_lite(submodule, submodule->path, NULL);
1661
+ /* for ignore == dirty, don't scan the working directory */
1662
+ if (ign == GIT_SUBMODULE_IGNORE_DIRTY) {
1663
+ /* git_submodule_open_bare will load WD OID data */
1664
+ if (git_submodule_open_bare(&smrepo, sm) < 0)
1665
+ git_error_clear();
1666
+ else
1667
+ git_repository_free(smrepo);
1668
+ smrepo = NULL;
1669
+ } else if (git_submodule_open(&smrepo, sm) < 0) {
1670
+ git_error_clear();
1671
+ smrepo = NULL;
1672
+ }
815
1673
 
816
- return error;
1674
+ status = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm->flags);
1675
+
1676
+ submodule_get_index_status(&status, sm);
1677
+ submodule_get_wd_status(&status, sm, smrepo, ign);
1678
+
1679
+ git_repository_free(smrepo);
1680
+
1681
+ *out_status = status;
1682
+
1683
+ submodule_copy_oid_maybe(out_head_id, &sm->head_oid,
1684
+ (sm->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID) != 0);
1685
+ submodule_copy_oid_maybe(out_index_id, &sm->index_oid,
1686
+ (sm->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID) != 0);
1687
+ submodule_copy_oid_maybe(out_wd_id, &sm->wd_oid,
1688
+ (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) != 0);
1689
+
1690
+ return 0;
817
1691
  }
818
1692
 
819
- int git_submodule_status(
820
- unsigned int *status,
821
- git_submodule *submodule)
1693
+ int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
822
1694
  {
823
- int error = 0;
824
- unsigned int status_val;
825
-
826
- assert(status && submodule);
1695
+ git_submodule *sm;
1696
+ int error;
827
1697
 
828
- status_val = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(submodule->flags);
1698
+ assert(status && repo && name);
829
1699
 
830
- if (submodule->ignore != GIT_SUBMODULE_IGNORE_ALL) {
831
- if (!(error = submodule_index_status(&status_val, submodule)))
832
- error = submodule_wd_status(&status_val, submodule);
833
- }
1700
+ if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
1701
+ return error;
834
1702
 
835
- *status = status_val;
1703
+ error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
1704
+ git_submodule_free(sm);
836
1705
 
837
1706
  return error;
838
1707
  }
839
1708
 
840
- int git_submodule_location(
841
- unsigned int *location_status,
842
- git_submodule *submodule)
1709
+ int git_submodule_location(unsigned int *location, git_submodule *sm)
843
1710
  {
844
- assert(location_status && submodule);
1711
+ assert(location && sm);
845
1712
 
846
- *location_status = submodule->flags &
847
- (GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX |
848
- GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD);
849
-
850
- return 0;
1713
+ return git_submodule__status(
1714
+ location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
851
1715
  }
852
1716
 
853
-
854
1717
  /*
855
1718
  * INTERNAL FUNCTIONS
856
1719
  */
857
1720
 
858
- static git_submodule *submodule_alloc(git_repository *repo, const char *name)
1721
+ static int submodule_alloc(
1722
+ git_submodule **out, git_repository *repo, const char *name)
859
1723
  {
1724
+ size_t namelen;
860
1725
  git_submodule *sm;
861
1726
 
862
- if (!name || !strlen(name)) {
863
- giterr_set(GITERR_SUBMODULE, "Invalid submodule name");
864
- return NULL;
1727
+ if (!name || !(namelen = strlen(name))) {
1728
+ git_error_set(GIT_ERROR_SUBMODULE, "invalid submodule name");
1729
+ return -1;
865
1730
  }
866
1731
 
867
1732
  sm = git__calloc(1, sizeof(git_submodule));
868
- if (sm == NULL)
869
- goto fail;
1733
+ GIT_ERROR_CHECK_ALLOC(sm);
1734
+
1735
+ sm->name = sm->path = git__strdup(name);
1736
+ if (!sm->name) {
1737
+ git__free(sm);
1738
+ return -1;
1739
+ }
1740
+
1741
+ GIT_REFCOUNT_INC(sm);
1742
+ sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
1743
+ sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
1744
+ sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
1745
+ sm->repo = repo;
1746
+ sm->branch = NULL;
870
1747
 
871
- sm->path = sm->name = git__strdup(name);
872
- if (!sm->name)
873
- goto fail;
1748
+ *out = sm;
1749
+ return 0;
1750
+ }
874
1751
 
875
- sm->owner = repo;
876
- sm->refcount = 1;
1752
+ static void submodule_release(git_submodule *sm)
1753
+ {
1754
+ if (!sm)
1755
+ return;
877
1756
 
878
- return sm;
1757
+ if (sm->repo) {
1758
+ sm->repo = NULL;
1759
+ }
879
1760
 
880
- fail:
881
- submodule_release(sm, 0);
882
- return NULL;
1761
+ if (sm->path != sm->name)
1762
+ git__free(sm->path);
1763
+ git__free(sm->name);
1764
+ git__free(sm->url);
1765
+ git__free(sm->branch);
1766
+ git__memzero(sm, sizeof(*sm));
1767
+ git__free(sm);
883
1768
  }
884
1769
 
885
- static void submodule_release(git_submodule *sm, int decr)
1770
+ void git_submodule_free(git_submodule *sm)
886
1771
  {
887
1772
  if (!sm)
888
1773
  return;
1774
+ GIT_REFCOUNT_DEC(sm, submodule_release);
1775
+ }
889
1776
 
890
- sm->refcount -= decr;
1777
+ static int submodule_config_error(const char *property, const char *value)
1778
+ {
1779
+ git_error_set(GIT_ERROR_INVALID,
1780
+ "invalid value for submodule '%s' property: '%s'", property, value);
1781
+ return -1;
1782
+ }
891
1783
 
892
- if (sm->refcount == 0) {
893
- if (sm->name != sm->path) {
894
- git__free(sm->path);
895
- sm->path = NULL;
896
- }
1784
+ int git_submodule_parse_ignore(git_submodule_ignore_t *out, const char *value)
1785
+ {
1786
+ int val;
897
1787
 
898
- git__free(sm->name);
899
- sm->name = NULL;
1788
+ if (git_config_lookup_map_value(
1789
+ &val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0) {
1790
+ *out = GIT_SUBMODULE_IGNORE_NONE;
1791
+ return submodule_config_error("ignore", value);
1792
+ }
900
1793
 
901
- git__free(sm->url);
902
- sm->url = NULL;
1794
+ *out = (git_submodule_ignore_t)val;
1795
+ return 0;
1796
+ }
903
1797
 
904
- sm->owner = NULL;
1798
+ int git_submodule_parse_update(git_submodule_update_t *out, const char *value)
1799
+ {
1800
+ int val;
905
1801
 
906
- git__free(sm);
1802
+ if (git_config_lookup_map_value(
1803
+ &val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0) {
1804
+ *out = GIT_SUBMODULE_UPDATE_CHECKOUT;
1805
+ return submodule_config_error("update", value);
907
1806
  }
1807
+
1808
+ *out = (git_submodule_update_t)val;
1809
+ return 0;
908
1810
  }
909
1811
 
910
- static int submodule_get(
911
- git_submodule **sm_ptr,
912
- git_repository *repo,
913
- const char *name,
914
- const char *alternate)
1812
+ int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
915
1813
  {
916
- git_strmap *smcfg = repo->submodules;
917
- khiter_t pos;
918
- git_submodule *sm;
919
- int error;
1814
+ int val;
920
1815
 
921
- assert(repo && name);
1816
+ if (git_config_lookup_map_value(
1817
+ &val, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), value) < 0) {
1818
+ *out = GIT_SUBMODULE_RECURSE_YES;
1819
+ return submodule_config_error("recurse", value);
1820
+ }
922
1821
 
923
- pos = git_strmap_lookup_index(smcfg, name);
1822
+ *out = (git_submodule_recurse_t)val;
1823
+ return 0;
1824
+ }
924
1825
 
925
- if (!git_strmap_valid_index(smcfg, pos) && alternate)
926
- pos = git_strmap_lookup_index(smcfg, alternate);
1826
+ static int get_value(const char **out, git_config *cfg, git_buf *buf, const char *name, const char *field)
1827
+ {
1828
+ int error;
927
1829
 
928
- if (!git_strmap_valid_index(smcfg, pos)) {
929
- sm = submodule_alloc(repo, name);
1830
+ git_buf_clear(buf);
930
1831
 
931
- /* insert value at name - if another thread beats us to it, then use
932
- * their record and release our own.
933
- */
934
- pos = kh_put(str, smcfg, sm->name, &error);
1832
+ if ((error = git_buf_printf(buf, "submodule.%s.%s", name, field)) < 0 ||
1833
+ (error = git_config_get_string(out, cfg, buf->ptr)) < 0)
1834
+ return error;
935
1835
 
936
- if (error < 0) {
937
- submodule_release(sm, 1);
938
- sm = NULL;
939
- } else if (error == 0) {
940
- submodule_release(sm, 1);
941
- sm = git_strmap_value_at(smcfg, pos);
942
- } else {
943
- git_strmap_set_value_at(smcfg, pos, sm);
944
- }
945
- } else {
946
- sm = git_strmap_value_at(smcfg, pos);
947
- }
1836
+ return error;
1837
+ }
948
1838
 
949
- *sm_ptr = sm;
1839
+ static bool looks_like_command_line_option(const char *s)
1840
+ {
1841
+ if (s && s[0] == '-')
1842
+ return true;
950
1843
 
951
- return (sm != NULL) ? 0 : -1;
1844
+ return false;
952
1845
  }
953
1846
 
954
- static int submodule_load_from_index(
955
- git_repository *repo, const git_index_entry *entry)
1847
+ static int submodule_read_config(git_submodule *sm, git_config *cfg)
956
1848
  {
957
- git_submodule *sm;
1849
+ git_buf key = GIT_BUF_INIT;
1850
+ const char *value;
1851
+ int error, in_config = 0;
958
1852
 
959
- if (submodule_get(&sm, repo, entry->path, NULL) < 0)
960
- return -1;
1853
+ /*
1854
+ * TODO: Look up path in index and if it is present but not a GITLINK
1855
+ * then this should be deleted (at least to match git's behavior)
1856
+ */
961
1857
 
962
- if (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) {
963
- sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
964
- return 0;
965
- }
1858
+ if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
1859
+ in_config = 1;
1860
+ /* We would warn here if we had that API */
1861
+ if (!looks_like_command_line_option(value)) {
1862
+ /*
1863
+ * TODO: if case insensitive filesystem, then the following strcmp
1864
+ * should be strcasecmp
1865
+ */
1866
+ if (strcmp(sm->name, value) != 0) {
1867
+ if (sm->path != sm->name)
1868
+ git__free(sm->path);
1869
+ sm->path = git__strdup(value);
1870
+ GIT_ERROR_CHECK_ALLOC(sm->path);
1871
+ }
966
1872
 
967
- sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX;
1873
+ }
1874
+ } else if (error != GIT_ENOTFOUND) {
1875
+ goto cleanup;
1876
+ }
968
1877
 
969
- git_oid_cpy(&sm->index_oid, &entry->oid);
970
- sm->flags |= GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
1878
+ if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
1879
+ /* We would warn here if we had that API */
1880
+ if (!looks_like_command_line_option(value)) {
1881
+ in_config = 1;
1882
+ sm->url = git__strdup(value);
1883
+ GIT_ERROR_CHECK_ALLOC(sm->url);
1884
+ }
1885
+ } else if (error != GIT_ENOTFOUND) {
1886
+ goto cleanup;
1887
+ }
971
1888
 
972
- return 0;
973
- }
1889
+ if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
1890
+ in_config = 1;
1891
+ sm->branch = git__strdup(value);
1892
+ GIT_ERROR_CHECK_ALLOC(sm->branch);
1893
+ } else if (error != GIT_ENOTFOUND) {
1894
+ goto cleanup;
1895
+ }
974
1896
 
975
- static int submodule_load_from_head(
976
- git_repository *repo, const char *path, const git_oid *oid)
977
- {
978
- git_submodule *sm;
1897
+ if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
1898
+ in_config = 1;
1899
+ if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
1900
+ goto cleanup;
1901
+ sm->update_default = sm->update;
1902
+ } else if (error != GIT_ENOTFOUND) {
1903
+ goto cleanup;
1904
+ }
979
1905
 
980
- if (submodule_get(&sm, repo, path, NULL) < 0)
981
- return -1;
1906
+ if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
1907
+ in_config = 1;
1908
+ if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
1909
+ goto cleanup;
1910
+ sm->fetch_recurse_default = sm->fetch_recurse;
1911
+ } else if (error != GIT_ENOTFOUND) {
1912
+ goto cleanup;
1913
+ }
982
1914
 
983
- sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD;
1915
+ if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
1916
+ in_config = 1;
1917
+ if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
1918
+ goto cleanup;
1919
+ sm->ignore_default = sm->ignore;
1920
+ } else if (error != GIT_ENOTFOUND) {
1921
+ goto cleanup;
1922
+ }
984
1923
 
985
- git_oid_cpy(&sm->head_oid, oid);
986
- sm->flags |= GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
1924
+ if (in_config)
1925
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
987
1926
 
988
- return 0;
989
- }
1927
+ error = 0;
990
1928
 
991
- static int submodule_config_error(const char *property, const char *value)
992
- {
993
- giterr_set(GITERR_INVALID,
994
- "Invalid value for submodule '%s' property: '%s'", property, value);
995
- return -1;
1929
+ cleanup:
1930
+ git_buf_dispose(&key);
1931
+ return error;
996
1932
  }
997
1933
 
998
- static int submodule_load_from_config(
999
- const git_config_entry *entry, void *data)
1934
+ static int submodule_load_each(const git_config_entry *entry, void *payload)
1000
1935
  {
1001
- git_repository *repo = data;
1002
- git_strmap *smcfg = repo->submodules;
1003
- const char *namestart, *property, *alternate = NULL;
1004
- const char *key = entry->name, *value = entry->value;
1936
+ lfc_data *data = payload;
1937
+ const char *namestart, *property;
1938
+ size_t pos;
1939
+ git_strmap *map = data->map;
1005
1940
  git_buf name = GIT_BUF_INIT;
1006
1941
  git_submodule *sm;
1007
- bool is_path;
1008
- int error = 0;
1942
+ int error, isvalid;
1009
1943
 
1010
- if (git__prefixcmp(key, "submodule.") != 0)
1944
+ if (git__prefixcmp(entry->name, "submodule.") != 0)
1011
1945
  return 0;
1012
1946
 
1013
- namestart = key + strlen("submodule.");
1947
+ namestart = entry->name + strlen("submodule.");
1014
1948
  property = strrchr(namestart, '.');
1015
- if (property == NULL)
1949
+
1950
+ if (!property || (property == namestart))
1016
1951
  return 0;
1952
+
1017
1953
  property++;
1018
- is_path = (strcasecmp(property, "path") == 0);
1019
1954
 
1020
- if (git_buf_set(&name, namestart, property - namestart - 1) < 0)
1021
- return -1;
1955
+ if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
1956
+ return error;
1022
1957
 
1023
- if (submodule_get(&sm, repo, name.ptr, is_path ? value : NULL) < 0) {
1024
- git_buf_free(&name);
1025
- return -1;
1958
+ isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0);
1959
+ if (isvalid <= 0) {
1960
+ error = isvalid;
1961
+ goto done;
1026
1962
  }
1027
1963
 
1028
- sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1029
-
1030
- /* Only from config might we get differing names & paths. If so, then
1031
- * update the submodule and insert under the alternative key.
1032
- */
1033
-
1034
- /* TODO: if case insensitive filesystem, then the following strcmps
1035
- * should be strcasecmp
1964
+ /*
1965
+ * Now that we have the submodule's name, we can use that to
1966
+ * figure out whether it's in the map. If it's not, we create
1967
+ * a new submodule, load the config and insert it. If it's
1968
+ * already inserted, we've already loaded it, so we skip.
1036
1969
  */
1037
-
1038
- if (strcmp(sm->name, name.ptr) != 0) {
1039
- alternate = sm->name = git_buf_detach(&name);
1040
- } else if (is_path && value && strcmp(sm->path, value) != 0) {
1041
- alternate = sm->path = git__strdup(value);
1042
- if (!sm->path)
1043
- error = -1;
1970
+ pos = git_strmap_lookup_index(map, name.ptr);
1971
+ if (git_strmap_valid_index(map, pos)) {
1972
+ error = 0;
1973
+ goto done;
1044
1974
  }
1045
- if (alternate) {
1046
- void *old_sm = NULL;
1047
- git_strmap_insert2(smcfg, alternate, sm, old_sm, error);
1048
1975
 
1049
- if (error >= 0)
1050
- sm->refcount++; /* inserted under a new key */
1976
+ if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
1977
+ goto done;
1051
1978
 
1052
- /* if we replaced an old module under this key, release the old one */
1053
- if (old_sm && ((git_submodule *)old_sm) != sm) {
1054
- submodule_release(old_sm, 1);
1055
- /* TODO: log warning about multiple submodules with same path */
1056
- }
1979
+ if ((error = submodule_read_config(sm, data->mods)) < 0) {
1980
+ git_submodule_free(sm);
1981
+ goto done;
1057
1982
  }
1058
1983
 
1059
- git_buf_free(&name);
1984
+ git_strmap_insert(map, sm->name, sm, &error);
1985
+ assert(error != 0);
1060
1986
  if (error < 0)
1061
- return error;
1062
-
1063
- /* TODO: Look up path in index and if it is present but not a GITLINK
1064
- * then this should be deleted (at least to match git's behavior)
1065
- */
1066
-
1067
- if (is_path)
1068
- return 0;
1987
+ goto done;
1069
1988
 
1070
- /* copy other properties into submodule entry */
1071
- if (strcasecmp(property, "url") == 0) {
1072
- git__free(sm->url);
1073
- sm->url = NULL;
1989
+ error = 0;
1074
1990
 
1075
- if (value != NULL && (sm->url = git__strdup(value)) == NULL)
1076
- return -1;
1077
- }
1078
- else if (strcasecmp(property, "update") == 0) {
1079
- int val;
1080
- if (git_config_lookup_map_value(
1081
- &val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0)
1082
- return submodule_config_error("update", value);
1083
- sm->update_default = sm->update = (git_submodule_update_t)val;
1084
- }
1085
- else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) {
1086
- if (git__parse_bool(&sm->fetch_recurse, value) < 0)
1087
- return submodule_config_error("fetchRecurseSubmodules", value);
1088
- }
1089
- else if (strcasecmp(property, "ignore") == 0) {
1090
- int val;
1091
- if (git_config_lookup_map_value(
1092
- &val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0)
1093
- return submodule_config_error("ignore", value);
1094
- sm->ignore_default = sm->ignore = (git_submodule_ignore_t)val;
1095
- }
1096
- /* ignore other unknown submodule properties */
1097
-
1098
- return 0;
1991
+ done:
1992
+ git_buf_dispose(&name);
1993
+ return error;
1099
1994
  }
1100
1995
 
1101
- static int submodule_load_from_wd_lite(
1102
- git_submodule *sm, const char *name, void *payload)
1996
+ static int submodule_load_from_wd_lite(git_submodule *sm)
1103
1997
  {
1104
- git_repository *repo = git_submodule_owner(sm);
1105
1998
  git_buf path = GIT_BUF_INIT;
1106
1999
 
1107
- GIT_UNUSED(name);
1108
- GIT_UNUSED(payload);
1109
-
1110
- if (git_buf_joinpath(&path, git_repository_workdir(repo), sm->path) < 0)
2000
+ if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
1111
2001
  return -1;
1112
2002
 
1113
2003
  if (git_path_isdir(path.ptr))
@@ -1116,106 +2006,48 @@ static int submodule_load_from_wd_lite(
1116
2006
  if (git_path_contains(&path, DOT_GIT))
1117
2007
  sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
1118
2008
 
1119
- git_buf_free(&path);
1120
-
2009
+ git_buf_dispose(&path);
1121
2010
  return 0;
1122
2011
  }
1123
2012
 
1124
- static void submodule_mode_mismatch(
1125
- git_repository *repo, const char *path, unsigned int flag)
1126
- {
1127
- khiter_t pos = git_strmap_lookup_index(repo->submodules, path);
1128
-
1129
- if (git_strmap_valid_index(repo->submodules, pos)) {
1130
- git_submodule *sm = git_strmap_value_at(repo->submodules, pos);
1131
-
1132
- sm->flags |= flag;
1133
- }
1134
- }
1135
-
1136
- static int load_submodule_config_from_index(
1137
- git_repository *repo, git_oid *gitmodules_oid)
1138
- {
1139
- int error;
1140
- git_index *index;
1141
- git_iterator *i;
1142
- const git_index_entry *entry;
1143
-
1144
- if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
1145
- (error = git_iterator_for_index(&i, index, 0, NULL, NULL)) < 0)
1146
- return error;
1147
-
1148
- while (!(error = git_iterator_advance(&entry, i))) {
1149
-
1150
- if (S_ISGITLINK(entry->mode)) {
1151
- error = submodule_load_from_index(repo, entry);
1152
- if (error < 0)
1153
- break;
1154
- } else {
1155
- submodule_mode_mismatch(
1156
- repo, entry->path, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE);
1157
-
1158
- if (strcmp(entry->path, GIT_MODULES_FILE) == 0)
1159
- git_oid_cpy(gitmodules_oid, &entry->oid);
1160
- }
1161
- }
1162
-
1163
- if (error == GIT_ITEROVER)
1164
- error = 0;
1165
-
1166
- git_iterator_free(i);
1167
-
1168
- return error;
1169
- }
1170
-
1171
- static int load_submodule_config_from_head(
1172
- git_repository *repo, git_oid *gitmodules_oid)
2013
+ /**
2014
+ * Requests a snapshot of $WORK_TREE/.gitmodules.
2015
+ *
2016
+ * Returns GIT_ENOTFOUND in case no .gitmodules file exist
2017
+ */
2018
+ static int gitmodules_snapshot(git_config **snap, git_repository *repo)
1173
2019
  {
2020
+ const char *workdir = git_repository_workdir(repo);
2021
+ git_config *mods = NULL;
2022
+ git_buf path = GIT_BUF_INIT;
1174
2023
  int error;
1175
- git_tree *head;
1176
- git_iterator *i;
1177
- const git_index_entry *entry;
1178
2024
 
1179
- /* if we can't look up current head, then there's no submodule in it */
1180
- if (git_repository_head_tree(&head, repo) < 0) {
1181
- giterr_clear();
1182
- return 0;
1183
- }
2025
+ if (!workdir)
2026
+ return GIT_ENOTFOUND;
1184
2027
 
1185
- if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0) {
1186
- git_tree_free(head);
2028
+ if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0)
1187
2029
  return error;
1188
- }
1189
-
1190
- while (!(error = git_iterator_advance(&entry, i))) {
1191
2030
 
1192
- if (S_ISGITLINK(entry->mode)) {
1193
- error = submodule_load_from_head(repo, entry->path, &entry->oid);
1194
- if (error < 0)
1195
- break;
1196
- } else {
1197
- submodule_mode_mismatch(
1198
- repo, entry->path, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE);
2031
+ if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
2032
+ goto cleanup;
2033
+ git_buf_dispose(&path);
1199
2034
 
1200
- if (strcmp(entry->path, GIT_MODULES_FILE) == 0 &&
1201
- git_oid_iszero(gitmodules_oid))
1202
- git_oid_cpy(gitmodules_oid, &entry->oid);
1203
- }
1204
- }
2035
+ if ((error = git_config_snapshot(snap, mods)) < 0)
2036
+ goto cleanup;
1205
2037
 
1206
- if (error == GIT_ITEROVER)
1207
- error = 0;
2038
+ error = 0;
1208
2039
 
1209
- git_iterator_free(i);
1210
- git_tree_free(head);
2040
+ cleanup:
2041
+ if (mods)
2042
+ git_config_free(mods);
2043
+ git_buf_dispose(&path);
1211
2044
 
1212
2045
  return error;
1213
2046
  }
1214
2047
 
1215
2048
  static git_config_backend *open_gitmodules(
1216
2049
  git_repository *repo,
1217
- bool okay_to_create,
1218
- const git_oid *gitmodules_oid)
2050
+ int okay_to_create)
1219
2051
  {
1220
2052
  const char *workdir = git_repository_workdir(repo);
1221
2053
  git_buf path = GIT_BUF_INIT;
@@ -1226,197 +2058,132 @@ static git_config_backend *open_gitmodules(
1226
2058
  return NULL;
1227
2059
 
1228
2060
  if (okay_to_create || git_path_isfile(path.ptr)) {
1229
- /* git_config_file__ondisk should only fail if OOM */
1230
- if (git_config_file__ondisk(&mods, path.ptr) < 0)
2061
+ /* git_config_backend_from_file should only fail if OOM */
2062
+ if (git_config_backend_from_file(&mods, path.ptr) < 0)
1231
2063
  mods = NULL;
1232
2064
  /* open should only fail here if the file is malformed */
1233
- else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) {
1234
- git_config_file_free(mods);
2065
+ else if (git_config_backend_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) {
2066
+ git_config_backend_free(mods);
1235
2067
  mods = NULL;
1236
2068
  }
1237
2069
  }
1238
2070
  }
1239
2071
 
1240
- if (!mods && gitmodules_oid && !git_oid_iszero(gitmodules_oid)) {
1241
- /* TODO: Retrieve .gitmodules content from ODB */
1242
-
1243
- /* Should we actually do this? Core git does not, but it means you
1244
- * can't really get much information about submodules on bare repos.
1245
- */
1246
- }
1247
-
1248
- git_buf_free(&path);
2072
+ git_buf_dispose(&path);
1249
2073
 
1250
2074
  return mods;
1251
2075
  }
1252
2076
 
1253
- static int load_submodule_config(git_repository *repo)
2077
+ /* Lookup name of remote of the local tracking branch HEAD points to */
2078
+ static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
1254
2079
  {
1255
2080
  int error;
1256
- git_oid gitmodules_oid;
1257
- git_buf path = GIT_BUF_INIT;
1258
- git_config_backend *mods = NULL;
1259
-
1260
- if (repo->submodules)
1261
- return 0;
2081
+ git_reference *head = NULL;
2082
+ git_buf upstream_name = GIT_BUF_INIT;
1262
2083
 
1263
- memset(&gitmodules_oid, 0, sizeof(gitmodules_oid));
2084
+ /* lookup and dereference HEAD */
2085
+ if ((error = git_repository_head(&head, repo)) < 0)
2086
+ return error;
1264
2087
 
1265
- /* Submodule data is kept in a hashtable keyed by both name and path.
1266
- * These are usually the same, but that is not guaranteed.
1267
- */
1268
- if (!repo->submodules) {
1269
- repo->submodules = git_strmap_alloc();
1270
- GITERR_CHECK_ALLOC(repo->submodules);
2088
+ /**
2089
+ * If head does not refer to a branch, then return
2090
+ * GIT_ENOTFOUND to indicate that we could not find
2091
+ * a remote key for the local tracking branch HEAD points to.
2092
+ **/
2093
+ if (!git_reference_is_branch(head)) {
2094
+ git_error_set(GIT_ERROR_INVALID,
2095
+ "HEAD does not refer to a branch.");
2096
+ error = GIT_ENOTFOUND;
2097
+ goto done;
1271
2098
  }
1272
2099
 
1273
- /* add submodule information from index */
1274
-
1275
- if ((error = load_submodule_config_from_index(repo, &gitmodules_oid)) < 0)
1276
- goto cleanup;
1277
-
1278
- /* add submodule information from HEAD */
1279
-
1280
- if ((error = load_submodule_config_from_head(repo, &gitmodules_oid)) < 0)
1281
- goto cleanup;
1282
-
1283
- /* add submodule information from .gitmodules */
1284
-
1285
- if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL)
1286
- error = git_config_file_foreach(mods, submodule_load_from_config, repo);
1287
-
1288
- if (error != 0)
1289
- goto cleanup;
1290
-
1291
- /* shallow scan submodules in work tree */
1292
-
1293
- if (!git_repository_is_bare(repo))
1294
- error = git_submodule_foreach(repo, submodule_load_from_wd_lite, NULL);
1295
-
1296
- cleanup:
1297
- git_buf_free(&path);
2100
+ /* lookup remote tracking branch of HEAD */
2101
+ if ((error = git_branch_upstream_name(
2102
+ &upstream_name,
2103
+ repo,
2104
+ git_reference_name(head))) < 0)
2105
+ goto done;
1298
2106
 
1299
- if (mods != NULL)
1300
- git_config_file_free(mods);
2107
+ /* lookup remote of remote tracking branch */
2108
+ if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
2109
+ goto done;
1301
2110
 
1302
- if (error)
1303
- git_submodule_config_free(repo);
2111
+ done:
2112
+ git_buf_dispose(&upstream_name);
2113
+ git_reference_free(head);
1304
2114
 
1305
2115
  return error;
1306
2116
  }
1307
2117
 
1308
- static int lookup_head_remote(git_buf *url, git_repository *repo)
2118
+ /* Lookup the remote of the local tracking branch HEAD points to */
2119
+ static int lookup_head_remote(git_remote **remote, git_repository *repo)
1309
2120
  {
1310
2121
  int error;
1311
- git_config *cfg;
1312
- git_reference *head = NULL, *remote = NULL;
1313
- const char *tgt, *scan;
1314
- git_buf key = GIT_BUF_INIT;
1315
-
1316
- /* 1. resolve HEAD -> refs/heads/BRANCH
1317
- * 2. lookup config branch.BRANCH.remote -> ORIGIN
1318
- * 3. lookup remote.ORIGIN.url
1319
- */
1320
-
1321
- if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1322
- return error;
1323
-
1324
- if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) {
1325
- giterr_set(GITERR_SUBMODULE,
1326
- "Cannot resolve relative URL when HEAD cannot be resolved");
1327
- error = GIT_ENOTFOUND;
1328
- goto cleanup;
1329
- }
1330
-
1331
- if (git_reference_type(head) != GIT_REF_SYMBOLIC) {
1332
- giterr_set(GITERR_SUBMODULE,
1333
- "Cannot resolve relative URL when HEAD is not symbolic");
1334
- error = GIT_ENOTFOUND;
1335
- goto cleanup;
1336
- }
1337
-
1338
- if ((error = git_branch_upstream(&remote, head)) < 0)
1339
- goto cleanup;
1340
-
1341
- /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
2122
+ git_buf remote_name = GIT_BUF_INIT;
1342
2123
 
1343
- if (git_reference_type(remote) != GIT_REF_SYMBOLIC ||
1344
- git__prefixcmp(git_reference_symbolic_target(remote), GIT_REFS_REMOTES_DIR) != 0)
1345
- {
1346
- giterr_set(GITERR_SUBMODULE,
1347
- "Cannot resolve relative URL when HEAD is not symbolic");
1348
- error = GIT_ENOTFOUND;
1349
- goto cleanup;
1350
- }
2124
+ /* lookup remote of remote tracking branch name */
2125
+ if (!(error = lookup_head_remote_key(&remote_name, repo)))
2126
+ error = git_remote_lookup(remote, repo, remote_name.ptr);
1351
2127
 
1352
- scan = tgt = git_reference_symbolic_target(remote) + strlen(GIT_REFS_REMOTES_DIR);
1353
- while (*scan && (*scan != '/' || (scan > tgt && scan[-1] != '\\')))
1354
- scan++; /* find non-escaped slash to end ORIGIN name */
2128
+ git_buf_dispose(&remote_name);
1355
2129
 
1356
- error = git_buf_printf(&key, "remote.%.*s.url", (int)(scan - tgt), tgt);
1357
- if (error < 0)
1358
- goto cleanup;
2130
+ return error;
2131
+ }
1359
2132
 
1360
- if ((error = git_config_get_string(&tgt, cfg, key.ptr)) < 0)
1361
- goto cleanup;
2133
+ /* Lookup remote, either from HEAD or fall back on origin */
2134
+ static int lookup_default_remote(git_remote **remote, git_repository *repo)
2135
+ {
2136
+ int error = lookup_head_remote(remote, repo);
1362
2137
 
1363
- error = git_buf_sets(url, tgt);
2138
+ /* if that failed, use 'origin' instead */
2139
+ if (error == GIT_ENOTFOUND)
2140
+ error = git_remote_lookup(remote, repo, "origin");
1364
2141
 
1365
- cleanup:
1366
- git_buf_free(&key);
1367
- git_reference_free(head);
1368
- git_reference_free(remote);
2142
+ if (error == GIT_ENOTFOUND)
2143
+ git_error_set(
2144
+ GIT_ERROR_SUBMODULE,
2145
+ "cannot get default remote for submodule - no local tracking "
2146
+ "branch for HEAD and origin does not exist");
1369
2147
 
1370
2148
  return error;
1371
2149
  }
1372
2150
 
1373
- static int submodule_update_config(
1374
- git_submodule *submodule,
1375
- const char *attr,
1376
- const char *value,
1377
- bool overwrite,
1378
- bool only_existing)
2151
+ static int get_url_base(git_buf *url, git_repository *repo)
1379
2152
  {
1380
2153
  int error;
1381
- git_config *config;
1382
- git_buf key = GIT_BUF_INIT;
1383
- const char *old = NULL;
1384
-
1385
- assert(submodule);
1386
-
1387
- error = git_repository_config__weakptr(&config, submodule->owner);
1388
- if (error < 0)
1389
- return error;
1390
-
1391
- error = git_buf_printf(&key, "submodule.%s.%s", submodule->name, attr);
1392
- if (error < 0)
1393
- goto cleanup;
1394
-
1395
- if (git_config_get_string(&old, config, key.ptr) < 0)
1396
- giterr_clear();
2154
+ git_worktree *wt = NULL;
2155
+ git_remote *remote = NULL;
2156
+
2157
+ if ((error = lookup_default_remote(&remote, repo)) == 0) {
2158
+ error = git_buf_sets(url, git_remote_url(remote));
2159
+ goto out;
2160
+ } else if (error != GIT_ENOTFOUND)
2161
+ goto out;
2162
+ else
2163
+ git_error_clear();
1397
2164
 
1398
- if (!old && only_existing)
1399
- goto cleanup;
1400
- if (old && !overwrite)
1401
- goto cleanup;
1402
- if ((!old && !value) || (old && value && strcmp(old, value) == 0))
1403
- goto cleanup;
2165
+ /* if repository does not have a default remote, use workdir instead */
2166
+ if (git_repository_is_worktree(repo)) {
2167
+ if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
2168
+ goto out;
2169
+ error = git_buf_sets(url, wt->parent_path);
2170
+ } else
2171
+ error = git_buf_sets(url, git_repository_workdir(repo));
1404
2172
 
1405
- if (!value)
1406
- error = git_config_delete_entry(config, key.ptr);
1407
- else
1408
- error = git_config_set_string(config, key.ptr, value);
2173
+ out:
2174
+ git_remote_free(remote);
2175
+ git_worktree_free(wt);
1409
2176
 
1410
- cleanup:
1411
- git_buf_free(&key);
1412
2177
  return error;
1413
2178
  }
1414
2179
 
1415
- static int submodule_index_status(unsigned int *status, git_submodule *sm)
2180
+ static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
1416
2181
  {
1417
2182
  const git_oid *head_oid = git_submodule_head_id(sm);
1418
2183
  const git_oid *index_oid = git_submodule_index_id(sm);
1419
2184
 
2185
+ *status = *status & ~GIT_SUBMODULE_STATUS__INDEX_FLAGS;
2186
+
1420
2187
  if (!head_oid) {
1421
2188
  if (index_oid)
1422
2189
  *status |= GIT_SUBMODULE_STATUS_INDEX_ADDED;
@@ -1425,27 +2192,24 @@ static int submodule_index_status(unsigned int *status, git_submodule *sm)
1425
2192
  *status |= GIT_SUBMODULE_STATUS_INDEX_DELETED;
1426
2193
  else if (!git_oid_equal(head_oid, index_oid))
1427
2194
  *status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
1428
-
1429
- return 0;
1430
2195
  }
1431
2196
 
1432
- static int submodule_wd_status(unsigned int *status, git_submodule *sm)
1433
- {
1434
- int error = 0;
1435
- const git_oid *wd_oid, *index_oid;
1436
- git_repository *sm_repo = NULL;
1437
2197
 
1438
- /* open repo now if we need it (so wd_id() call won't reopen) */
1439
- if ((sm->ignore == GIT_SUBMODULE_IGNORE_NONE ||
1440
- sm->ignore == GIT_SUBMODULE_IGNORE_UNTRACKED) &&
1441
- (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0)
1442
- {
1443
- if ((error = git_submodule_open(&sm_repo, sm)) < 0)
1444
- return error;
1445
- }
2198
+ static void submodule_get_wd_status(
2199
+ unsigned int *status,
2200
+ git_submodule *sm,
2201
+ git_repository *sm_repo,
2202
+ git_submodule_ignore_t ign)
2203
+ {
2204
+ const git_oid *index_oid = git_submodule_index_id(sm);
2205
+ const git_oid *wd_oid =
2206
+ (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) ? &sm->wd_oid : NULL;
2207
+ git_tree *sm_head = NULL;
2208
+ git_index *index = NULL;
2209
+ git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
2210
+ git_diff *diff;
1446
2211
 
1447
- index_oid = git_submodule_index_id(sm);
1448
- wd_oid = git_submodule_wd_id(sm);
2212
+ *status = *status & ~GIT_SUBMODULE_STATUS__WD_FLAGS;
1449
2213
 
1450
2214
  if (!index_oid) {
1451
2215
  if (wd_oid)
@@ -1461,59 +2225,51 @@ static int submodule_wd_status(unsigned int *status, git_submodule *sm)
1461
2225
  else if (!git_oid_equal(index_oid, wd_oid))
1462
2226
  *status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
1463
2227
 
1464
- if (sm_repo != NULL) {
1465
- git_tree *sm_head;
1466
- git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
1467
- git_diff_list *diff;
1468
-
1469
- /* the diffs below could be optimized with an early termination
1470
- * option to the git_diff functions, but for now this is sufficient
1471
- * (and certainly no worse that what core git does).
1472
- */
1473
-
1474
- /* perform head-to-index diff on submodule */
2228
+ /* if we have no repo, then we're done */
2229
+ if (!sm_repo)
2230
+ return;
1475
2231
 
1476
- if ((error = git_repository_head_tree(&sm_head, sm_repo)) < 0)
1477
- return error;
2232
+ /* the diffs below could be optimized with an early termination
2233
+ * option to the git_diff functions, but for now this is sufficient
2234
+ * (and certainly no worse that what core git does).
2235
+ */
1478
2236
 
1479
- if (sm->ignore == GIT_SUBMODULE_IGNORE_NONE)
1480
- opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
2237
+ if (ign == GIT_SUBMODULE_IGNORE_NONE)
2238
+ opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
1481
2239
 
1482
- error = git_diff_tree_to_index(&diff, sm_repo, sm_head, NULL, &opt);
2240
+ (void)git_repository_index__weakptr(&index, sm_repo);
1483
2241
 
1484
- if (!error) {
2242
+ /* if we don't have an unborn head, check diff with index */
2243
+ if (git_repository_head_tree(&sm_head, sm_repo) < 0)
2244
+ git_error_clear();
2245
+ else {
2246
+ /* perform head to index diff on submodule */
2247
+ if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
2248
+ git_error_clear();
2249
+ else {
1485
2250
  if (git_diff_num_deltas(diff) > 0)
1486
2251
  *status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
1487
-
1488
- git_diff_list_free(diff);
2252
+ git_diff_free(diff);
1489
2253
  diff = NULL;
1490
2254
  }
1491
2255
 
1492
2256
  git_tree_free(sm_head);
2257
+ }
1493
2258
 
1494
- if (error < 0)
1495
- return error;
1496
-
1497
- /* perform index-to-workdir diff on submodule */
1498
-
1499
- error = git_diff_index_to_workdir(&diff, sm_repo, NULL, &opt);
1500
-
1501
- if (!error) {
1502
- size_t untracked =
1503
- git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
1504
-
1505
- if (untracked > 0)
1506
- *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
2259
+ /* perform index-to-workdir diff on submodule */
2260
+ if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
2261
+ git_error_clear();
2262
+ else {
2263
+ size_t untracked =
2264
+ git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
1507
2265
 
1508
- if (git_diff_num_deltas(diff) != untracked)
1509
- *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
2266
+ if (untracked > 0)
2267
+ *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
1510
2268
 
1511
- git_diff_list_free(diff);
1512
- diff = NULL;
1513
- }
2269
+ if (git_diff_num_deltas(diff) != untracked)
2270
+ *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
1514
2271
 
1515
- git_repository_free(sm_repo);
2272
+ git_diff_free(diff);
2273
+ diff = NULL;
1516
2274
  }
1517
-
1518
- return error;
1519
2275
  }