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,10 +5,10 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
- #include <assert.h>
9
-
10
8
  #include "checkout.h"
11
9
 
10
+ #include <assert.h>
11
+
12
12
  #include "git2/repository.h"
13
13
  #include "git2/refs.h"
14
14
  #include "git2/tree.h"
@@ -17,6 +17,8 @@
17
17
  #include "git2/diff.h"
18
18
  #include "git2/submodule.h"
19
19
  #include "git2/sys/index.h"
20
+ #include "git2/sys/filter.h"
21
+ #include "git2/merge.h"
20
22
 
21
23
  #include "refs.h"
22
24
  #include "repository.h"
@@ -24,8 +26,14 @@
24
26
  #include "filter.h"
25
27
  #include "blob.h"
26
28
  #include "diff.h"
29
+ #include "diff_generate.h"
27
30
  #include "pathspec.h"
28
31
  #include "buf_text.h"
32
+ #include "diff_xdiff.h"
33
+ #include "path.h"
34
+ #include "attr.h"
35
+ #include "pool.h"
36
+ #include "strmap.h"
29
37
 
30
38
  /* See docs/checkout-internals.md for more information */
31
39
 
@@ -35,30 +43,54 @@ enum {
35
43
  CHECKOUT_ACTION__UPDATE_BLOB = 2,
36
44
  CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
37
45
  CHECKOUT_ACTION__CONFLICT = 8,
38
- CHECKOUT_ACTION__MAX = 8,
39
- CHECKOUT_ACTION__DEFER_REMOVE = 16,
46
+ CHECKOUT_ACTION__REMOVE_CONFLICT = 16,
47
+ CHECKOUT_ACTION__UPDATE_CONFLICT = 32,
48
+ CHECKOUT_ACTION__MAX = 32,
49
+ CHECKOUT_ACTION__DEFER_REMOVE = 64,
40
50
  CHECKOUT_ACTION__REMOVE_AND_UPDATE =
41
51
  (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
42
52
  };
43
53
 
44
54
  typedef struct {
45
55
  git_repository *repo;
46
- git_diff_list *diff;
47
- git_checkout_opts opts;
56
+ git_iterator *target;
57
+ git_diff *diff;
58
+ git_checkout_options opts;
48
59
  bool opts_free_baseline;
49
60
  char *pfx;
50
61
  git_index *index;
51
62
  git_pool pool;
52
63
  git_vector removes;
53
- git_buf path;
54
- size_t workdir_len;
64
+ git_vector remove_conflicts;
65
+ git_vector update_conflicts;
66
+ git_vector *update_reuc;
67
+ git_vector *update_names;
68
+ git_buf target_path;
69
+ size_t target_len;
70
+ git_buf tmp;
55
71
  unsigned int strategy;
56
72
  int can_symlink;
73
+ int respect_filemode;
57
74
  bool reload_submodules;
58
75
  size_t total_steps;
59
76
  size_t completed_steps;
77
+ git_checkout_perfdata perfdata;
78
+ git_strmap *mkdir_map;
79
+ git_attr_session attr_session;
60
80
  } checkout_data;
61
81
 
82
+ typedef struct {
83
+ const git_index_entry *ancestor;
84
+ const git_index_entry *ours;
85
+ const git_index_entry *theirs;
86
+
87
+ int name_collision:1,
88
+ directoryfile:1,
89
+ one_to_two:1,
90
+ binary:1,
91
+ submodule:1;
92
+ } checkout_conflictdata;
93
+
62
94
  static int checkout_notify(
63
95
  checkout_data *data,
64
96
  git_checkout_notify_t why,
@@ -69,19 +101,17 @@ static int checkout_notify(
69
101
  const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL;
70
102
  const char *path = NULL;
71
103
 
72
- if (!data->opts.notify_cb)
73
- return 0;
74
-
75
- if ((why & data->opts.notify_flags) == 0)
104
+ if (!data->opts.notify_cb ||
105
+ (why & data->opts.notify_flags) == 0)
76
106
  return 0;
77
107
 
78
108
  if (wditem) {
79
109
  memset(&wdfile, 0, sizeof(wdfile));
80
110
 
81
- git_oid_cpy(&wdfile.oid, &wditem->oid);
111
+ git_oid_cpy(&wdfile.id, &wditem->id);
82
112
  wdfile.path = wditem->path;
83
113
  wdfile.size = wditem->file_size;
84
- wdfile.flags = GIT_DIFF_FLAG_VALID_OID;
114
+ wdfile.flags = GIT_DIFF_FLAG_VALID_ID;
85
115
  wdfile.mode = wditem->mode;
86
116
 
87
117
  workdir = &wdfile;
@@ -101,6 +131,7 @@ static int checkout_notify(
101
131
  case GIT_DELTA_ADDED:
102
132
  case GIT_DELTA_IGNORED:
103
133
  case GIT_DELTA_UNTRACKED:
134
+ case GIT_DELTA_UNREADABLE:
104
135
  target = &delta->new_file;
105
136
  break;
106
137
  case GIT_DELTA_DELETED:
@@ -111,13 +142,44 @@ static int checkout_notify(
111
142
  path = delta->old_file.path;
112
143
  }
113
144
 
114
- return data->opts.notify_cb(
115
- why, path, baseline, target, workdir, data->opts.notify_payload);
145
+ {
146
+ int error = data->opts.notify_cb(
147
+ why, path, baseline, target, workdir, data->opts.notify_payload);
148
+
149
+ return git_error_set_after_callback_function(
150
+ error, "git_checkout notification");
151
+ }
152
+ }
153
+
154
+ GIT_INLINE(bool) is_workdir_base_or_new(
155
+ const git_oid *workdir_id,
156
+ const git_diff_file *baseitem,
157
+ const git_diff_file *newitem)
158
+ {
159
+ return (git_oid__cmp(&baseitem->id, workdir_id) == 0 ||
160
+ git_oid__cmp(&newitem->id, workdir_id) == 0);
161
+ }
162
+
163
+ GIT_INLINE(bool) is_filemode_changed(git_filemode_t a, git_filemode_t b, int respect_filemode)
164
+ {
165
+ /* If core.filemode = false, ignore links in the repository and executable bit changes */
166
+ if (!respect_filemode) {
167
+ if (a == S_IFLNK)
168
+ a = GIT_FILEMODE_BLOB;
169
+ if (b == S_IFLNK)
170
+ b = GIT_FILEMODE_BLOB;
171
+
172
+ a &= ~0111;
173
+ b &= ~0111;
174
+ }
175
+
176
+ return (a != b);
116
177
  }
117
178
 
118
179
  static bool checkout_is_workdir_modified(
119
180
  checkout_data *data,
120
181
  const git_diff_file *baseitem,
182
+ const git_diff_file *newitem,
121
183
  const git_index_entry *wditem)
122
184
  {
123
185
  git_oid oid;
@@ -128,30 +190,42 @@ static bool checkout_is_workdir_modified(
128
190
  git_submodule *sm;
129
191
  unsigned int sm_status = 0;
130
192
  const git_oid *sm_oid = NULL;
193
+ bool rval = false;
131
194
 
132
- if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0 ||
133
- git_submodule_status(&sm_status, sm) < 0)
134
- return true;
135
-
136
- if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
195
+ if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0) {
196
+ git_error_clear();
137
197
  return true;
198
+ }
138
199
 
139
- sm_oid = git_submodule_wd_id(sm);
140
- if (!sm_oid)
141
- return false;
200
+ if (git_submodule_status(&sm_status, data->repo, wditem->path, GIT_SUBMODULE_IGNORE_UNSPECIFIED) < 0 ||
201
+ GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
202
+ rval = true;
203
+ else if ((sm_oid = git_submodule_wd_id(sm)) == NULL)
204
+ rval = false;
205
+ else
206
+ rval = (git_oid__cmp(&baseitem->id, sm_oid) != 0);
142
207
 
143
- return (git_oid__cmp(&baseitem->oid, sm_oid) != 0);
208
+ git_submodule_free(sm);
209
+ return rval;
144
210
  }
145
211
 
146
- /* Look at the cache to decide if the workdir is modified. If not,
147
- * we can simply compare the oid in the cache to the baseitem instead
148
- * of hashing the file.
212
+ /*
213
+ * Look at the cache to decide if the workdir is modified: if the
214
+ * cache contents match the workdir contents, then we do not need
215
+ * to examine the working directory directly, instead we can
216
+ * examine the cache to see if _it_ has been modified. This allows
217
+ * us to avoid touching the disk.
149
218
  */
150
- if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
151
- if (wditem->mtime.seconds == ie->mtime.seconds &&
152
- wditem->mtime.nanoseconds == ie->mtime.nanoseconds &&
153
- wditem->file_size == ie->file_size)
154
- return (git_oid__cmp(&baseitem->oid, &ie->oid) != 0);
219
+ ie = git_index_get_bypath(data->index, wditem->path, 0);
220
+
221
+ if (ie != NULL &&
222
+ git_index_time_eq(&wditem->mtime, &ie->mtime) &&
223
+ wditem->file_size == ie->file_size &&
224
+ !is_filemode_changed(wditem->mode, ie->mode, data->respect_filemode)) {
225
+
226
+ /* The workdir is modified iff the index entry is modified */
227
+ return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
228
+ is_filemode_changed(baseitem->mode, ie->mode, data->respect_filemode);
155
229
  }
156
230
 
157
231
  /* depending on where base is coming from, we may or may not know
@@ -160,145 +234,220 @@ static bool checkout_is_workdir_modified(
160
234
  if (baseitem->size && wditem->file_size != baseitem->size)
161
235
  return true;
162
236
 
163
- if (git_diff__oid_for_file(
164
- data->repo, wditem->path, wditem->mode,
165
- wditem->file_size, &oid) < 0)
237
+ /* if the workdir item is a directory, it cannot be a modified file */
238
+ if (S_ISDIR(wditem->mode))
239
+ return false;
240
+
241
+ if (is_filemode_changed(baseitem->mode, wditem->mode, data->respect_filemode))
242
+ return true;
243
+
244
+ if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
166
245
  return false;
167
246
 
168
- return (git_oid__cmp(&baseitem->oid, &oid) != 0);
247
+ /* Allow the checkout if the workdir is not modified *or* if the checkout
248
+ * target's contents are already in the working directory.
249
+ */
250
+ return !is_workdir_base_or_new(&oid, baseitem, newitem);
169
251
  }
170
252
 
171
253
  #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
172
254
  ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
173
255
 
174
256
  static int checkout_action_common(
257
+ int *action,
175
258
  checkout_data *data,
176
- int action,
177
259
  const git_diff_delta *delta,
178
260
  const git_index_entry *wd)
179
261
  {
180
262
  git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
181
263
 
182
- if (action <= 0)
183
- return action;
184
-
185
264
  if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
186
- action = (action & ~CHECKOUT_ACTION__REMOVE);
265
+ *action = (*action & ~CHECKOUT_ACTION__REMOVE);
187
266
 
188
- if ((action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) {
267
+ if ((*action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) {
189
268
  if (S_ISGITLINK(delta->new_file.mode))
190
- action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB) |
269
+ *action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB) |
191
270
  CHECKOUT_ACTION__UPDATE_SUBMODULE;
192
271
 
193
272
  /* to "update" a symlink, we must remove the old one first */
194
273
  if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL)
195
- action |= CHECKOUT_ACTION__REMOVE;
274
+ *action |= CHECKOUT_ACTION__REMOVE;
275
+
276
+ /* if the file is on disk and doesn't match our mode, force update */
277
+ if (wd &&
278
+ GIT_PERMS_IS_EXEC(wd->mode) !=
279
+ GIT_PERMS_IS_EXEC(delta->new_file.mode))
280
+ *action |= CHECKOUT_ACTION__REMOVE;
196
281
 
197
282
  notify = GIT_CHECKOUT_NOTIFY_UPDATED;
198
283
  }
199
284
 
200
- if ((action & CHECKOUT_ACTION__CONFLICT) != 0)
285
+ if ((*action & CHECKOUT_ACTION__CONFLICT) != 0)
201
286
  notify = GIT_CHECKOUT_NOTIFY_CONFLICT;
202
287
 
203
- if (notify != GIT_CHECKOUT_NOTIFY_NONE &&
204
- checkout_notify(data, notify, delta, wd) != 0)
205
- return GIT_EUSER;
206
-
207
- return action;
288
+ return checkout_notify(data, notify, delta, wd);
208
289
  }
209
290
 
210
291
  static int checkout_action_no_wd(
292
+ int *action,
211
293
  checkout_data *data,
212
294
  const git_diff_delta *delta)
213
295
  {
214
- int action = CHECKOUT_ACTION__NONE;
296
+ int error = 0;
297
+
298
+ *action = CHECKOUT_ACTION__NONE;
215
299
 
216
300
  switch (delta->status) {
217
301
  case GIT_DELTA_UNMODIFIED: /* case 12 */
218
- if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL))
219
- return GIT_EUSER;
220
- action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE);
302
+ error = checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL);
303
+ if (error)
304
+ return error;
305
+ *action = CHECKOUT_ACTION_IF(RECREATE_MISSING, UPDATE_BLOB, NONE);
221
306
  break;
222
307
  case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */
223
- action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
308
+ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
224
309
  break;
225
310
  case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
226
- action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT);
311
+ *action = CHECKOUT_ACTION_IF(RECREATE_MISSING, UPDATE_BLOB, CONFLICT);
227
312
  break;
228
313
  case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/
229
314
  if (delta->new_file.mode == GIT_FILEMODE_TREE)
230
- action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
315
+ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
231
316
  break;
232
317
  case GIT_DELTA_DELETED: /* case 8 or 25 */
318
+ *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
319
+ break;
233
320
  default: /* impossible */
234
321
  break;
235
322
  }
236
323
 
237
- return checkout_action_common(data, action, delta, NULL);
324
+ return checkout_action_common(action, data, delta, NULL);
325
+ }
326
+
327
+ static int checkout_target_fullpath(
328
+ git_buf **out, checkout_data *data, const char *path)
329
+ {
330
+ git_buf_truncate(&data->target_path, data->target_len);
331
+
332
+ if (path && git_buf_puts(&data->target_path, path) < 0)
333
+ return -1;
334
+
335
+ *out = &data->target_path;
336
+
337
+ return 0;
338
+ }
339
+
340
+ static bool wd_item_is_removable(
341
+ checkout_data *data, const git_index_entry *wd)
342
+ {
343
+ git_buf *full;
344
+
345
+ if (wd->mode != GIT_FILEMODE_TREE)
346
+ return true;
347
+
348
+ if (checkout_target_fullpath(&full, data, wd->path) < 0)
349
+ return false;
350
+
351
+ return !full || !git_path_contains(full, DOT_GIT);
238
352
  }
239
353
 
354
+ static int checkout_queue_remove(checkout_data *data, const char *path)
355
+ {
356
+ char *copy = git_pool_strdup(&data->pool, path);
357
+ GIT_ERROR_CHECK_ALLOC(copy);
358
+ return git_vector_insert(&data->removes, copy);
359
+ }
360
+
361
+ /* note that this advances the iterator over the wd item */
240
362
  static int checkout_action_wd_only(
241
363
  checkout_data *data,
242
364
  git_iterator *workdir,
243
- const git_index_entry *wd,
365
+ const git_index_entry **wditem,
244
366
  git_vector *pathspec)
245
367
  {
368
+ int error = 0;
246
369
  bool remove = false;
247
370
  git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
371
+ const git_index_entry *wd = *wditem;
248
372
 
249
- if (!git_pathspec_match_path(
373
+ if (!git_pathspec__match(
250
374
  pathspec, wd->path,
251
375
  (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
252
- git_iterator_ignore_case(workdir), NULL))
253
- return 0;
376
+ git_iterator_ignore_case(workdir), NULL, NULL))
377
+ return git_iterator_advance(wditem, workdir);
254
378
 
255
379
  /* check if item is tracked in the index but not in the checkout diff */
256
380
  if (data->index != NULL) {
257
- if (wd->mode != GIT_FILEMODE_TREE) {
258
- int error;
381
+ size_t pos;
382
+
383
+ error = git_index__find_pos(
384
+ &pos, data->index, wd->path, 0, GIT_INDEX_STAGE_ANY);
259
385
 
260
- if ((error = git_index_find(NULL, data->index, wd->path)) == 0) {
386
+ if (wd->mode != GIT_FILEMODE_TREE) {
387
+ if (!error) { /* found by git_index__find_pos call */
261
388
  notify = GIT_CHECKOUT_NOTIFY_DIRTY;
262
389
  remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
263
390
  } else if (error != GIT_ENOTFOUND)
264
391
  return error;
392
+ else
393
+ error = 0; /* git_index__find_pos does not set error msg */
265
394
  } else {
266
395
  /* for tree entries, we have to see if there are any index
267
396
  * entries that are contained inside that tree
268
397
  */
269
- size_t pos = git_index__prefix_position(data->index, wd->path);
270
398
  const git_index_entry *e = git_index_get_byindex(data->index, pos);
271
399
 
272
- if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
273
- notify = GIT_CHECKOUT_NOTIFY_DIRTY;
274
- remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
275
- }
400
+ if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0)
401
+ return git_iterator_advance_into(wditem, workdir);
276
402
  }
277
403
  }
278
404
 
279
- if (notify != GIT_CHECKOUT_NOTIFY_NONE)
280
- /* found in index */;
281
- else if (git_iterator_current_is_ignored(workdir)) {
282
- notify = GIT_CHECKOUT_NOTIFY_IGNORED;
283
- remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
284
- }
285
- else {
286
- notify = GIT_CHECKOUT_NOTIFY_UNTRACKED;
287
- remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0);
288
- }
405
+ if (notify != GIT_CHECKOUT_NOTIFY_NONE) {
406
+ /* if we found something in the index, notify and advance */
407
+ if ((error = checkout_notify(data, notify, NULL, wd)) != 0)
408
+ return error;
289
409
 
290
- if (checkout_notify(data, notify, NULL, wd))
291
- return GIT_EUSER;
410
+ if (remove && wd_item_is_removable(data, wd))
411
+ error = checkout_queue_remove(data, wd->path);
292
412
 
293
- if (remove) {
294
- char *path = git_pool_strdup(&data->pool, wd->path);
295
- GITERR_CHECK_ALLOC(path);
413
+ if (!error)
414
+ error = git_iterator_advance(wditem, workdir);
415
+ } else {
416
+ /* untracked or ignored - can't know which until we advance through */
417
+ bool over = false, removable = wd_item_is_removable(data, wd);
418
+ git_iterator_status_t untracked_state;
419
+
420
+ /* copy the entry for issuing notification callback later */
421
+ git_index_entry saved_wd = *wd;
422
+ git_buf_sets(&data->tmp, wd->path);
423
+ saved_wd.path = data->tmp.ptr;
424
+
425
+ error = git_iterator_advance_over(
426
+ wditem, &untracked_state, workdir);
427
+ if (error == GIT_ITEROVER)
428
+ over = true;
429
+ else if (error < 0)
430
+ return error;
296
431
 
297
- if (git_vector_insert(&data->removes, path) < 0)
298
- return -1;
432
+ if (untracked_state == GIT_ITERATOR_STATUS_IGNORED) {
433
+ notify = GIT_CHECKOUT_NOTIFY_IGNORED;
434
+ remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
435
+ } else {
436
+ notify = GIT_CHECKOUT_NOTIFY_UNTRACKED;
437
+ remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0);
438
+ }
439
+
440
+ if ((error = checkout_notify(data, notify, NULL, &saved_wd)) != 0)
441
+ return error;
442
+
443
+ if (remove && removable)
444
+ error = checkout_queue_remove(data, saved_wd.path);
445
+
446
+ if (!error && over) /* restore ITEROVER if needed */
447
+ error = GIT_ITEROVER;
299
448
  }
300
449
 
301
- return 0;
450
+ return error;
302
451
  }
303
452
 
304
453
  static bool submodule_is_config_only(
@@ -307,45 +456,65 @@ static bool submodule_is_config_only(
307
456
  {
308
457
  git_submodule *sm = NULL;
309
458
  unsigned int sm_loc = 0;
459
+ bool rval = false;
310
460
 
311
- if (git_submodule_lookup(&sm, data->repo, path) < 0 ||
312
- git_submodule_location(&sm_loc, sm) < 0 ||
313
- sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
461
+ if (git_submodule_lookup(&sm, data->repo, path) < 0)
314
462
  return true;
315
463
 
316
- return false;
464
+ if (git_submodule_location(&sm_loc, sm) < 0 ||
465
+ sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
466
+ rval = true;
467
+
468
+ git_submodule_free(sm);
469
+
470
+ return rval;
471
+ }
472
+
473
+ static bool checkout_is_empty_dir(checkout_data *data, const char *path)
474
+ {
475
+ git_buf *fullpath;
476
+
477
+ if (checkout_target_fullpath(&fullpath, data, path) < 0)
478
+ return false;
479
+
480
+ return git_path_is_empty_dir(fullpath->ptr);
317
481
  }
318
482
 
319
483
  static int checkout_action_with_wd(
484
+ int *action,
320
485
  checkout_data *data,
321
486
  const git_diff_delta *delta,
487
+ git_iterator *workdir,
322
488
  const git_index_entry *wd)
323
489
  {
324
- int action = CHECKOUT_ACTION__NONE;
490
+ *action = CHECKOUT_ACTION__NONE;
325
491
 
326
492
  switch (delta->status) {
327
493
  case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */
328
- if (checkout_is_workdir_modified(data, &delta->old_file, wd)) {
329
- if (checkout_notify(
330
- data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
331
- return GIT_EUSER;
332
- action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
494
+ if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) {
495
+ GIT_ERROR_CHECK_ERROR(
496
+ checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
497
+ *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
333
498
  }
334
499
  break;
335
500
  case GIT_DELTA_ADDED: /* case 3, 4 or 6 */
336
- action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
501
+ if (git_iterator_current_is_ignored(workdir))
502
+ *action = CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, UPDATE_BLOB);
503
+ else
504
+ *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
337
505
  break;
338
506
  case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
339
- if (checkout_is_workdir_modified(data, &delta->old_file, wd))
340
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
507
+ if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
508
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
341
509
  else
342
- action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
510
+ *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
343
511
  break;
344
512
  case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
345
- if (checkout_is_workdir_modified(data, &delta->old_file, wd))
346
- action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
513
+ if (wd->mode != GIT_FILEMODE_COMMIT &&
514
+ checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
515
+ *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
347
516
  else
348
- action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
517
+ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
349
518
  break;
350
519
  case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */
351
520
  if (delta->old_file.mode == GIT_FILEMODE_TREE) {
@@ -353,92 +522,97 @@ static int checkout_action_with_wd(
353
522
  /* either deleting items in old tree will delete the wd dir,
354
523
  * or we'll get a conflict when we attempt blob update...
355
524
  */
356
- action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
525
+ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
357
526
  else if (wd->mode == GIT_FILEMODE_COMMIT) {
358
527
  /* workdir is possibly a "phantom" submodule - treat as a
359
528
  * tree if the only submodule info came from the config
360
529
  */
361
530
  if (submodule_is_config_only(data, wd->path))
362
- action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
531
+ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
363
532
  else
364
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
533
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
365
534
  } else
366
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
535
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
367
536
  }
368
- else if (checkout_is_workdir_modified(data, &delta->old_file, wd))
369
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
537
+ else if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
538
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
370
539
  else
371
- action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
540
+ *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
372
541
 
373
542
  /* don't update if the typechange is to a tree */
374
543
  if (delta->new_file.mode == GIT_FILEMODE_TREE)
375
- action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB);
544
+ *action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB);
376
545
  break;
377
546
  default: /* impossible */
378
547
  break;
379
548
  }
380
549
 
381
- return checkout_action_common(data, action, delta, wd);
550
+ return checkout_action_common(action, data, delta, wd);
382
551
  }
383
552
 
384
553
  static int checkout_action_with_wd_blocker(
554
+ int *action,
385
555
  checkout_data *data,
386
556
  const git_diff_delta *delta,
387
557
  const git_index_entry *wd)
388
558
  {
389
- int action = CHECKOUT_ACTION__NONE;
559
+ *action = CHECKOUT_ACTION__NONE;
390
560
 
391
561
  switch (delta->status) {
392
562
  case GIT_DELTA_UNMODIFIED:
393
563
  /* should show delta as dirty / deleted */
394
- if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
395
- return GIT_EUSER;
396
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
564
+ GIT_ERROR_CHECK_ERROR(
565
+ checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
566
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
397
567
  break;
398
568
  case GIT_DELTA_ADDED:
399
569
  case GIT_DELTA_MODIFIED:
400
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
570
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
401
571
  break;
402
572
  case GIT_DELTA_DELETED:
403
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
573
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
404
574
  break;
405
575
  case GIT_DELTA_TYPECHANGE:
406
576
  /* not 100% certain about this... */
407
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
577
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
408
578
  break;
409
579
  default: /* impossible */
410
580
  break;
411
581
  }
412
582
 
413
- return checkout_action_common(data, action, delta, wd);
583
+ return checkout_action_common(action, data, delta, wd);
414
584
  }
415
585
 
416
586
  static int checkout_action_with_wd_dir(
587
+ int *action,
417
588
  checkout_data *data,
418
589
  const git_diff_delta *delta,
590
+ git_iterator *workdir,
419
591
  const git_index_entry *wd)
420
592
  {
421
- int action = CHECKOUT_ACTION__NONE;
593
+ *action = CHECKOUT_ACTION__NONE;
422
594
 
423
595
  switch (delta->status) {
424
596
  case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */
425
- if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) ||
426
- checkout_notify(
427
- data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
428
- return GIT_EUSER;
597
+ GIT_ERROR_CHECK_ERROR(
598
+ checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL));
599
+ GIT_ERROR_CHECK_ERROR(
600
+ checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
601
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
429
602
  break;
430
603
  case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
431
604
  case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
432
605
  if (delta->old_file.mode == GIT_FILEMODE_COMMIT)
433
606
  /* expected submodule (and maybe found one) */;
434
607
  else if (delta->new_file.mode != GIT_FILEMODE_TREE)
435
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
608
+ *action = git_iterator_current_is_ignored(workdir) ?
609
+ CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, REMOVE_AND_UPDATE) :
610
+ CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
436
611
  break;
437
612
  case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */
438
- if (delta->old_file.mode != GIT_FILEMODE_TREE &&
439
- checkout_notify(
440
- data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
441
- return GIT_EUSER;
613
+ if (delta->old_file.mode != GIT_FILEMODE_TREE)
614
+ GIT_ERROR_CHECK_ERROR(
615
+ checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
442
616
  break;
443
617
  case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */
444
618
  if (delta->old_file.mode == GIT_FILEMODE_TREE) {
@@ -448,39 +622,53 @@ static int checkout_action_with_wd_dir(
448
622
  * directory if is it left empty, so we can defer removing the
449
623
  * dir and it will succeed if no children are left.
450
624
  */
451
- action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
452
- if (action != CHECKOUT_ACTION__NONE)
453
- action |= CHECKOUT_ACTION__DEFER_REMOVE;
625
+ *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
454
626
  }
455
627
  else if (delta->new_file.mode != GIT_FILEMODE_TREE)
456
628
  /* For typechange to dir, dir is already created so no action */
457
- action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
629
+ *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
458
630
  break;
459
631
  default: /* impossible */
460
632
  break;
461
633
  }
462
634
 
463
- return checkout_action_common(data, action, delta, wd);
635
+ return checkout_action_common(action, data, delta, wd);
636
+ }
637
+
638
+ static int checkout_action_with_wd_dir_empty(
639
+ int *action,
640
+ checkout_data *data,
641
+ const git_diff_delta *delta)
642
+ {
643
+ int error = checkout_action_no_wd(action, data, delta);
644
+
645
+ /* We can always safely remove an empty directory. */
646
+ if (error == 0 && *action != CHECKOUT_ACTION__NONE)
647
+ *action |= CHECKOUT_ACTION__REMOVE;
648
+
649
+ return error;
464
650
  }
465
651
 
466
652
  static int checkout_action(
653
+ int *action,
467
654
  checkout_data *data,
468
655
  git_diff_delta *delta,
469
656
  git_iterator *workdir,
470
- const git_index_entry **wditem_ptr,
657
+ const git_index_entry **wditem,
471
658
  git_vector *pathspec)
472
659
  {
473
- const git_index_entry *wd = *wditem_ptr;
474
- int cmp = -1, act;
660
+ int cmp = -1, error;
475
661
  int (*strcomp)(const char *, const char *) = data->diff->strcomp;
476
662
  int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp;
477
- int error;
663
+ int (*advance)(const git_index_entry **, git_iterator *) = NULL;
478
664
 
479
665
  /* move workdir iterator to follow along with deltas */
480
666
 
481
667
  while (1) {
668
+ const git_index_entry *wd = *wditem;
669
+
482
670
  if (!wd)
483
- return checkout_action_no_wd(data, delta);
671
+ return checkout_action_no_wd(action, data, delta);
484
672
 
485
673
  cmp = strcomp(wd->path, delta->old_file.path);
486
674
 
@@ -498,79 +686,76 @@ static int checkout_action(
498
686
  if (cmp == 0) {
499
687
  if (wd->mode == GIT_FILEMODE_TREE) {
500
688
  /* case 2 - entry prefixed by workdir tree */
501
- error = git_iterator_advance_into_or_over(&wd, workdir);
502
- if (error && error != GIT_ITEROVER)
503
- goto fail;
504
- *wditem_ptr = wd;
689
+ error = git_iterator_advance_into(wditem, workdir);
690
+ if (error < 0 && error != GIT_ITEROVER)
691
+ goto done;
505
692
  continue;
506
693
  }
507
694
 
508
695
  /* case 3 maybe - wd contains non-dir where dir expected */
509
696
  if (delta->old_file.path[strlen(wd->path)] == '/') {
510
- act = checkout_action_with_wd_blocker(data, delta, wd);
511
- *wditem_ptr =
512
- git_iterator_advance(&wd, workdir) ? NULL : wd;
513
- return act;
697
+ error = checkout_action_with_wd_blocker(
698
+ action, data, delta, wd);
699
+ advance = git_iterator_advance;
700
+ goto done;
514
701
  }
515
702
  }
516
703
 
517
704
  /* case 1 - handle wd item (if it matches pathspec) */
518
- if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0)
519
- goto fail;
520
- if ((error = git_iterator_advance(&wd, workdir)) < 0 &&
521
- error != GIT_ITEROVER)
522
- goto fail;
523
-
524
- *wditem_ptr = wd;
705
+ error = checkout_action_wd_only(data, workdir, wditem, pathspec);
706
+ if (error && error != GIT_ITEROVER)
707
+ goto done;
525
708
  continue;
526
709
  }
527
710
 
528
711
  if (cmp == 0) {
529
712
  /* case 4 */
530
- act = checkout_action_with_wd(data, delta, wd);
531
- *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd;
532
- return act;
713
+ error = checkout_action_with_wd(action, data, delta, workdir, wd);
714
+ advance = git_iterator_advance;
715
+ goto done;
533
716
  }
534
717
 
535
718
  cmp = pfxcomp(wd->path, delta->old_file.path);
536
719
 
537
720
  if (cmp == 0) { /* case 5 */
538
721
  if (wd->path[strlen(delta->old_file.path)] != '/')
539
- return checkout_action_no_wd(data, delta);
722
+ return checkout_action_no_wd(action, data, delta);
540
723
 
541
724
  if (delta->status == GIT_DELTA_TYPECHANGE) {
542
725
  if (delta->old_file.mode == GIT_FILEMODE_TREE) {
543
- act = checkout_action_with_wd(data, delta, wd);
544
- if ((error = git_iterator_advance_into(&wd, workdir)) < 0 &&
545
- error != GIT_ENOTFOUND)
546
- goto fail;
547
- *wditem_ptr = wd;
548
- return act;
726
+ error = checkout_action_with_wd(action, data, delta, workdir, wd);
727
+ advance = git_iterator_advance_into;
728
+ goto done;
549
729
  }
550
730
 
551
731
  if (delta->new_file.mode == GIT_FILEMODE_TREE ||
552
732
  delta->new_file.mode == GIT_FILEMODE_COMMIT ||
553
733
  delta->old_file.mode == GIT_FILEMODE_COMMIT)
554
734
  {
555
- act = checkout_action_with_wd(data, delta, wd);
556
- if ((error = git_iterator_advance(&wd, workdir)) < 0 &&
557
- error != GIT_ITEROVER)
558
- goto fail;
559
- *wditem_ptr = wd;
560
- return act;
735
+ error = checkout_action_with_wd(action, data, delta, workdir, wd);
736
+ advance = git_iterator_advance;
737
+ goto done;
561
738
  }
562
739
  }
563
740
 
564
- return checkout_action_with_wd_dir(data, delta, wd);
741
+ return checkout_is_empty_dir(data, wd->path) ?
742
+ checkout_action_with_wd_dir_empty(action, data, delta) :
743
+ checkout_action_with_wd_dir(action, data, delta, workdir, wd);
565
744
  }
566
745
 
567
746
  /* case 6 - wd is after delta */
568
- return checkout_action_no_wd(data, delta);
747
+ return checkout_action_no_wd(action, data, delta);
569
748
  }
570
749
 
571
- fail:
572
- *wditem_ptr = NULL;
573
- return -1;
750
+ done:
751
+ if (!error && advance != NULL &&
752
+ (error = advance(wditem, workdir)) < 0) {
753
+ *wditem = NULL;
754
+ if (error == GIT_ITEROVER)
755
+ error = 0;
756
+ }
757
+
758
+ return error;
574
759
  }
575
760
 
576
761
  static int checkout_remaining_wd_items(
@@ -581,10 +766,8 @@ static int checkout_remaining_wd_items(
581
766
  {
582
767
  int error = 0;
583
768
 
584
- while (wd && !error) {
585
- if (!(error = checkout_action_wd_only(data, workdir, wd, spec)))
586
- error = git_iterator_advance(&wd, workdir);
587
- }
769
+ while (wd && !error)
770
+ error = checkout_action_wd_only(data, workdir, &wd, spec);
588
771
 
589
772
  if (error == GIT_ITEROVER)
590
773
  error = 0;
@@ -592,219 +775,842 @@ static int checkout_remaining_wd_items(
592
775
  return error;
593
776
  }
594
777
 
595
- static int checkout_get_actions(
596
- uint32_t **actions_ptr,
597
- size_t **counts_ptr,
598
- checkout_data *data,
599
- git_iterator *workdir)
778
+ GIT_INLINE(int) checkout_idxentry_cmp(
779
+ const git_index_entry *a,
780
+ const git_index_entry *b)
600
781
  {
601
- int error = 0;
602
- const git_index_entry *wditem;
603
- git_vector pathspec = GIT_VECTOR_INIT, *deltas;
604
- git_pool pathpool = GIT_POOL_INIT_STRINGPOOL;
605
- git_diff_delta *delta;
606
- size_t i, *counts = NULL;
607
- uint32_t *actions = NULL;
782
+ if (!a && !b)
783
+ return 0;
784
+ else if (!a && b)
785
+ return -1;
786
+ else if(a && !b)
787
+ return 1;
788
+ else
789
+ return strcmp(a->path, b->path);
790
+ }
608
791
 
609
- if (data->opts.paths.count > 0 &&
610
- git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0)
792
+ static int checkout_conflictdata_cmp(const void *a, const void *b)
793
+ {
794
+ const checkout_conflictdata *ca = a;
795
+ const checkout_conflictdata *cb = b;
796
+ int diff;
797
+
798
+ if ((diff = checkout_idxentry_cmp(ca->ancestor, cb->ancestor)) == 0 &&
799
+ (diff = checkout_idxentry_cmp(ca->ours, cb->theirs)) == 0)
800
+ diff = checkout_idxentry_cmp(ca->theirs, cb->theirs);
801
+
802
+ return diff;
803
+ }
804
+
805
+ int checkout_conflictdata_empty(
806
+ const git_vector *conflicts, size_t idx, void *payload)
807
+ {
808
+ checkout_conflictdata *conflict;
809
+
810
+ GIT_UNUSED(payload);
811
+
812
+ if ((conflict = git_vector_get(conflicts, idx)) == NULL)
611
813
  return -1;
612
814
 
613
- if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
614
- error != GIT_ITEROVER)
615
- goto fail;
815
+ if (conflict->ancestor || conflict->ours || conflict->theirs)
816
+ return 0;
616
817
 
617
- deltas = &data->diff->deltas;
818
+ git__free(conflict);
819
+ return 1;
820
+ }
618
821
 
619
- *counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t));
620
- *actions_ptr = actions = git__calloc(
621
- deltas->length ? deltas->length : 1, sizeof(uint32_t));
622
- if (!counts || !actions) {
623
- error = -1;
624
- goto fail;
625
- }
822
+ GIT_INLINE(bool) conflict_pathspec_match(
823
+ checkout_data *data,
824
+ git_iterator *workdir,
825
+ git_vector *pathspec,
826
+ const git_index_entry *ancestor,
827
+ const git_index_entry *ours,
828
+ const git_index_entry *theirs)
829
+ {
830
+ /* if the pathspec matches ours *or* theirs, proceed */
831
+ if (ours && git_pathspec__match(pathspec, ours->path,
832
+ (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
833
+ git_iterator_ignore_case(workdir), NULL, NULL))
834
+ return true;
626
835
 
627
- git_vector_foreach(deltas, i, delta) {
628
- int act = checkout_action(data, delta, workdir, &wditem, &pathspec);
836
+ if (theirs && git_pathspec__match(pathspec, theirs->path,
837
+ (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
838
+ git_iterator_ignore_case(workdir), NULL, NULL))
839
+ return true;
629
840
 
630
- if (act < 0) {
631
- error = act;
632
- goto fail;
633
- }
841
+ if (ancestor && git_pathspec__match(pathspec, ancestor->path,
842
+ (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
843
+ git_iterator_ignore_case(workdir), NULL, NULL))
844
+ return true;
634
845
 
635
- actions[i] = act;
846
+ return false;
847
+ }
636
848
 
637
- if (act & CHECKOUT_ACTION__REMOVE)
638
- counts[CHECKOUT_ACTION__REMOVE]++;
639
- if (act & CHECKOUT_ACTION__UPDATE_BLOB)
640
- counts[CHECKOUT_ACTION__UPDATE_BLOB]++;
641
- if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE)
642
- counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++;
643
- if (act & CHECKOUT_ACTION__CONFLICT)
644
- counts[CHECKOUT_ACTION__CONFLICT]++;
645
- }
849
+ GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata *conflict)
850
+ {
851
+ conflict->submodule = ((conflict->ancestor && S_ISGITLINK(conflict->ancestor->mode)) ||
852
+ (conflict->ours && S_ISGITLINK(conflict->ours->mode)) ||
853
+ (conflict->theirs && S_ISGITLINK(conflict->theirs->mode)));
854
+ return 0;
855
+ }
646
856
 
647
- error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec);
648
- if (error < 0)
649
- goto fail;
857
+ GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict)
858
+ {
859
+ git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
860
+ int error = 0;
650
861
 
651
- counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
862
+ if (conflict->submodule)
863
+ return 0;
652
864
 
653
- if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
654
- (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
655
- {
656
- giterr_set(GITERR_CHECKOUT, "%d conflicts prevent checkout",
657
- (int)counts[CHECKOUT_ACTION__CONFLICT]);
658
- error = GIT_EMERGECONFLICT;
659
- goto fail;
865
+ if (conflict->ancestor) {
866
+ if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->id)) < 0)
867
+ goto done;
868
+
869
+ conflict->binary = git_blob_is_binary(ancestor_blob);
660
870
  }
661
871
 
662
- git_pathspec_free(&pathspec);
663
- git_pool_clear(&pathpool);
872
+ if (!conflict->binary && conflict->ours) {
873
+ if ((error = git_blob_lookup(&our_blob, repo, &conflict->ours->id)) < 0)
874
+ goto done;
664
875
 
665
- return 0;
876
+ conflict->binary = git_blob_is_binary(our_blob);
877
+ }
666
878
 
667
- fail:
668
- *counts_ptr = NULL;
669
- git__free(counts);
670
- *actions_ptr = NULL;
671
- git__free(actions);
879
+ if (!conflict->binary && conflict->theirs) {
880
+ if ((error = git_blob_lookup(&their_blob, repo, &conflict->theirs->id)) < 0)
881
+ goto done;
672
882
 
673
- git_pathspec_free(&pathspec);
674
- git_pool_clear(&pathpool);
883
+ conflict->binary = git_blob_is_binary(their_blob);
884
+ }
885
+
886
+ done:
887
+ git_blob_free(ancestor_blob);
888
+ git_blob_free(our_blob);
889
+ git_blob_free(their_blob);
675
890
 
676
891
  return error;
677
892
  }
678
893
 
679
- static int buffer_to_file(
680
- struct stat *st,
681
- git_buf *buffer,
682
- const char *path,
683
- mode_t dir_mode,
684
- int file_open_flags,
685
- mode_t file_mode)
894
+ static int checkout_conflict_append_update(
895
+ const git_index_entry *ancestor,
896
+ const git_index_entry *ours,
897
+ const git_index_entry *theirs,
898
+ void *payload)
686
899
  {
900
+ checkout_data *data = payload;
901
+ checkout_conflictdata *conflict;
687
902
  int error;
688
903
 
689
- if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
690
- return error;
904
+ conflict = git__calloc(1, sizeof(checkout_conflictdata));
905
+ GIT_ERROR_CHECK_ALLOC(conflict);
691
906
 
692
- if ((error = git_futils_writebuffer(
693
- buffer, path, file_open_flags, file_mode)) < 0)
694
- return error;
907
+ conflict->ancestor = ancestor;
908
+ conflict->ours = ours;
909
+ conflict->theirs = theirs;
695
910
 
696
- if (st != NULL && (error = p_stat(path, st)) < 0) {
697
- giterr_set(GITERR_OS, "Error while statting '%s'", path);
911
+ if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
912
+ (error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
913
+ {
914
+ git__free(conflict);
698
915
  return error;
699
916
  }
700
917
 
701
- if ((file_mode & 0100) != 0 && (error = p_chmod(path, file_mode)) < 0) {
702
- giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
703
- return error;
704
- }
918
+ if (git_vector_insert(&data->update_conflicts, conflict))
919
+ return -1;
705
920
 
706
921
  return 0;
707
922
  }
708
923
 
709
- static int blob_content_to_file(
710
- struct stat *st,
711
- git_blob *blob,
712
- const char *path,
713
- mode_t entry_filemode,
714
- git_checkout_opts *opts)
715
- {
716
- int error = -1, nb_filters = 0;
717
- mode_t file_mode = opts->file_mode;
718
- bool dont_free_filtered;
719
- git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
720
- git_vector filters = GIT_VECTOR_INIT;
721
-
722
- /* Create a fake git_buf from the blob raw data... */
723
- filtered.ptr = (void *)git_blob_rawcontent(blob);
724
- filtered.size = (size_t)git_blob_rawsize(blob);
725
- /* ... and make sure it doesn't get unexpectedly freed */
726
- dont_free_filtered = true;
727
-
728
- if (!opts->disable_filters &&
729
- !git_buf_text_is_binary(&filtered) &&
730
- (nb_filters = git_filters_load(
731
- &filters,
732
- git_object_owner((git_object *)blob),
733
- path,
734
- GIT_FILTER_TO_WORKTREE)) > 0)
735
- {
736
- /* reset 'filtered' so it can be a filter target */
737
- git_buf_init(&filtered, 0);
738
- dont_free_filtered = false;
739
- }
924
+ static int checkout_conflicts_foreach(
925
+ checkout_data *data,
926
+ git_index *index,
927
+ git_iterator *workdir,
928
+ git_vector *pathspec,
929
+ int (*cb)(const git_index_entry *, const git_index_entry *, const git_index_entry *, void *),
930
+ void *payload)
931
+ {
932
+ git_index_conflict_iterator *iterator = NULL;
933
+ const git_index_entry *ancestor, *ours, *theirs;
934
+ int error = 0;
740
935
 
741
- if (nb_filters < 0)
742
- return nb_filters;
936
+ if ((error = git_index_conflict_iterator_new(&iterator, index)) < 0)
937
+ goto done;
743
938
 
744
- if (nb_filters > 0) {
745
- if ((error = git_blob__getbuf(&unfiltered, blob)) < 0)
746
- goto cleanup;
939
+ /* Collect the conflicts */
940
+ while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) {
941
+ if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs))
942
+ continue;
747
943
 
748
- if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0)
749
- goto cleanup;
944
+ if ((error = cb(ancestor, ours, theirs, payload)) < 0)
945
+ goto done;
750
946
  }
751
947
 
752
- /* Allow overriding of file mode */
753
- if (!file_mode)
754
- file_mode = entry_filemode;
755
-
756
- error = buffer_to_file(
757
- st, &filtered, path, opts->dir_mode, opts->file_open_flags, file_mode);
758
-
759
- if (!error)
760
- st->st_mode = entry_filemode;
948
+ if (error == GIT_ITEROVER)
949
+ error = 0;
761
950
 
762
- cleanup:
763
- git_filters_free(&filters);
764
- git_buf_free(&unfiltered);
765
- if (!dont_free_filtered)
766
- git_buf_free(&filtered);
951
+ done:
952
+ git_index_conflict_iterator_free(iterator);
767
953
 
768
954
  return error;
769
955
  }
770
956
 
771
- static int blob_content_to_link(
772
- struct stat *st,
773
- git_blob *blob,
774
- const char *path,
775
- mode_t dir_mode,
776
- int can_symlink)
957
+ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
777
958
  {
778
- git_buf linktarget = GIT_BUF_INIT;
779
- int error;
780
-
781
- if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
782
- return error;
959
+ git_index *index;
783
960
 
784
- if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
785
- return error;
961
+ /* Only write conficts from sources that have them: indexes. */
962
+ if ((index = git_iterator_index(data->target)) == NULL)
963
+ return 0;
786
964
 
787
- if (can_symlink) {
788
- if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
789
- giterr_set(GITERR_OS, "Could not create symlink %s\n", path);
790
- } else {
791
- error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
792
- }
965
+ data->update_conflicts._cmp = checkout_conflictdata_cmp;
793
966
 
794
- if (!error) {
795
- if ((error = p_lstat(path, st)) < 0)
796
- giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
967
+ if (checkout_conflicts_foreach(data, index, workdir, pathspec, checkout_conflict_append_update, data) < 0)
968
+ return -1;
797
969
 
798
- st->st_mode = GIT_FILEMODE_LINK;
799
- }
970
+ /* Collect the REUC and NAME entries */
971
+ data->update_reuc = &index->reuc;
972
+ data->update_names = &index->names;
800
973
 
801
- git_buf_free(&linktarget);
974
+ return 0;
975
+ }
802
976
 
803
- return error;
977
+ GIT_INLINE(int) checkout_conflicts_cmp_entry(
978
+ const char *path,
979
+ const git_index_entry *entry)
980
+ {
981
+ return strcmp((const char *)path, entry->path);
804
982
  }
805
983
 
806
- static int checkout_update_index(
807
- checkout_data *data,
984
+ static int checkout_conflicts_cmp_ancestor(const void *p, const void *c)
985
+ {
986
+ const char *path = p;
987
+ const checkout_conflictdata *conflict = c;
988
+
989
+ if (!conflict->ancestor)
990
+ return 1;
991
+
992
+ return checkout_conflicts_cmp_entry(path, conflict->ancestor);
993
+ }
994
+
995
+ static checkout_conflictdata *checkout_conflicts_search_ancestor(
996
+ checkout_data *data,
997
+ const char *path)
998
+ {
999
+ size_t pos;
1000
+
1001
+ if (git_vector_bsearch2(&pos, &data->update_conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
1002
+ return NULL;
1003
+
1004
+ return git_vector_get(&data->update_conflicts, pos);
1005
+ }
1006
+
1007
+ static checkout_conflictdata *checkout_conflicts_search_branch(
1008
+ checkout_data *data,
1009
+ const char *path)
1010
+ {
1011
+ checkout_conflictdata *conflict;
1012
+ size_t i;
1013
+
1014
+ git_vector_foreach(&data->update_conflicts, i, conflict) {
1015
+ int cmp = -1;
1016
+
1017
+ if (conflict->ancestor)
1018
+ break;
1019
+
1020
+ if (conflict->ours)
1021
+ cmp = checkout_conflicts_cmp_entry(path, conflict->ours);
1022
+ else if (conflict->theirs)
1023
+ cmp = checkout_conflicts_cmp_entry(path, conflict->theirs);
1024
+
1025
+ if (cmp == 0)
1026
+ return conflict;
1027
+ }
1028
+
1029
+ return NULL;
1030
+ }
1031
+
1032
+ static int checkout_conflicts_load_byname_entry(
1033
+ checkout_conflictdata **ancestor_out,
1034
+ checkout_conflictdata **ours_out,
1035
+ checkout_conflictdata **theirs_out,
1036
+ checkout_data *data,
1037
+ const git_index_name_entry *name_entry)
1038
+ {
1039
+ checkout_conflictdata *ancestor, *ours = NULL, *theirs = NULL;
1040
+ int error = 0;
1041
+
1042
+ *ancestor_out = NULL;
1043
+ *ours_out = NULL;
1044
+ *theirs_out = NULL;
1045
+
1046
+ if (!name_entry->ancestor) {
1047
+ git_error_set(GIT_ERROR_INDEX, "a NAME entry exists without an ancestor");
1048
+ error = -1;
1049
+ goto done;
1050
+ }
1051
+
1052
+ if (!name_entry->ours && !name_entry->theirs) {
1053
+ git_error_set(GIT_ERROR_INDEX, "a NAME entry exists without an ours or theirs");
1054
+ error = -1;
1055
+ goto done;
1056
+ }
1057
+
1058
+ if ((ancestor = checkout_conflicts_search_ancestor(data,
1059
+ name_entry->ancestor)) == NULL) {
1060
+ git_error_set(GIT_ERROR_INDEX,
1061
+ "a NAME entry referenced ancestor entry '%s' which does not exist in the main index",
1062
+ name_entry->ancestor);
1063
+ error = -1;
1064
+ goto done;
1065
+ }
1066
+
1067
+ if (name_entry->ours) {
1068
+ if (strcmp(name_entry->ancestor, name_entry->ours) == 0)
1069
+ ours = ancestor;
1070
+ else if ((ours = checkout_conflicts_search_branch(data, name_entry->ours)) == NULL ||
1071
+ ours->ours == NULL) {
1072
+ git_error_set(GIT_ERROR_INDEX,
1073
+ "a NAME entry referenced our entry '%s' which does not exist in the main index",
1074
+ name_entry->ours);
1075
+ error = -1;
1076
+ goto done;
1077
+ }
1078
+ }
1079
+
1080
+ if (name_entry->theirs) {
1081
+ if (strcmp(name_entry->ancestor, name_entry->theirs) == 0)
1082
+ theirs = ancestor;
1083
+ else if (name_entry->ours && strcmp(name_entry->ours, name_entry->theirs) == 0)
1084
+ theirs = ours;
1085
+ else if ((theirs = checkout_conflicts_search_branch(data, name_entry->theirs)) == NULL ||
1086
+ theirs->theirs == NULL) {
1087
+ git_error_set(GIT_ERROR_INDEX,
1088
+ "a NAME entry referenced their entry '%s' which does not exist in the main index",
1089
+ name_entry->theirs);
1090
+ error = -1;
1091
+ goto done;
1092
+ }
1093
+ }
1094
+
1095
+ *ancestor_out = ancestor;
1096
+ *ours_out = ours;
1097
+ *theirs_out = theirs;
1098
+
1099
+ done:
1100
+ return error;
1101
+ }
1102
+
1103
+ static int checkout_conflicts_coalesce_renames(
1104
+ checkout_data *data)
1105
+ {
1106
+ git_index *index;
1107
+ const git_index_name_entry *name_entry;
1108
+ checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict;
1109
+ size_t i, names;
1110
+ int error = 0;
1111
+
1112
+ if ((index = git_iterator_index(data->target)) == NULL)
1113
+ return 0;
1114
+
1115
+ /* Juggle entries based on renames */
1116
+ names = git_index_name_entrycount(index);
1117
+
1118
+ for (i = 0; i < names; i++) {
1119
+ name_entry = git_index_name_get_byindex(index, i);
1120
+
1121
+ if ((error = checkout_conflicts_load_byname_entry(
1122
+ &ancestor_conflict, &our_conflict, &their_conflict,
1123
+ data, name_entry)) < 0)
1124
+ goto done;
1125
+
1126
+ if (our_conflict && our_conflict != ancestor_conflict) {
1127
+ ancestor_conflict->ours = our_conflict->ours;
1128
+ our_conflict->ours = NULL;
1129
+
1130
+ if (our_conflict->theirs)
1131
+ our_conflict->name_collision = 1;
1132
+
1133
+ if (our_conflict->name_collision)
1134
+ ancestor_conflict->name_collision = 1;
1135
+ }
1136
+
1137
+ if (their_conflict && their_conflict != ancestor_conflict) {
1138
+ ancestor_conflict->theirs = their_conflict->theirs;
1139
+ their_conflict->theirs = NULL;
1140
+
1141
+ if (their_conflict->ours)
1142
+ their_conflict->name_collision = 1;
1143
+
1144
+ if (their_conflict->name_collision)
1145
+ ancestor_conflict->name_collision = 1;
1146
+ }
1147
+
1148
+ if (our_conflict && our_conflict != ancestor_conflict &&
1149
+ their_conflict && their_conflict != ancestor_conflict)
1150
+ ancestor_conflict->one_to_two = 1;
1151
+ }
1152
+
1153
+ git_vector_remove_matching(
1154
+ &data->update_conflicts, checkout_conflictdata_empty, NULL);
1155
+
1156
+ done:
1157
+ return error;
1158
+ }
1159
+
1160
+ static int checkout_conflicts_mark_directoryfile(
1161
+ checkout_data *data)
1162
+ {
1163
+ git_index *index;
1164
+ checkout_conflictdata *conflict;
1165
+ const git_index_entry *entry;
1166
+ size_t i, j, len;
1167
+ const char *path;
1168
+ int prefixed, error = 0;
1169
+
1170
+ if ((index = git_iterator_index(data->target)) == NULL)
1171
+ return 0;
1172
+
1173
+ len = git_index_entrycount(index);
1174
+
1175
+ /* Find d/f conflicts */
1176
+ git_vector_foreach(&data->update_conflicts, i, conflict) {
1177
+ if ((conflict->ours && conflict->theirs) ||
1178
+ (!conflict->ours && !conflict->theirs))
1179
+ continue;
1180
+
1181
+ path = conflict->ours ?
1182
+ conflict->ours->path : conflict->theirs->path;
1183
+
1184
+ if ((error = git_index_find(&j, index, path)) < 0) {
1185
+ if (error == GIT_ENOTFOUND)
1186
+ git_error_set(GIT_ERROR_INDEX,
1187
+ "index inconsistency, could not find entry for expected conflict '%s'", path);
1188
+
1189
+ goto done;
1190
+ }
1191
+
1192
+ for (; j < len; j++) {
1193
+ if ((entry = git_index_get_byindex(index, j)) == NULL) {
1194
+ git_error_set(GIT_ERROR_INDEX,
1195
+ "index inconsistency, truncated index while loading expected conflict '%s'", path);
1196
+ error = -1;
1197
+ goto done;
1198
+ }
1199
+
1200
+ prefixed = git_path_equal_or_prefixed(path, entry->path, NULL);
1201
+
1202
+ if (prefixed == GIT_PATH_EQUAL)
1203
+ continue;
1204
+
1205
+ if (prefixed == GIT_PATH_PREFIX)
1206
+ conflict->directoryfile = 1;
1207
+
1208
+ break;
1209
+ }
1210
+ }
1211
+
1212
+ done:
1213
+ return error;
1214
+ }
1215
+
1216
+ static int checkout_get_update_conflicts(
1217
+ checkout_data *data,
1218
+ git_iterator *workdir,
1219
+ git_vector *pathspec)
1220
+ {
1221
+ int error = 0;
1222
+
1223
+ if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED)
1224
+ return 0;
1225
+
1226
+ if ((error = checkout_conflicts_load(data, workdir, pathspec)) < 0 ||
1227
+ (error = checkout_conflicts_coalesce_renames(data)) < 0 ||
1228
+ (error = checkout_conflicts_mark_directoryfile(data)) < 0)
1229
+ goto done;
1230
+
1231
+ done:
1232
+ return error;
1233
+ }
1234
+
1235
+ static int checkout_conflict_append_remove(
1236
+ const git_index_entry *ancestor,
1237
+ const git_index_entry *ours,
1238
+ const git_index_entry *theirs,
1239
+ void *payload)
1240
+ {
1241
+ checkout_data *data = payload;
1242
+ const char *name;
1243
+
1244
+ assert(ancestor || ours || theirs);
1245
+
1246
+ if (ancestor)
1247
+ name = git__strdup(ancestor->path);
1248
+ else if (ours)
1249
+ name = git__strdup(ours->path);
1250
+ else if (theirs)
1251
+ name = git__strdup(theirs->path);
1252
+ else
1253
+ abort();
1254
+
1255
+ GIT_ERROR_CHECK_ALLOC(name);
1256
+
1257
+ return git_vector_insert(&data->remove_conflicts, (char *)name);
1258
+ }
1259
+
1260
+ static int checkout_get_remove_conflicts(
1261
+ checkout_data *data,
1262
+ git_iterator *workdir,
1263
+ git_vector *pathspec)
1264
+ {
1265
+ if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0)
1266
+ return 0;
1267
+
1268
+ return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data);
1269
+ }
1270
+
1271
+ static int checkout_verify_paths(
1272
+ git_repository *repo,
1273
+ int action,
1274
+ git_diff_delta *delta)
1275
+ {
1276
+ unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
1277
+
1278
+ if (action & CHECKOUT_ACTION__REMOVE) {
1279
+ if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) {
1280
+ git_error_set(GIT_ERROR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
1281
+ return -1;
1282
+ }
1283
+ }
1284
+
1285
+ if (action & ~CHECKOUT_ACTION__REMOVE) {
1286
+ if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) {
1287
+ git_error_set(GIT_ERROR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
1288
+ return -1;
1289
+ }
1290
+ }
1291
+
1292
+ return 0;
1293
+ }
1294
+
1295
+ static int checkout_get_actions(
1296
+ uint32_t **actions_ptr,
1297
+ size_t **counts_ptr,
1298
+ checkout_data *data,
1299
+ git_iterator *workdir)
1300
+ {
1301
+ int error = 0, act;
1302
+ const git_index_entry *wditem;
1303
+ git_vector pathspec = GIT_VECTOR_INIT, *deltas;
1304
+ git_pool pathpool;
1305
+ git_diff_delta *delta;
1306
+ size_t i, *counts = NULL;
1307
+ uint32_t *actions = NULL;
1308
+
1309
+ git_pool_init(&pathpool, 1);
1310
+
1311
+ if (data->opts.paths.count > 0 &&
1312
+ git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
1313
+ return -1;
1314
+
1315
+ if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
1316
+ error != GIT_ITEROVER)
1317
+ goto fail;
1318
+
1319
+ deltas = &data->diff->deltas;
1320
+
1321
+ *counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t));
1322
+ *actions_ptr = actions = git__calloc(
1323
+ deltas->length ? deltas->length : 1, sizeof(uint32_t));
1324
+ if (!counts || !actions) {
1325
+ error = -1;
1326
+ goto fail;
1327
+ }
1328
+
1329
+ git_vector_foreach(deltas, i, delta) {
1330
+ if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0)
1331
+ error = checkout_verify_paths(data->repo, act, delta);
1332
+
1333
+ if (error != 0)
1334
+ goto fail;
1335
+
1336
+ actions[i] = act;
1337
+
1338
+ if (act & CHECKOUT_ACTION__REMOVE)
1339
+ counts[CHECKOUT_ACTION__REMOVE]++;
1340
+ if (act & CHECKOUT_ACTION__UPDATE_BLOB)
1341
+ counts[CHECKOUT_ACTION__UPDATE_BLOB]++;
1342
+ if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE)
1343
+ counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++;
1344
+ if (act & CHECKOUT_ACTION__CONFLICT)
1345
+ counts[CHECKOUT_ACTION__CONFLICT]++;
1346
+ }
1347
+
1348
+ error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec);
1349
+ if (error)
1350
+ goto fail;
1351
+
1352
+ counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
1353
+
1354
+ if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
1355
+ (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
1356
+ {
1357
+ git_error_set(GIT_ERROR_CHECKOUT, "%"PRIuZ" %s checkout",
1358
+ counts[CHECKOUT_ACTION__CONFLICT],
1359
+ counts[CHECKOUT_ACTION__CONFLICT] == 1 ?
1360
+ "conflict prevents" : "conflicts prevent");
1361
+ error = GIT_ECONFLICT;
1362
+ goto fail;
1363
+ }
1364
+
1365
+
1366
+ if ((error = checkout_get_remove_conflicts(data, workdir, &pathspec)) < 0 ||
1367
+ (error = checkout_get_update_conflicts(data, workdir, &pathspec)) < 0)
1368
+ goto fail;
1369
+
1370
+ counts[CHECKOUT_ACTION__REMOVE_CONFLICT] = git_vector_length(&data->remove_conflicts);
1371
+ counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->update_conflicts);
1372
+
1373
+ git_pathspec__vfree(&pathspec);
1374
+ git_pool_clear(&pathpool);
1375
+
1376
+ return 0;
1377
+
1378
+ fail:
1379
+ *counts_ptr = NULL;
1380
+ git__free(counts);
1381
+ *actions_ptr = NULL;
1382
+ git__free(actions);
1383
+
1384
+ git_pathspec__vfree(&pathspec);
1385
+ git_pool_clear(&pathpool);
1386
+
1387
+ return error;
1388
+ }
1389
+
1390
+ static bool should_remove_existing(checkout_data *data)
1391
+ {
1392
+ int ignorecase;
1393
+
1394
+ if (git_repository__cvar(&ignorecase, data->repo, GIT_CVAR_IGNORECASE) < 0) {
1395
+ ignorecase = 0;
1396
+ }
1397
+
1398
+ return (ignorecase &&
1399
+ (data->strategy & GIT_CHECKOUT_DONT_REMOVE_EXISTING) == 0);
1400
+ }
1401
+
1402
+ #define MKDIR_NORMAL \
1403
+ GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR
1404
+ #define MKDIR_REMOVE_EXISTING \
1405
+ MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
1406
+
1407
+ static int checkout_mkdir(
1408
+ checkout_data *data,
1409
+ const char *path,
1410
+ const char *base,
1411
+ mode_t mode,
1412
+ unsigned int flags)
1413
+ {
1414
+ struct git_futils_mkdir_options mkdir_opts = {0};
1415
+ int error;
1416
+
1417
+ mkdir_opts.dir_map = data->mkdir_map;
1418
+ mkdir_opts.pool = &data->pool;
1419
+
1420
+ error = git_futils_mkdir_relative(
1421
+ path, base, mode, flags, &mkdir_opts);
1422
+
1423
+ data->perfdata.mkdir_calls += mkdir_opts.perfdata.mkdir_calls;
1424
+ data->perfdata.stat_calls += mkdir_opts.perfdata.stat_calls;
1425
+ data->perfdata.chmod_calls += mkdir_opts.perfdata.chmod_calls;
1426
+
1427
+ return error;
1428
+ }
1429
+
1430
+ static int mkpath2file(
1431
+ checkout_data *data, const char *path, unsigned int mode)
1432
+ {
1433
+ struct stat st;
1434
+ bool remove_existing = should_remove_existing(data);
1435
+ unsigned int flags =
1436
+ (remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL) |
1437
+ GIT_MKDIR_SKIP_LAST;
1438
+ int error;
1439
+
1440
+ if ((error = checkout_mkdir(
1441
+ data, path, data->opts.target_directory, mode, flags)) < 0)
1442
+ return error;
1443
+
1444
+ if (remove_existing) {
1445
+ data->perfdata.stat_calls++;
1446
+
1447
+ if (p_lstat(path, &st) == 0) {
1448
+
1449
+ /* Some file, symlink or folder already exists at this name.
1450
+ * We would have removed it in remove_the_old unless we're on
1451
+ * a case inensitive filesystem (or the user has asked us not
1452
+ * to). Remove the similarly named file to write the new.
1453
+ */
1454
+ error = git_futils_rmdir_r(path, NULL, GIT_RMDIR_REMOVE_FILES);
1455
+ } else if (errno != ENOENT) {
1456
+ git_error_set(GIT_ERROR_OS, "failed to stat '%s'", path);
1457
+ return GIT_EEXISTS;
1458
+ } else {
1459
+ git_error_clear();
1460
+ }
1461
+ }
1462
+
1463
+ return error;
1464
+ }
1465
+
1466
+ struct checkout_stream {
1467
+ git_writestream base;
1468
+ const char *path;
1469
+ int fd;
1470
+ int open;
1471
+ };
1472
+
1473
+ static int checkout_stream_write(
1474
+ git_writestream *s, const char *buffer, size_t len)
1475
+ {
1476
+ struct checkout_stream *stream = (struct checkout_stream *)s;
1477
+ int ret;
1478
+
1479
+ if ((ret = p_write(stream->fd, buffer, len)) < 0)
1480
+ git_error_set(GIT_ERROR_OS, "could not write to '%s'", stream->path);
1481
+
1482
+ return ret;
1483
+ }
1484
+
1485
+ static int checkout_stream_close(git_writestream *s)
1486
+ {
1487
+ struct checkout_stream *stream = (struct checkout_stream *)s;
1488
+ assert(stream && stream->open);
1489
+
1490
+ stream->open = 0;
1491
+ return p_close(stream->fd);
1492
+ }
1493
+
1494
+ static void checkout_stream_free(git_writestream *s)
1495
+ {
1496
+ GIT_UNUSED(s);
1497
+ }
1498
+
1499
+ static int blob_content_to_file(
1500
+ checkout_data *data,
1501
+ struct stat *st,
1502
+ git_blob *blob,
1503
+ const char *path,
1504
+ const char *hint_path,
1505
+ mode_t entry_filemode)
1506
+ {
1507
+ int flags = data->opts.file_open_flags;
1508
+ mode_t file_mode = data->opts.file_mode ?
1509
+ data->opts.file_mode : entry_filemode;
1510
+ git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
1511
+ struct checkout_stream writer;
1512
+ mode_t mode;
1513
+ git_filter_list *fl = NULL;
1514
+ int fd;
1515
+ int error = 0;
1516
+
1517
+ if (hint_path == NULL)
1518
+ hint_path = path;
1519
+
1520
+ if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
1521
+ return error;
1522
+
1523
+ if (flags <= 0)
1524
+ flags = O_CREAT | O_TRUNC | O_WRONLY;
1525
+ if (!(mode = file_mode))
1526
+ mode = GIT_FILEMODE_BLOB;
1527
+
1528
+ if ((fd = p_open(path, flags, mode)) < 0) {
1529
+ git_error_set(GIT_ERROR_OS, "could not open '%s' for writing", path);
1530
+ return fd;
1531
+ }
1532
+
1533
+ filter_opts.attr_session = &data->attr_session;
1534
+ filter_opts.temp_buf = &data->tmp;
1535
+
1536
+ if (!data->opts.disable_filters &&
1537
+ (error = git_filter_list__load_ext(
1538
+ &fl, data->repo, blob, hint_path,
1539
+ GIT_FILTER_TO_WORKTREE, &filter_opts))) {
1540
+ p_close(fd);
1541
+ return error;
1542
+ }
1543
+
1544
+ /* setup the writer */
1545
+ memset(&writer, 0, sizeof(struct checkout_stream));
1546
+ writer.base.write = checkout_stream_write;
1547
+ writer.base.close = checkout_stream_close;
1548
+ writer.base.free = checkout_stream_free;
1549
+ writer.path = path;
1550
+ writer.fd = fd;
1551
+ writer.open = 1;
1552
+
1553
+ error = git_filter_list_stream_blob(fl, blob, &writer.base);
1554
+
1555
+ assert(writer.open == 0);
1556
+
1557
+ git_filter_list_free(fl);
1558
+
1559
+ if (error < 0)
1560
+ return error;
1561
+
1562
+ if (st) {
1563
+ data->perfdata.stat_calls++;
1564
+
1565
+ if ((error = p_stat(path, st)) < 0) {
1566
+ git_error_set(GIT_ERROR_OS, "failed to stat '%s'", path);
1567
+ return error;
1568
+ }
1569
+
1570
+ st->st_mode = entry_filemode;
1571
+ }
1572
+
1573
+ return 0;
1574
+ }
1575
+
1576
+ static int blob_content_to_link(
1577
+ checkout_data *data,
1578
+ struct stat *st,
1579
+ git_blob *blob,
1580
+ const char *path)
1581
+ {
1582
+ git_buf linktarget = GIT_BUF_INIT;
1583
+ int error;
1584
+
1585
+ if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
1586
+ return error;
1587
+
1588
+ if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
1589
+ return error;
1590
+
1591
+ if (data->can_symlink) {
1592
+ if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
1593
+ git_error_set(GIT_ERROR_OS, "could not create symlink %s", path);
1594
+ } else {
1595
+ error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
1596
+ }
1597
+
1598
+ if (!error) {
1599
+ data->perfdata.stat_calls++;
1600
+
1601
+ if ((error = p_lstat(path, st)) < 0)
1602
+ git_error_set(GIT_ERROR_CHECKOUT, "could not stat symlink %s", path);
1603
+
1604
+ st->st_mode = GIT_FILEMODE_LINK;
1605
+ }
1606
+
1607
+ git_buf_dispose(&linktarget);
1608
+
1609
+ return error;
1610
+ }
1611
+
1612
+ static int checkout_update_index(
1613
+ checkout_data *data,
808
1614
  const git_diff_file *file,
809
1615
  struct stat *st)
810
1616
  {
@@ -815,8 +1621,8 @@ static int checkout_update_index(
815
1621
 
816
1622
  memset(&entry, 0, sizeof(entry));
817
1623
  entry.path = (char *)file->path; /* cast to prevent warning */
818
- git_index_entry__init_from_stat(&entry, st);
819
- git_oid_cpy(&entry.oid, &file->oid);
1624
+ git_index_entry__init_from_stat(&entry, st, true);
1625
+ git_oid_cpy(&entry.id, &file->id);
820
1626
 
821
1627
  return git_index_add(data->index, &entry);
822
1628
  }
@@ -825,19 +1631,20 @@ static int checkout_submodule_update_index(
825
1631
  checkout_data *data,
826
1632
  const git_diff_file *file)
827
1633
  {
1634
+ git_buf *fullpath;
828
1635
  struct stat st;
829
1636
 
830
1637
  /* update the index unless prevented */
831
1638
  if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0)
832
1639
  return 0;
833
1640
 
834
- git_buf_truncate(&data->path, data->workdir_len);
835
- if (git_buf_puts(&data->path, file->path) < 0)
1641
+ if (checkout_target_fullpath(&fullpath, data, file->path) < 0)
836
1642
  return -1;
837
1643
 
838
- if (p_stat(git_buf_cstr(&data->path), &st) < 0) {
839
- giterr_set(
840
- GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
1644
+ data->perfdata.stat_calls++;
1645
+ if (p_stat(fullpath->ptr, &st) < 0) {
1646
+ git_error_set(
1647
+ GIT_ERROR_CHECKOUT, "could not stat submodule %s\n", file->path);
841
1648
  return GIT_ENOTFOUND;
842
1649
  }
843
1650
 
@@ -850,24 +1657,25 @@ static int checkout_submodule(
850
1657
  checkout_data *data,
851
1658
  const git_diff_file *file)
852
1659
  {
1660
+ bool remove_existing = should_remove_existing(data);
853
1661
  int error = 0;
854
- git_submodule *sm;
855
1662
 
856
1663
  /* Until submodules are supported, UPDATE_ONLY means do nothing here */
857
1664
  if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
858
1665
  return 0;
859
1666
 
860
- if ((error = git_futils_mkdir(
861
- file->path, data->opts.target_directory,
862
- data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
1667
+ if ((error = checkout_mkdir(
1668
+ data,
1669
+ file->path, data->opts.target_directory, data->opts.dir_mode,
1670
+ remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL)) < 0)
863
1671
  return error;
864
1672
 
865
- if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0) {
1673
+ if ((error = git_submodule_lookup(NULL, data->repo, file->path)) < 0) {
866
1674
  /* I've observed repos with submodules in the tree that do not
867
1675
  * have a .gitmodules - core Git just makes an empty directory
868
1676
  */
869
1677
  if (error == GIT_ENOTFOUND) {
870
- giterr_clear();
1678
+ git_error_clear();
871
1679
  return checkout_submodule_update_index(data, file);
872
1680
  }
873
1681
 
@@ -896,17 +1704,20 @@ static void report_progress(
896
1704
  data->opts.progress_payload);
897
1705
  }
898
1706
 
899
- static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
1707
+ static int checkout_safe_for_update_only(
1708
+ checkout_data *data, const char *path, mode_t expected_mode)
900
1709
  {
901
1710
  struct stat st;
902
1711
 
1712
+ data->perfdata.stat_calls++;
1713
+
903
1714
  if (p_lstat(path, &st) < 0) {
904
1715
  /* if doesn't exist, then no error and no update */
905
1716
  if (errno == ENOENT || errno == ENOTDIR)
906
1717
  return 0;
907
1718
 
908
1719
  /* otherwise, stat error and no update */
909
- giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
1720
+ git_error_set(GIT_ERROR_OS, "failed to stat '%s'", path);
910
1721
  return -1;
911
1722
  }
912
1723
 
@@ -917,47 +1728,62 @@ static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
917
1728
  return 0;
918
1729
  }
919
1730
 
920
- static int checkout_blob(
1731
+ static int checkout_write_content(
921
1732
  checkout_data *data,
922
- const git_diff_file *file)
1733
+ const git_oid *oid,
1734
+ const char *full_path,
1735
+ const char *hint_path,
1736
+ unsigned int mode,
1737
+ struct stat *st)
923
1738
  {
924
1739
  int error = 0;
925
1740
  git_blob *blob;
1741
+
1742
+ if ((error = git_blob_lookup(&blob, data->repo, oid)) < 0)
1743
+ return error;
1744
+
1745
+ if (S_ISLNK(mode))
1746
+ error = blob_content_to_link(data, st, blob, full_path);
1747
+ else
1748
+ error = blob_content_to_file(data, st, blob, full_path, hint_path, mode);
1749
+
1750
+ git_blob_free(blob);
1751
+
1752
+ /* if we try to create the blob and an existing directory blocks it from
1753
+ * being written, then there must have been a typechange conflict in a
1754
+ * parent directory - suppress the error and try to continue.
1755
+ */
1756
+ if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 &&
1757
+ (error == GIT_ENOTFOUND || error == GIT_EEXISTS))
1758
+ {
1759
+ git_error_clear();
1760
+ error = 0;
1761
+ }
1762
+
1763
+ return error;
1764
+ }
1765
+
1766
+ static int checkout_blob(
1767
+ checkout_data *data,
1768
+ const git_diff_file *file)
1769
+ {
1770
+ git_buf *fullpath;
926
1771
  struct stat st;
1772
+ int error = 0;
927
1773
 
928
- git_buf_truncate(&data->path, data->workdir_len);
929
- if (git_buf_puts(&data->path, file->path) < 0)
1774
+ if (checkout_target_fullpath(&fullpath, data, file->path) < 0)
930
1775
  return -1;
931
1776
 
932
1777
  if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
933
1778
  int rval = checkout_safe_for_update_only(
934
- git_buf_cstr(&data->path), file->mode);
1779
+ data, fullpath->ptr, file->mode);
1780
+
935
1781
  if (rval <= 0)
936
1782
  return rval;
937
1783
  }
938
1784
 
939
- if ((error = git_blob_lookup(&blob, data->repo, &file->oid)) < 0)
940
- return error;
941
-
942
- if (S_ISLNK(file->mode))
943
- error = blob_content_to_link(
944
- &st, blob, git_buf_cstr(&data->path), data->opts.dir_mode, data->can_symlink);
945
- else
946
- error = blob_content_to_file(
947
- &st, blob, git_buf_cstr(&data->path), file->mode, &data->opts);
948
-
949
- git_blob_free(blob);
950
-
951
- /* if we try to create the blob and an existing directory blocks it from
952
- * being written, then there must have been a typechange conflict in a
953
- * parent directory - suppress the error and try to continue.
954
- */
955
- if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 &&
956
- (error == GIT_ENOTFOUND || error == GIT_EEXISTS))
957
- {
958
- giterr_clear();
959
- error = 0;
960
- }
1785
+ error = checkout_write_content(
1786
+ data, &file->id, fullpath->ptr, NULL, file->mode, &st);
961
1787
 
962
1788
  /* update the index unless prevented */
963
1789
  if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
@@ -978,18 +1804,21 @@ static int checkout_remove_the_old(
978
1804
  git_diff_delta *delta;
979
1805
  const char *str;
980
1806
  size_t i;
981
- const char *workdir = git_buf_cstr(&data->path);
1807
+ git_buf *fullpath;
982
1808
  uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
983
1809
  GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
984
1810
 
985
1811
  if (data->opts.checkout_strategy & GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES)
986
1812
  flg |= GIT_RMDIR_SKIP_NONEMPTY;
987
1813
 
988
- git_buf_truncate(&data->path, data->workdir_len);
1814
+ if (checkout_target_fullpath(&fullpath, data, NULL) < 0)
1815
+ return -1;
989
1816
 
990
1817
  git_vector_foreach(&data->diff->deltas, i, delta) {
991
1818
  if (actions[i] & CHECKOUT_ACTION__REMOVE) {
992
- error = git_futils_rmdir_r(delta->old_file.path, workdir, flg);
1819
+ error = git_futils_rmdir_r(
1820
+ delta->old_file.path, fullpath->ptr, flg);
1821
+
993
1822
  if (error < 0)
994
1823
  return error;
995
1824
 
@@ -1006,7 +1835,7 @@ static int checkout_remove_the_old(
1006
1835
  }
1007
1836
 
1008
1837
  git_vector_foreach(&data->removes, i, str) {
1009
- error = git_futils_rmdir_r(str, workdir, flg);
1838
+ error = git_futils_rmdir_r(str, fullpath->ptr, flg);
1010
1839
  if (error < 0)
1011
1840
  return error;
1012
1841
 
@@ -1034,7 +1863,7 @@ static int checkout_deferred_remove(git_repository *repo, const char *path)
1034
1863
 
1035
1864
  if (error == GIT_ENOTFOUND) {
1036
1865
  error = 0;
1037
- giterr_clear();
1866
+ git_error_clear();
1038
1867
  }
1039
1868
 
1040
1869
  return error;
@@ -1085,11 +1914,6 @@ static int checkout_create_submodules(
1085
1914
  git_diff_delta *delta;
1086
1915
  size_t i;
1087
1916
 
1088
- /* initial reload of submodules if .gitmodules was changed */
1089
- if (data->reload_submodules &&
1090
- (error = git_submodule_reload_all(data->repo)) < 0)
1091
- return error;
1092
-
1093
1917
  git_vector_foreach(&data->diff->deltas, i, delta) {
1094
1918
  if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1095
1919
  /* this has a blocker directory that should only be removed iff
@@ -1110,8 +1934,7 @@ static int checkout_create_submodules(
1110
1934
  }
1111
1935
  }
1112
1936
 
1113
- /* final reload once submodules have been updated */
1114
- return git_submodule_reload_all(data->repo);
1937
+ return 0;
1115
1938
  }
1116
1939
 
1117
1940
  static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
@@ -1121,7 +1944,7 @@ static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
1121
1944
  git_object *head;
1122
1945
 
1123
1946
  if (!(error = git_repository_head(&ref, repo)) &&
1124
- !(error = git_reference_peel(&head, ref, GIT_OBJ_TREE)))
1947
+ !(error = git_reference_peel(&head, ref, GIT_OBJECT_TREE)))
1125
1948
  *out = (git_tree *)head;
1126
1949
 
1127
1950
  git_reference_free(ref);
@@ -1129,6 +1952,385 @@ static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
1129
1952
  return error;
1130
1953
  }
1131
1954
 
1955
+
1956
+ static int conflict_entry_name(
1957
+ git_buf *out,
1958
+ const char *side_name,
1959
+ const char *filename)
1960
+ {
1961
+ if (git_buf_puts(out, side_name) < 0 ||
1962
+ git_buf_putc(out, ':') < 0 ||
1963
+ git_buf_puts(out, filename) < 0)
1964
+ return -1;
1965
+
1966
+ return 0;
1967
+ }
1968
+
1969
+ static int checkout_path_suffixed(git_buf *path, const char *suffix)
1970
+ {
1971
+ size_t path_len;
1972
+ int i = 0, error = 0;
1973
+
1974
+ if ((error = git_buf_putc(path, '~')) < 0 || (error = git_buf_puts(path, suffix)) < 0)
1975
+ return -1;
1976
+
1977
+ path_len = git_buf_len(path);
1978
+
1979
+ while (git_path_exists(git_buf_cstr(path)) && i < INT_MAX) {
1980
+ git_buf_truncate(path, path_len);
1981
+
1982
+ if ((error = git_buf_putc(path, '_')) < 0 ||
1983
+ (error = git_buf_printf(path, "%d", i)) < 0)
1984
+ return error;
1985
+
1986
+ i++;
1987
+ }
1988
+
1989
+ if (i == INT_MAX) {
1990
+ git_buf_truncate(path, path_len);
1991
+
1992
+ git_error_set(GIT_ERROR_CHECKOUT, "could not write '%s': working directory file exists", path->ptr);
1993
+ return GIT_EEXISTS;
1994
+ }
1995
+
1996
+ return 0;
1997
+ }
1998
+
1999
+ static int checkout_write_entry(
2000
+ checkout_data *data,
2001
+ checkout_conflictdata *conflict,
2002
+ const git_index_entry *side)
2003
+ {
2004
+ const char *hint_path = NULL, *suffix;
2005
+ git_buf *fullpath;
2006
+ struct stat st;
2007
+ int error;
2008
+
2009
+ assert (side == conflict->ours || side == conflict->theirs);
2010
+
2011
+ if (checkout_target_fullpath(&fullpath, data, side->path) < 0)
2012
+ return -1;
2013
+
2014
+ if ((conflict->name_collision || conflict->directoryfile) &&
2015
+ (data->strategy & GIT_CHECKOUT_USE_OURS) == 0 &&
2016
+ (data->strategy & GIT_CHECKOUT_USE_THEIRS) == 0) {
2017
+
2018
+ if (side == conflict->ours)
2019
+ suffix = data->opts.our_label ? data->opts.our_label :
2020
+ "ours";
2021
+ else
2022
+ suffix = data->opts.their_label ? data->opts.their_label :
2023
+ "theirs";
2024
+
2025
+ if (checkout_path_suffixed(fullpath, suffix) < 0)
2026
+ return -1;
2027
+
2028
+ hint_path = side->path;
2029
+ }
2030
+
2031
+ if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
2032
+ (error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0)
2033
+ return error;
2034
+
2035
+ if (!S_ISGITLINK(side->mode))
2036
+ return checkout_write_content(data,
2037
+ &side->id, fullpath->ptr, hint_path, side->mode, &st);
2038
+
2039
+ return 0;
2040
+ }
2041
+
2042
+ static int checkout_write_entries(
2043
+ checkout_data *data,
2044
+ checkout_conflictdata *conflict)
2045
+ {
2046
+ int error = 0;
2047
+
2048
+ if ((error = checkout_write_entry(data, conflict, conflict->ours)) >= 0)
2049
+ error = checkout_write_entry(data, conflict, conflict->theirs);
2050
+
2051
+ return error;
2052
+ }
2053
+
2054
+ static int checkout_merge_path(
2055
+ git_buf *out,
2056
+ checkout_data *data,
2057
+ checkout_conflictdata *conflict,
2058
+ git_merge_file_result *result)
2059
+ {
2060
+ const char *our_label_raw, *their_label_raw, *suffix;
2061
+ int error = 0;
2062
+
2063
+ if ((error = git_buf_joinpath(out, git_repository_workdir(data->repo), result->path)) < 0)
2064
+ return error;
2065
+
2066
+ /* Most conflicts simply use the filename in the index */
2067
+ if (!conflict->name_collision)
2068
+ return 0;
2069
+
2070
+ /* Rename 2->1 conflicts need the branch name appended */
2071
+ our_label_raw = data->opts.our_label ? data->opts.our_label : "ours";
2072
+ their_label_raw = data->opts.their_label ? data->opts.their_label : "theirs";
2073
+ suffix = strcmp(result->path, conflict->ours->path) == 0 ? our_label_raw : their_label_raw;
2074
+
2075
+ if ((error = checkout_path_suffixed(out, suffix)) < 0)
2076
+ return error;
2077
+
2078
+ return 0;
2079
+ }
2080
+
2081
+ static int checkout_write_merge(
2082
+ checkout_data *data,
2083
+ checkout_conflictdata *conflict)
2084
+ {
2085
+ git_buf our_label = GIT_BUF_INIT, their_label = GIT_BUF_INIT,
2086
+ path_suffixed = GIT_BUF_INIT, path_workdir = GIT_BUF_INIT,
2087
+ in_data = GIT_BUF_INIT, out_data = GIT_BUF_INIT;
2088
+ git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
2089
+ git_merge_file_result result = {0};
2090
+ git_filebuf output = GIT_FILEBUF_INIT;
2091
+ git_filter_list *fl = NULL;
2092
+ git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
2093
+ int error = 0;
2094
+
2095
+ if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
2096
+ opts.flags |= GIT_MERGE_FILE_STYLE_DIFF3;
2097
+
2098
+ opts.ancestor_label = data->opts.ancestor_label ?
2099
+ data->opts.ancestor_label : "ancestor";
2100
+ opts.our_label = data->opts.our_label ?
2101
+ data->opts.our_label : "ours";
2102
+ opts.their_label = data->opts.their_label ?
2103
+ data->opts.their_label : "theirs";
2104
+
2105
+ /* If all the paths are identical, decorate the diff3 file with the branch
2106
+ * names. Otherwise, append branch_name:path.
2107
+ */
2108
+ if (conflict->ours && conflict->theirs &&
2109
+ strcmp(conflict->ours->path, conflict->theirs->path) != 0) {
2110
+
2111
+ if ((error = conflict_entry_name(
2112
+ &our_label, opts.our_label, conflict->ours->path)) < 0 ||
2113
+ (error = conflict_entry_name(
2114
+ &their_label, opts.their_label, conflict->theirs->path)) < 0)
2115
+ goto done;
2116
+
2117
+ opts.our_label = git_buf_cstr(&our_label);
2118
+ opts.their_label = git_buf_cstr(&their_label);
2119
+ }
2120
+
2121
+ if ((error = git_merge_file_from_index(&result, data->repo,
2122
+ conflict->ancestor, conflict->ours, conflict->theirs, &opts)) < 0)
2123
+ goto done;
2124
+
2125
+ if (result.path == NULL || result.mode == 0) {
2126
+ git_error_set(GIT_ERROR_CHECKOUT, "could not merge contents of file");
2127
+ error = GIT_ECONFLICT;
2128
+ goto done;
2129
+ }
2130
+
2131
+ if ((error = checkout_merge_path(&path_workdir, data, conflict, &result)) < 0)
2132
+ goto done;
2133
+
2134
+ if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
2135
+ (error = checkout_safe_for_update_only(data, git_buf_cstr(&path_workdir), result.mode)) <= 0)
2136
+ goto done;
2137
+
2138
+ if (!data->opts.disable_filters) {
2139
+ in_data.ptr = (char *)result.ptr;
2140
+ in_data.size = result.len;
2141
+
2142
+ filter_opts.attr_session = &data->attr_session;
2143
+ filter_opts.temp_buf = &data->tmp;
2144
+
2145
+ if ((error = git_filter_list__load_ext(
2146
+ &fl, data->repo, NULL, git_buf_cstr(&path_workdir),
2147
+ GIT_FILTER_TO_WORKTREE, &filter_opts)) < 0 ||
2148
+ (error = git_filter_list_apply_to_data(&out_data, fl, &in_data)) < 0)
2149
+ goto done;
2150
+ } else {
2151
+ out_data.ptr = (char *)result.ptr;
2152
+ out_data.size = result.len;
2153
+ }
2154
+
2155
+ if ((error = mkpath2file(data, path_workdir.ptr, data->opts.dir_mode)) < 0 ||
2156
+ (error = git_filebuf_open(&output, git_buf_cstr(&path_workdir), GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
2157
+ (error = git_filebuf_write(&output, out_data.ptr, out_data.size)) < 0 ||
2158
+ (error = git_filebuf_commit(&output)) < 0)
2159
+ goto done;
2160
+
2161
+ done:
2162
+ git_filter_list_free(fl);
2163
+
2164
+ git_buf_dispose(&out_data);
2165
+ git_buf_dispose(&our_label);
2166
+ git_buf_dispose(&their_label);
2167
+
2168
+ git_merge_file_result_free(&result);
2169
+ git_buf_dispose(&path_workdir);
2170
+ git_buf_dispose(&path_suffixed);
2171
+
2172
+ return error;
2173
+ }
2174
+
2175
+ static int checkout_conflict_add(
2176
+ checkout_data *data,
2177
+ const git_index_entry *conflict)
2178
+ {
2179
+ int error = git_index_remove(data->index, conflict->path, 0);
2180
+
2181
+ if (error == GIT_ENOTFOUND)
2182
+ git_error_clear();
2183
+ else if (error < 0)
2184
+ return error;
2185
+
2186
+ return git_index_add(data->index, conflict);
2187
+ }
2188
+
2189
+ static int checkout_conflict_update_index(
2190
+ checkout_data *data,
2191
+ checkout_conflictdata *conflict)
2192
+ {
2193
+ int error = 0;
2194
+
2195
+ if (conflict->ancestor)
2196
+ error = checkout_conflict_add(data, conflict->ancestor);
2197
+
2198
+ if (!error && conflict->ours)
2199
+ error = checkout_conflict_add(data, conflict->ours);
2200
+
2201
+ if (!error && conflict->theirs)
2202
+ error = checkout_conflict_add(data, conflict->theirs);
2203
+
2204
+ return error;
2205
+ }
2206
+
2207
+ static int checkout_create_conflicts(checkout_data *data)
2208
+ {
2209
+ checkout_conflictdata *conflict;
2210
+ size_t i;
2211
+ int error = 0;
2212
+
2213
+ git_vector_foreach(&data->update_conflicts, i, conflict) {
2214
+
2215
+ /* Both deleted: nothing to do */
2216
+ if (conflict->ours == NULL && conflict->theirs == NULL)
2217
+ error = 0;
2218
+
2219
+ else if ((data->strategy & GIT_CHECKOUT_USE_OURS) &&
2220
+ conflict->ours)
2221
+ error = checkout_write_entry(data, conflict, conflict->ours);
2222
+ else if ((data->strategy & GIT_CHECKOUT_USE_THEIRS) &&
2223
+ conflict->theirs)
2224
+ error = checkout_write_entry(data, conflict, conflict->theirs);
2225
+
2226
+ /* Ignore the other side of name collisions. */
2227
+ else if ((data->strategy & GIT_CHECKOUT_USE_OURS) &&
2228
+ !conflict->ours && conflict->name_collision)
2229
+ error = 0;
2230
+ else if ((data->strategy & GIT_CHECKOUT_USE_THEIRS) &&
2231
+ !conflict->theirs && conflict->name_collision)
2232
+ error = 0;
2233
+
2234
+ /* For modify/delete, name collisions and d/f conflicts, write
2235
+ * the file (potentially with the name mangled.
2236
+ */
2237
+ else if (conflict->ours != NULL && conflict->theirs == NULL)
2238
+ error = checkout_write_entry(data, conflict, conflict->ours);
2239
+ else if (conflict->ours == NULL && conflict->theirs != NULL)
2240
+ error = checkout_write_entry(data, conflict, conflict->theirs);
2241
+
2242
+ /* Add/add conflicts and rename 1->2 conflicts, write the
2243
+ * ours/theirs sides (potentially name mangled).
2244
+ */
2245
+ else if (conflict->one_to_two)
2246
+ error = checkout_write_entries(data, conflict);
2247
+
2248
+ /* If all sides are links, write the ours side */
2249
+ else if (S_ISLNK(conflict->ours->mode) &&
2250
+ S_ISLNK(conflict->theirs->mode))
2251
+ error = checkout_write_entry(data, conflict, conflict->ours);
2252
+ /* Link/file conflicts, write the file side */
2253
+ else if (S_ISLNK(conflict->ours->mode))
2254
+ error = checkout_write_entry(data, conflict, conflict->theirs);
2255
+ else if (S_ISLNK(conflict->theirs->mode))
2256
+ error = checkout_write_entry(data, conflict, conflict->ours);
2257
+
2258
+ /* If any side is a gitlink, do nothing. */
2259
+ else if (conflict->submodule)
2260
+ error = 0;
2261
+
2262
+ /* If any side is binary, write the ours side */
2263
+ else if (conflict->binary)
2264
+ error = checkout_write_entry(data, conflict, conflict->ours);
2265
+
2266
+ else if (!error)
2267
+ error = checkout_write_merge(data, conflict);
2268
+
2269
+ /* Update the index extensions (REUC and NAME) if we're checking
2270
+ * out a different index. (Otherwise just leave them there.)
2271
+ */
2272
+ if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
2273
+ error = checkout_conflict_update_index(data, conflict);
2274
+
2275
+ if (error)
2276
+ break;
2277
+
2278
+ data->completed_steps++;
2279
+ report_progress(data,
2280
+ conflict->ours ? conflict->ours->path :
2281
+ (conflict->theirs ? conflict->theirs->path : conflict->ancestor->path));
2282
+ }
2283
+
2284
+ return error;
2285
+ }
2286
+
2287
+ static int checkout_remove_conflicts(checkout_data *data)
2288
+ {
2289
+ const char *conflict;
2290
+ size_t i;
2291
+
2292
+ git_vector_foreach(&data->remove_conflicts, i, conflict) {
2293
+ if (git_index_conflict_remove(data->index, conflict) < 0)
2294
+ return -1;
2295
+
2296
+ data->completed_steps++;
2297
+ }
2298
+
2299
+ return 0;
2300
+ }
2301
+
2302
+ static int checkout_extensions_update_index(checkout_data *data)
2303
+ {
2304
+ const git_index_reuc_entry *reuc_entry;
2305
+ const git_index_name_entry *name_entry;
2306
+ size_t i;
2307
+ int error = 0;
2308
+
2309
+ if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
2310
+ return 0;
2311
+
2312
+ if (data->update_reuc) {
2313
+ git_vector_foreach(data->update_reuc, i, reuc_entry) {
2314
+ if ((error = git_index_reuc_add(data->index, reuc_entry->path,
2315
+ reuc_entry->mode[0], &reuc_entry->oid[0],
2316
+ reuc_entry->mode[1], &reuc_entry->oid[1],
2317
+ reuc_entry->mode[2], &reuc_entry->oid[2])) < 0)
2318
+ goto done;
2319
+ }
2320
+ }
2321
+
2322
+ if (data->update_names) {
2323
+ git_vector_foreach(data->update_names, i, name_entry) {
2324
+ if ((error = git_index_name_add(data->index, name_entry->ancestor,
2325
+ name_entry->ours, name_entry->theirs)) < 0)
2326
+ goto done;
2327
+ }
2328
+ }
2329
+
2330
+ done:
2331
+ return error;
2332
+ }
2333
+
1132
2334
  static void checkout_data_clear(checkout_data *data)
1133
2335
  {
1134
2336
  if (data->opts_free_baseline) {
@@ -1139,19 +2341,28 @@ static void checkout_data_clear(checkout_data *data)
1139
2341
  git_vector_free(&data->removes);
1140
2342
  git_pool_clear(&data->pool);
1141
2343
 
2344
+ git_vector_free_deep(&data->remove_conflicts);
2345
+ git_vector_free_deep(&data->update_conflicts);
2346
+
1142
2347
  git__free(data->pfx);
1143
2348
  data->pfx = NULL;
1144
2349
 
1145
- git_buf_free(&data->path);
2350
+ git_buf_dispose(&data->target_path);
2351
+ git_buf_dispose(&data->tmp);
1146
2352
 
1147
2353
  git_index_free(data->index);
1148
2354
  data->index = NULL;
2355
+
2356
+ git_strmap_free(data->mkdir_map);
2357
+ data->mkdir_map = NULL;
2358
+
2359
+ git_attr_session__free(&data->attr_session);
1149
2360
  }
1150
2361
 
1151
2362
  static int checkout_data_init(
1152
2363
  checkout_data *data,
1153
2364
  git_iterator *target,
1154
- git_checkout_opts *proposed)
2365
+ const git_checkout_options *proposed)
1155
2366
  {
1156
2367
  int error = 0;
1157
2368
  git_repository *repo = git_iterator_owner(target);
@@ -1159,7 +2370,7 @@ static int checkout_data_init(
1159
2370
  memset(data, 0, sizeof(*data));
1160
2371
 
1161
2372
  if (!repo) {
1162
- giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing");
2373
+ git_error_set(GIT_ERROR_CHECKOUT, "cannot checkout nothing");
1163
2374
  return -1;
1164
2375
  }
1165
2376
 
@@ -1168,51 +2379,77 @@ static int checkout_data_init(
1168
2379
  return error;
1169
2380
 
1170
2381
  data->repo = repo;
2382
+ data->target = target;
1171
2383
 
1172
- GITERR_CHECK_VERSION(
1173
- proposed, GIT_CHECKOUT_OPTS_VERSION, "git_checkout_opts");
2384
+ GIT_ERROR_CHECK_VERSION(
2385
+ proposed, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options");
1174
2386
 
1175
2387
  if (!proposed)
1176
- GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTS_VERSION);
2388
+ GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTIONS_VERSION);
1177
2389
  else
1178
- memmove(&data->opts, proposed, sizeof(git_checkout_opts));
2390
+ memmove(&data->opts, proposed, sizeof(git_checkout_options));
1179
2391
 
1180
2392
  if (!data->opts.target_directory)
1181
2393
  data->opts.target_directory = git_repository_workdir(repo);
1182
2394
  else if (!git_path_isdir(data->opts.target_directory) &&
1183
- (error = git_futils_mkdir(data->opts.target_directory, NULL,
1184
- GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
2395
+ (error = checkout_mkdir(data,
2396
+ data->opts.target_directory, NULL,
2397
+ GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
2398
+ goto cleanup;
2399
+
2400
+ if ((error = git_repository_index(&data->index, data->repo)) < 0)
1185
2401
  goto cleanup;
1186
2402
 
1187
2403
  /* refresh config and index content unless NO_REFRESH is given */
1188
2404
  if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
1189
2405
  git_config *cfg;
1190
2406
 
1191
- if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
1192
- (error = git_config_refresh(cfg)) < 0)
2407
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1193
2408
  goto cleanup;
1194
2409
 
1195
- /* if we are checking out the index, don't reload,
1196
- * otherwise get index and force reload
2410
+ /* Reload the repository index (unless we're checking out the
2411
+ * index; then it has the changes we're trying to check out
2412
+ * and those should not be overwritten.)
1197
2413
  */
1198
- if ((data->index = git_iterator_get_index(target)) != NULL) {
1199
- GIT_REFCOUNT_INC(data->index);
1200
- } else {
1201
- /* otherwise, grab and reload the index */
1202
- if ((error = git_repository_index(&data->index, data->repo)) < 0 ||
1203
- (error = git_index_read(data->index)) < 0)
1204
- goto cleanup;
2414
+ if (data->index != git_iterator_index(target)) {
2415
+ if (data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) {
2416
+ /* When forcing, we can blindly re-read the index */
2417
+ if ((error = git_index_read(data->index, false)) < 0)
2418
+ goto cleanup;
2419
+ } else {
2420
+ /*
2421
+ * When not being forced, we need to check for unresolved
2422
+ * conflicts and unsaved changes in the index before
2423
+ * proceeding.
2424
+ */
2425
+ if (git_index_has_conflicts(data->index)) {
2426
+ error = GIT_ECONFLICT;
2427
+ git_error_set(GIT_ERROR_CHECKOUT,
2428
+ "unresolved conflicts exist in the index");
2429
+ goto cleanup;
2430
+ }
1205
2431
 
1206
- /* clear the REUC when doing a tree or commit checkout */
2432
+ if ((error = git_index_read_safely(data->index)) < 0)
2433
+ goto cleanup;
2434
+ }
2435
+
2436
+ /* clean conflict data in the current index */
2437
+ git_index_name_clear(data->index);
1207
2438
  git_index_reuc_clear(data->index);
1208
2439
  }
1209
2440
  }
1210
2441
 
1211
- /* if you are forcing, definitely allow safe updates */
2442
+ /* if you are forcing, allow all safe updates, plus recreate missing */
1212
2443
  if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0)
1213
- data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE;
1214
- if ((data->opts.checkout_strategy & GIT_CHECKOUT_SAFE_CREATE) != 0)
1215
- data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
2444
+ data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE |
2445
+ GIT_CHECKOUT_RECREATE_MISSING;
2446
+
2447
+ /* if the repository does not actually have an index file, then this
2448
+ * is an initial checkout (perhaps from clone), so we allow safe updates
2449
+ */
2450
+ if (!data->index->on_disk &&
2451
+ (data->opts.checkout_strategy & GIT_CHECKOUT_SAFE) != 0)
2452
+ data->opts.checkout_strategy |= GIT_CHECKOUT_RECREATE_MISSING;
1216
2453
 
1217
2454
  data->strategy = data->opts.checkout_strategy;
1218
2455
 
@@ -1230,27 +2467,67 @@ static int checkout_data_init(
1230
2467
  &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
1231
2468
  goto cleanup;
1232
2469
 
1233
- if (!data->opts.baseline) {
2470
+ if ((error = git_repository__cvar(
2471
+ &data->respect_filemode, repo, GIT_CVAR_FILEMODE)) < 0)
2472
+ goto cleanup;
2473
+
2474
+ if (!data->opts.baseline && !data->opts.baseline_index) {
1234
2475
  data->opts_free_baseline = true;
2476
+ error = 0;
1235
2477
 
1236
- error = checkout_lookup_head_tree(&data->opts.baseline, repo);
2478
+ /* if we don't have an index, this is an initial checkout and
2479
+ * should be against an empty baseline
2480
+ */
2481
+ if (data->index->on_disk)
2482
+ error = checkout_lookup_head_tree(&data->opts.baseline, repo);
1237
2483
 
1238
- if (error == GIT_EORPHANEDHEAD) {
2484
+ if (error == GIT_EUNBORNBRANCH) {
1239
2485
  error = 0;
1240
- giterr_clear();
2486
+ git_error_clear();
1241
2487
  }
1242
2488
 
1243
2489
  if (error < 0)
1244
2490
  goto cleanup;
1245
2491
  }
1246
2492
 
2493
+ if ((data->opts.checkout_strategy &
2494
+ (GIT_CHECKOUT_CONFLICT_STYLE_MERGE | GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)) == 0) {
2495
+ git_config_entry *conflict_style = NULL;
2496
+ git_config *cfg = NULL;
2497
+
2498
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
2499
+ (error = git_config_get_entry(&conflict_style, cfg, "merge.conflictstyle")) < 0 ||
2500
+ error == GIT_ENOTFOUND)
2501
+ ;
2502
+ else if (error)
2503
+ goto cleanup;
2504
+ else if (strcmp(conflict_style->value, "merge") == 0)
2505
+ data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_MERGE;
2506
+ else if (strcmp(conflict_style->value, "diff3") == 0)
2507
+ data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
2508
+ else {
2509
+ git_error_set(GIT_ERROR_CHECKOUT, "unknown style '%s' given for 'merge.conflictstyle'",
2510
+ conflict_style->value);
2511
+ error = -1;
2512
+ git_config_entry_free(conflict_style);
2513
+ goto cleanup;
2514
+ }
2515
+ git_config_entry_free(conflict_style);
2516
+ }
2517
+
2518
+ git_pool_init(&data->pool, 1);
2519
+
1247
2520
  if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
1248
- (error = git_pool_init(&data->pool, 1, 0)) < 0 ||
1249
- (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
1250
- (error = git_path_to_dir(&data->path)) < 0)
2521
+ (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 ||
2522
+ (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
2523
+ (error = git_buf_puts(&data->target_path, data->opts.target_directory)) < 0 ||
2524
+ (error = git_path_to_dir(&data->target_path)) < 0 ||
2525
+ (error = git_strmap_alloc(&data->mkdir_map)) < 0)
1251
2526
  goto cleanup;
1252
2527
 
1253
- data->workdir_len = git_buf_len(&data->path);
2528
+ data->target_len = git_buf_len(&data->target_path);
2529
+
2530
+ git_attr_session__init(&data->attr_session, data->repo);
1254
2531
 
1255
2532
  cleanup:
1256
2533
  if (error < 0)
@@ -1259,17 +2536,22 @@ cleanup:
1259
2536
  return error;
1260
2537
  }
1261
2538
 
2539
+ #define CHECKOUT_INDEX_DONT_WRITE_MASK \
2540
+ (GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
2541
+
1262
2542
  int git_checkout_iterator(
1263
2543
  git_iterator *target,
1264
- git_checkout_opts *opts)
2544
+ git_index *index,
2545
+ const git_checkout_options *opts)
1265
2546
  {
1266
2547
  int error = 0;
1267
2548
  git_iterator *baseline = NULL, *workdir = NULL;
2549
+ git_iterator_options baseline_opts = GIT_ITERATOR_OPTIONS_INIT,
2550
+ workdir_opts = GIT_ITERATOR_OPTIONS_INIT;
1268
2551
  checkout_data data = {0};
1269
2552
  git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
1270
2553
  uint32_t *actions = NULL;
1271
2554
  size_t *counts = NULL;
1272
- git_iterator_flag_t iterflags = 0;
1273
2555
 
1274
2556
  /* initialize structures and options */
1275
2557
  error = checkout_data_init(&data, target, opts);
@@ -1278,12 +2560,14 @@ int git_checkout_iterator(
1278
2560
 
1279
2561
  diff_opts.flags =
1280
2562
  GIT_DIFF_INCLUDE_UNMODIFIED |
2563
+ GIT_DIFF_INCLUDE_UNREADABLE |
1281
2564
  GIT_DIFF_INCLUDE_UNTRACKED |
1282
2565
  GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
1283
2566
  GIT_DIFF_INCLUDE_IGNORED |
1284
2567
  GIT_DIFF_INCLUDE_TYPECHANGE |
1285
2568
  GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
1286
- GIT_DIFF_SKIP_BINARY_CHECK;
2569
+ GIT_DIFF_SKIP_BINARY_CHECK |
2570
+ GIT_DIFF_INCLUDE_CASECHANGE;
1287
2571
  if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)
1288
2572
  diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
1289
2573
  if (data.opts.paths.count > 0)
@@ -1291,19 +2575,38 @@ int git_checkout_iterator(
1291
2575
 
1292
2576
  /* set up iterators */
1293
2577
 
1294
- iterflags = git_iterator_ignore_case(target) ?
2578
+ workdir_opts.flags = git_iterator_ignore_case(target) ?
1295
2579
  GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
2580
+ workdir_opts.flags |= GIT_ITERATOR_DONT_AUTOEXPAND;
2581
+ workdir_opts.start = data.pfx;
2582
+ workdir_opts.end = data.pfx;
1296
2583
 
1297
- if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
2584
+ if ((error = git_iterator_reset_range(target, data.pfx, data.pfx)) < 0 ||
1298
2585
  (error = git_iterator_for_workdir_ext(
1299
- &workdir, data.repo, data.opts.target_directory,
1300
- iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
1301
- data.pfx, data.pfx)) < 0 ||
1302
- (error = git_iterator_for_tree(
1303
- &baseline, data.opts.baseline,
1304
- iterflags, data.pfx, data.pfx)) < 0)
2586
+ &workdir, data.repo, data.opts.target_directory, index, NULL,
2587
+ &workdir_opts)) < 0)
1305
2588
  goto cleanup;
1306
2589
 
2590
+ baseline_opts.flags = git_iterator_ignore_case(target) ?
2591
+ GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
2592
+ baseline_opts.start = data.pfx;
2593
+ baseline_opts.end = data.pfx;
2594
+ if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
2595
+ baseline_opts.pathlist.count = opts->paths.count;
2596
+ baseline_opts.pathlist.strings = opts->paths.strings;
2597
+ }
2598
+
2599
+ if (data.opts.baseline_index) {
2600
+ if ((error = git_iterator_for_index(
2601
+ &baseline, git_index_owner(data.opts.baseline_index),
2602
+ data.opts.baseline_index, &baseline_opts)) < 0)
2603
+ goto cleanup;
2604
+ } else {
2605
+ if ((error = git_iterator_for_tree(
2606
+ &baseline, data.opts.baseline, &baseline_opts)) < 0)
2607
+ goto cleanup;
2608
+ }
2609
+
1307
2610
  /* Should not have case insensitivity mismatch */
1308
2611
  assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
1309
2612
 
@@ -1315,14 +2618,17 @@ int git_checkout_iterator(
1315
2618
  goto cleanup;
1316
2619
 
1317
2620
  /* Loop through diff (and working directory iterator) building a list of
1318
- * actions to be taken, plus look for conflicts and send notifications.
2621
+ * actions to be taken, plus look for conflicts and send notifications,
2622
+ * then loop through conflicts.
1319
2623
  */
1320
- if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0)
2624
+ if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0)
1321
2625
  goto cleanup;
1322
2626
 
1323
2627
  data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
2628
+ counts[CHECKOUT_ACTION__REMOVE_CONFLICT] +
1324
2629
  counts[CHECKOUT_ACTION__UPDATE_BLOB] +
1325
- counts[CHECKOUT_ACTION__UPDATE_SUBMODULE];
2630
+ counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] +
2631
+ counts[CHECKOUT_ACTION__UPDATE_CONFLICT];
1326
2632
 
1327
2633
  report_progress(&data, NULL); /* establish 0 baseline */
1328
2634
 
@@ -1333,6 +2639,10 @@ int git_checkout_iterator(
1333
2639
  (error = checkout_remove_the_old(actions, &data)) < 0)
1334
2640
  goto cleanup;
1335
2641
 
2642
+ if (counts[CHECKOUT_ACTION__REMOVE_CONFLICT] > 0 &&
2643
+ (error = checkout_remove_conflicts(&data)) < 0)
2644
+ goto cleanup;
2645
+
1336
2646
  if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 &&
1337
2647
  (error = checkout_create_the_new(actions, &data)) < 0)
1338
2648
  goto cleanup;
@@ -1341,17 +2651,25 @@ int git_checkout_iterator(
1341
2651
  (error = checkout_create_submodules(actions, &data)) < 0)
1342
2652
  goto cleanup;
1343
2653
 
2654
+ if (counts[CHECKOUT_ACTION__UPDATE_CONFLICT] > 0 &&
2655
+ (error = checkout_create_conflicts(&data)) < 0)
2656
+ goto cleanup;
2657
+
2658
+ if (data.index != git_iterator_index(target) &&
2659
+ (error = checkout_extensions_update_index(&data)) < 0)
2660
+ goto cleanup;
2661
+
1344
2662
  assert(data.completed_steps == data.total_steps);
1345
2663
 
1346
- cleanup:
1347
- if (error == GIT_EUSER)
1348
- giterr_clear();
2664
+ if (data.opts.perfdata_cb)
2665
+ data.opts.perfdata_cb(&data.perfdata, data.opts.perfdata_payload);
1349
2666
 
2667
+ cleanup:
1350
2668
  if (!error && data.index != NULL &&
1351
- (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
2669
+ (data.strategy & CHECKOUT_INDEX_DONT_WRITE_MASK) == 0)
1352
2670
  error = git_index_write(data.index);
1353
2671
 
1354
- git_diff_list_free(data.diff);
2672
+ git_diff_free(data.diff);
1355
2673
  git_iterator_free(workdir);
1356
2674
  git_iterator_free(baseline);
1357
2675
  git__free(actions);
@@ -1364,20 +2682,26 @@ cleanup:
1364
2682
  int git_checkout_index(
1365
2683
  git_repository *repo,
1366
2684
  git_index *index,
1367
- git_checkout_opts *opts)
2685
+ const git_checkout_options *opts)
1368
2686
  {
1369
- int error;
2687
+ int error, owned = 0;
1370
2688
  git_iterator *index_i;
1371
2689
 
1372
2690
  if (!index && !repo) {
1373
- giterr_set(GITERR_CHECKOUT,
1374
- "Must provide either repository or index to checkout");
2691
+ git_error_set(GIT_ERROR_CHECKOUT,
2692
+ "must provide either repository or index to checkout");
1375
2693
  return -1;
1376
2694
  }
1377
- if (index && repo && git_index_owner(index) != repo) {
1378
- giterr_set(GITERR_CHECKOUT,
1379
- "Index to checkout does not match repository");
2695
+
2696
+ if (index && repo &&
2697
+ git_index_owner(index) &&
2698
+ git_index_owner(index) != repo) {
2699
+ git_error_set(GIT_ERROR_CHECKOUT,
2700
+ "index to checkout does not match repository");
1380
2701
  return -1;
2702
+ } else if(index && repo && !git_index_owner(index)) {
2703
+ GIT_REFCOUNT_OWN(index, repo);
2704
+ owned = 1;
1381
2705
  }
1382
2706
 
1383
2707
  if (!repo)
@@ -1387,8 +2711,11 @@ int git_checkout_index(
1387
2711
  return error;
1388
2712
  GIT_REFCOUNT_INC(index);
1389
2713
 
1390
- if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL)))
1391
- error = git_checkout_iterator(index_i, opts);
2714
+ if (!(error = git_iterator_for_index(&index_i, repo, index, NULL)))
2715
+ error = git_checkout_iterator(index_i, index, opts);
2716
+
2717
+ if (owned)
2718
+ GIT_REFCOUNT_OWN(index, NULL);
1392
2719
 
1393
2720
  git_iterator_free(index_i);
1394
2721
  git_index_free(index);
@@ -1399,36 +2726,58 @@ int git_checkout_index(
1399
2726
  int git_checkout_tree(
1400
2727
  git_repository *repo,
1401
2728
  const git_object *treeish,
1402
- git_checkout_opts *opts)
2729
+ const git_checkout_options *opts)
1403
2730
  {
1404
2731
  int error;
2732
+ git_index *index;
1405
2733
  git_tree *tree = NULL;
1406
2734
  git_iterator *tree_i = NULL;
2735
+ git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
1407
2736
 
1408
2737
  if (!treeish && !repo) {
1409
- giterr_set(GITERR_CHECKOUT,
1410
- "Must provide either repository or tree to checkout");
2738
+ git_error_set(GIT_ERROR_CHECKOUT,
2739
+ "must provide either repository or tree to checkout");
1411
2740
  return -1;
1412
2741
  }
1413
2742
  if (treeish && repo && git_object_owner(treeish) != repo) {
1414
- giterr_set(GITERR_CHECKOUT,
1415
- "Object to checkout does not match repository");
2743
+ git_error_set(GIT_ERROR_CHECKOUT,
2744
+ "object to checkout does not match repository");
1416
2745
  return -1;
1417
2746
  }
1418
2747
 
1419
2748
  if (!repo)
1420
2749
  repo = git_object_owner(treeish);
1421
2750
 
1422
- if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
1423
- giterr_set(
1424
- GITERR_CHECKOUT, "Provided object cannot be peeled to a tree");
1425
- return -1;
2751
+ if (treeish) {
2752
+ if (git_object_peel((git_object **)&tree, treeish, GIT_OBJECT_TREE) < 0) {
2753
+ git_error_set(
2754
+ GIT_ERROR_CHECKOUT, "provided object cannot be peeled to a tree");
2755
+ return -1;
2756
+ }
2757
+ }
2758
+ else {
2759
+ if ((error = checkout_lookup_head_tree(&tree, repo)) < 0) {
2760
+ if (error != GIT_EUNBORNBRANCH)
2761
+ git_error_set(
2762
+ GIT_ERROR_CHECKOUT,
2763
+ "HEAD could not be peeled to a tree and no treeish given");
2764
+ return error;
2765
+ }
2766
+ }
2767
+
2768
+ if ((error = git_repository_index(&index, repo)) < 0)
2769
+ return error;
2770
+
2771
+ if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
2772
+ iter_opts.pathlist.count = opts->paths.count;
2773
+ iter_opts.pathlist.strings = opts->paths.strings;
1426
2774
  }
1427
2775
 
1428
- if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL)))
1429
- error = git_checkout_iterator(tree_i, opts);
2776
+ if (!(error = git_iterator_for_tree(&tree_i, tree, &iter_opts)))
2777
+ error = git_checkout_iterator(tree_i, index, opts);
1430
2778
 
1431
2779
  git_iterator_free(tree_i);
2780
+ git_index_free(index);
1432
2781
  git_tree_free(tree);
1433
2782
 
1434
2783
  return error;
@@ -1436,20 +2785,15 @@ int git_checkout_tree(
1436
2785
 
1437
2786
  int git_checkout_head(
1438
2787
  git_repository *repo,
1439
- git_checkout_opts *opts)
2788
+ const git_checkout_options *opts)
1440
2789
  {
1441
- int error;
1442
- git_tree *head = NULL;
1443
- git_iterator *head_i = NULL;
1444
-
1445
2790
  assert(repo);
2791
+ return git_checkout_tree(repo, NULL, opts);
2792
+ }
1446
2793
 
1447
- if (!(error = checkout_lookup_head_tree(&head, repo)) &&
1448
- !(error = git_iterator_for_tree(&head_i, head, 0, NULL, NULL)))
1449
- error = git_checkout_iterator(head_i, opts);
1450
-
1451
- git_iterator_free(head_i);
1452
- git_tree_free(head);
1453
-
1454
- return error;
2794
+ int git_checkout_init_options(git_checkout_options *opts, unsigned int version)
2795
+ {
2796
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2797
+ opts, version, git_checkout_options, GIT_CHECKOUT_OPTIONS_INIT);
2798
+ return 0;
1455
2799
  }