rugged 0.19.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (453) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/README.md +151 -25
  4. data/ext/rugged/extconf.rb +48 -27
  5. data/ext/rugged/rugged.c +107 -35
  6. data/ext/rugged/rugged.h +44 -8
  7. data/ext/rugged/rugged_blame.c +292 -0
  8. data/ext/rugged/rugged_blob.c +84 -31
  9. data/ext/rugged/rugged_branch.c +90 -223
  10. data/ext/rugged/rugged_branch_collection.c +445 -0
  11. data/ext/rugged/rugged_commit.c +190 -9
  12. data/ext/rugged/rugged_config.c +1 -1
  13. data/ext/rugged/rugged_cred.c +125 -0
  14. data/ext/rugged/rugged_diff.c +267 -94
  15. data/ext/rugged/rugged_diff_delta.c +14 -3
  16. data/ext/rugged/rugged_diff_hunk.c +31 -28
  17. data/ext/rugged/rugged_diff_line.c +21 -17
  18. data/ext/rugged/rugged_index.c +326 -6
  19. data/ext/rugged/rugged_note.c +39 -34
  20. data/ext/rugged/rugged_object.c +9 -9
  21. data/ext/rugged/rugged_patch.c +245 -0
  22. data/ext/rugged/rugged_reference.c +67 -332
  23. data/ext/rugged/rugged_reference_collection.c +490 -0
  24. data/ext/rugged/rugged_remote.c +447 -351
  25. data/ext/rugged/rugged_remote_collection.c +285 -0
  26. data/ext/rugged/rugged_repo.c +752 -203
  27. data/ext/rugged/rugged_revwalk.c +119 -27
  28. data/ext/rugged/rugged_settings.c +48 -1
  29. data/ext/rugged/rugged_signature.c +30 -16
  30. data/ext/rugged/rugged_tag.c +86 -191
  31. data/ext/rugged/rugged_tag_collection.c +279 -0
  32. data/ext/rugged/rugged_tree.c +159 -22
  33. data/lib/rugged/branch.rb +8 -17
  34. data/lib/rugged/credentials.rb +43 -0
  35. data/lib/rugged/diff/delta.rb +1 -2
  36. data/lib/rugged/diff/hunk.rb +4 -9
  37. data/lib/rugged/diff/line.rb +23 -3
  38. data/lib/rugged/diff.rb +3 -1
  39. data/lib/rugged/patch.rb +26 -0
  40. data/lib/rugged/reference.rb +1 -3
  41. data/lib/rugged/remote.rb +0 -9
  42. data/lib/rugged/repository.rb +70 -13
  43. data/lib/rugged/tag.rb +23 -18
  44. data/lib/rugged/tree.rb +7 -0
  45. data/lib/rugged/version.rb +1 -1
  46. data/lib/rugged.rb +8 -1
  47. data/vendor/libgit2/AUTHORS +75 -0
  48. data/vendor/libgit2/CMakeLists.txt +490 -0
  49. data/vendor/libgit2/COPYING +920 -0
  50. data/vendor/libgit2/Makefile.embed +25 -7
  51. data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +16 -0
  52. data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
  53. data/vendor/libgit2/cmake/Modules/FindIconv.cmake +43 -0
  54. data/vendor/libgit2/cmake/Modules/FindLIBSSH2.cmake +44 -0
  55. data/vendor/libgit2/deps/http-parser/LICENSE-MIT +23 -0
  56. data/vendor/libgit2/deps/regex/regex.c +10 -3
  57. data/vendor/libgit2/include/git2/attr.h +2 -1
  58. data/vendor/libgit2/include/git2/blame.h +213 -0
  59. data/vendor/libgit2/include/git2/blob.h +57 -29
  60. data/vendor/libgit2/include/git2/branch.h +56 -44
  61. data/vendor/libgit2/include/git2/buffer.h +112 -0
  62. data/vendor/libgit2/include/git2/checkout.h +72 -37
  63. data/vendor/libgit2/include/git2/cherrypick.h +87 -0
  64. data/vendor/libgit2/include/git2/clone.h +153 -56
  65. data/vendor/libgit2/include/git2/commit.h +82 -12
  66. data/vendor/libgit2/include/git2/common.h +31 -19
  67. data/vendor/libgit2/include/git2/config.h +124 -19
  68. data/vendor/libgit2/include/git2/cred_helpers.h +1 -1
  69. data/vendor/libgit2/include/git2/diff.h +636 -494
  70. data/vendor/libgit2/include/git2/errors.h +48 -15
  71. data/vendor/libgit2/include/git2/filter.h +149 -0
  72. data/vendor/libgit2/include/git2/graph.h +14 -0
  73. data/vendor/libgit2/include/git2/index.h +95 -54
  74. data/vendor/libgit2/include/git2/indexer.h +15 -9
  75. data/vendor/libgit2/include/git2/merge.h +402 -39
  76. data/vendor/libgit2/include/git2/message.h +9 -14
  77. data/vendor/libgit2/include/git2/net.h +5 -0
  78. data/vendor/libgit2/include/git2/notes.h +6 -6
  79. data/vendor/libgit2/include/git2/object.h +34 -2
  80. data/vendor/libgit2/include/git2/odb.h +77 -14
  81. data/vendor/libgit2/include/git2/odb_backend.h +50 -6
  82. data/vendor/libgit2/include/git2/oid.h +4 -8
  83. data/vendor/libgit2/include/git2/pack.h +58 -4
  84. data/vendor/libgit2/include/git2/patch.h +277 -0
  85. data/vendor/libgit2/include/git2/pathspec.h +263 -0
  86. data/vendor/libgit2/include/git2/push.h +55 -5
  87. data/vendor/libgit2/include/git2/reflog.h +11 -8
  88. data/vendor/libgit2/include/git2/refs.h +219 -33
  89. data/vendor/libgit2/include/git2/refspec.h +3 -4
  90. data/vendor/libgit2/include/git2/remote.h +216 -76
  91. data/vendor/libgit2/include/git2/repository.h +85 -40
  92. data/vendor/libgit2/include/git2/reset.h +15 -4
  93. data/vendor/libgit2/include/git2/revert.h +86 -0
  94. data/vendor/libgit2/include/git2/revparse.h +27 -16
  95. data/vendor/libgit2/include/git2/revwalk.h +44 -6
  96. data/vendor/libgit2/include/git2/signature.h +17 -3
  97. data/vendor/libgit2/include/git2/stash.h +8 -12
  98. data/vendor/libgit2/include/git2/status.h +67 -18
  99. data/vendor/libgit2/include/git2/submodule.h +100 -85
  100. data/vendor/libgit2/include/git2/sys/commit.h +38 -4
  101. data/vendor/libgit2/include/git2/sys/config.h +44 -3
  102. data/vendor/libgit2/include/git2/sys/diff.h +91 -0
  103. data/vendor/libgit2/include/git2/sys/filter.h +301 -0
  104. data/vendor/libgit2/include/git2/sys/index.h +0 -2
  105. data/vendor/libgit2/include/git2/sys/mempack.h +85 -0
  106. data/vendor/libgit2/include/git2/sys/odb_backend.h +33 -11
  107. data/vendor/libgit2/include/git2/sys/refdb_backend.h +51 -5
  108. data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
  109. data/vendor/libgit2/include/git2/sys/refs.h +2 -2
  110. data/vendor/libgit2/include/git2/sys/repository.h +19 -1
  111. data/vendor/libgit2/include/git2/transport.h +216 -75
  112. data/vendor/libgit2/include/git2/tree.h +32 -11
  113. data/vendor/libgit2/include/git2/types.h +124 -10
  114. data/vendor/libgit2/include/git2/version.h +4 -2
  115. data/vendor/libgit2/include/git2.h +41 -40
  116. data/vendor/libgit2/libgit2.pc.in +10 -0
  117. data/vendor/libgit2/src/array.h +16 -8
  118. data/vendor/libgit2/src/attr.c +140 -402
  119. data/vendor/libgit2/src/attr.h +1 -33
  120. data/vendor/libgit2/src/attr_file.c +298 -135
  121. data/vendor/libgit2/src/attr_file.h +61 -22
  122. data/vendor/libgit2/src/attrcache.c +449 -0
  123. data/vendor/libgit2/src/attrcache.h +38 -6
  124. data/vendor/libgit2/src/bitvec.h +75 -0
  125. data/vendor/libgit2/src/blame.c +488 -0
  126. data/vendor/libgit2/src/blame.h +93 -0
  127. data/vendor/libgit2/src/blame_git.c +624 -0
  128. data/vendor/libgit2/src/blame_git.h +20 -0
  129. data/vendor/libgit2/src/blob.c +137 -92
  130. data/vendor/libgit2/src/blob.h +9 -0
  131. data/vendor/libgit2/src/branch.c +175 -156
  132. data/vendor/libgit2/src/buf_text.c +29 -14
  133. data/vendor/libgit2/src/buf_text.h +5 -4
  134. data/vendor/libgit2/src/buffer.c +158 -15
  135. data/vendor/libgit2/src/buffer.h +33 -20
  136. data/vendor/libgit2/src/cc-compat.h +8 -2
  137. data/vendor/libgit2/src/checkout.c +1081 -287
  138. data/vendor/libgit2/src/checkout.h +1 -1
  139. data/vendor/libgit2/src/cherrypick.c +226 -0
  140. data/vendor/libgit2/src/clone.c +297 -245
  141. data/vendor/libgit2/src/{compress.h → clone.h} +4 -8
  142. data/vendor/libgit2/src/commit.c +313 -101
  143. data/vendor/libgit2/src/commit.h +6 -3
  144. data/vendor/libgit2/src/commit_list.c +3 -3
  145. data/vendor/libgit2/src/commit_list.h +1 -1
  146. data/vendor/libgit2/src/common.h +74 -1
  147. data/vendor/libgit2/src/config.c +570 -145
  148. data/vendor/libgit2/src/config.h +39 -6
  149. data/vendor/libgit2/src/config_cache.c +32 -18
  150. data/vendor/libgit2/src/config_file.c +711 -424
  151. data/vendor/libgit2/src/config_file.h +4 -3
  152. data/vendor/libgit2/src/crlf.c +149 -109
  153. data/vendor/libgit2/src/date.c +35 -7
  154. data/vendor/libgit2/src/delta.c +1 -1
  155. data/vendor/libgit2/src/diff.c +719 -414
  156. data/vendor/libgit2/src/diff.h +52 -7
  157. data/vendor/libgit2/src/diff_driver.c +183 -85
  158. data/vendor/libgit2/src/diff_driver.h +1 -1
  159. data/vendor/libgit2/src/diff_file.c +65 -84
  160. data/vendor/libgit2/src/diff_file.h +12 -10
  161. data/vendor/libgit2/src/diff_patch.c +274 -333
  162. data/vendor/libgit2/src/diff_patch.h +10 -9
  163. data/vendor/libgit2/src/diff_print.c +381 -179
  164. data/vendor/libgit2/src/diff_stats.c +336 -0
  165. data/vendor/libgit2/src/diff_tform.c +393 -215
  166. data/vendor/libgit2/src/diff_xdiff.c +117 -42
  167. data/vendor/libgit2/src/errors.c +59 -4
  168. data/vendor/libgit2/src/fetch.c +40 -34
  169. data/vendor/libgit2/src/fetch.h +2 -5
  170. data/vendor/libgit2/src/fetchhead.c +14 -7
  171. data/vendor/libgit2/src/filebuf.c +13 -24
  172. data/vendor/libgit2/src/filebuf.h +3 -3
  173. data/vendor/libgit2/src/fileops.c +104 -296
  174. data/vendor/libgit2/src/fileops.h +23 -94
  175. data/vendor/libgit2/src/filter.c +642 -43
  176. data/vendor/libgit2/src/filter.h +7 -66
  177. data/vendor/libgit2/src/fnmatch.c +46 -3
  178. data/vendor/libgit2/src/fnmatch.h +24 -3
  179. data/vendor/libgit2/src/global.c +158 -42
  180. data/vendor/libgit2/src/global.h +9 -0
  181. data/vendor/libgit2/src/graph.c +34 -20
  182. data/vendor/libgit2/src/hash/hash_generic.h +0 -1
  183. data/vendor/libgit2/src/hash/hash_openssl.h +0 -1
  184. data/vendor/libgit2/src/hash/hash_win32.c +14 -29
  185. data/vendor/libgit2/src/hash.h +0 -2
  186. data/vendor/libgit2/src/hashsig.c +97 -117
  187. data/vendor/libgit2/src/ident.c +125 -0
  188. data/vendor/libgit2/src/ignore.c +159 -110
  189. data/vendor/libgit2/src/ignore.h +13 -3
  190. data/vendor/libgit2/src/index.c +803 -445
  191. data/vendor/libgit2/src/index.h +43 -6
  192. data/vendor/libgit2/src/indexer.c +475 -157
  193. data/vendor/libgit2/src/iterator.c +198 -55
  194. data/vendor/libgit2/src/iterator.h +28 -4
  195. data/vendor/libgit2/src/map.h +1 -0
  196. data/vendor/libgit2/src/merge.c +849 -142
  197. data/vendor/libgit2/src/merge.h +11 -4
  198. data/vendor/libgit2/src/merge_file.c +183 -78
  199. data/vendor/libgit2/src/merge_file.h +0 -57
  200. data/vendor/libgit2/src/message.c +4 -28
  201. data/vendor/libgit2/src/mwindow.c +117 -8
  202. data/vendor/libgit2/src/mwindow.h +9 -1
  203. data/vendor/libgit2/src/netops.c +164 -59
  204. data/vendor/libgit2/src/netops.h +37 -1
  205. data/vendor/libgit2/src/notes.c +9 -18
  206. data/vendor/libgit2/src/notes.h +1 -1
  207. data/vendor/libgit2/src/object.c +78 -2
  208. data/vendor/libgit2/src/odb.c +191 -59
  209. data/vendor/libgit2/src/odb.h +2 -1
  210. data/vendor/libgit2/src/odb_loose.c +66 -51
  211. data/vendor/libgit2/src/odb_mempack.c +182 -0
  212. data/vendor/libgit2/src/odb_pack.c +151 -61
  213. data/vendor/libgit2/src/oid.c +30 -19
  214. data/vendor/libgit2/src/oid.h +13 -10
  215. data/vendor/libgit2/src/pack-objects.c +198 -147
  216. data/vendor/libgit2/src/pack-objects.h +7 -0
  217. data/vendor/libgit2/src/pack.c +272 -101
  218. data/vendor/libgit2/src/pack.h +15 -1
  219. data/vendor/libgit2/src/path.c +359 -117
  220. data/vendor/libgit2/src/path.h +110 -20
  221. data/vendor/libgit2/src/pathspec.c +583 -57
  222. data/vendor/libgit2/src/pathspec.h +36 -15
  223. data/vendor/libgit2/src/pool.c +4 -5
  224. data/vendor/libgit2/src/posix.c +45 -2
  225. data/vendor/libgit2/src/posix.h +13 -5
  226. data/vendor/libgit2/src/pqueue.c +73 -119
  227. data/vendor/libgit2/src/pqueue.h +35 -82
  228. data/vendor/libgit2/src/push.c +116 -48
  229. data/vendor/libgit2/src/push.h +5 -0
  230. data/vendor/libgit2/src/refdb.c +45 -6
  231. data/vendor/libgit2/src/refdb.h +13 -3
  232. data/vendor/libgit2/src/refdb_fs.c +1130 -551
  233. data/vendor/libgit2/src/reflog.c +36 -327
  234. data/vendor/libgit2/src/reflog.h +6 -1
  235. data/vendor/libgit2/src/refs.c +345 -142
  236. data/vendor/libgit2/src/refs.h +9 -2
  237. data/vendor/libgit2/src/refspec.c +90 -62
  238. data/vendor/libgit2/src/refspec.h +7 -24
  239. data/vendor/libgit2/src/remote.c +815 -415
  240. data/vendor/libgit2/src/remote.h +3 -4
  241. data/vendor/libgit2/src/repository.c +360 -207
  242. data/vendor/libgit2/src/repository.h +16 -10
  243. data/vendor/libgit2/src/reset.c +28 -13
  244. data/vendor/libgit2/src/revert.c +228 -0
  245. data/vendor/libgit2/src/revparse.c +29 -30
  246. data/vendor/libgit2/src/revwalk.c +141 -96
  247. data/vendor/libgit2/src/revwalk.h +6 -1
  248. data/vendor/libgit2/src/settings.c +140 -0
  249. data/vendor/libgit2/src/sha1_lookup.c +71 -0
  250. data/vendor/libgit2/src/sha1_lookup.h +5 -0
  251. data/vendor/libgit2/src/signature.c +38 -10
  252. data/vendor/libgit2/src/sortedcache.c +378 -0
  253. data/vendor/libgit2/src/sortedcache.h +178 -0
  254. data/vendor/libgit2/src/stash.c +98 -116
  255. data/vendor/libgit2/src/status.c +88 -60
  256. data/vendor/libgit2/src/status.h +2 -2
  257. data/vendor/libgit2/src/strmap.c +32 -0
  258. data/vendor/libgit2/src/strmap.h +14 -1
  259. data/vendor/libgit2/src/strnlen.h +23 -0
  260. data/vendor/libgit2/src/submodule.c +1073 -615
  261. data/vendor/libgit2/src/submodule.h +89 -21
  262. data/vendor/libgit2/src/sysdir.c +252 -0
  263. data/vendor/libgit2/src/sysdir.h +101 -0
  264. data/vendor/libgit2/src/tag.c +31 -20
  265. data/vendor/libgit2/src/thread-utils.h +98 -17
  266. data/vendor/libgit2/src/trace.h +0 -2
  267. data/vendor/libgit2/src/transport.c +76 -6
  268. data/vendor/libgit2/src/transports/cred.c +164 -61
  269. data/vendor/libgit2/src/transports/git.c +41 -48
  270. data/vendor/libgit2/src/transports/http.c +65 -109
  271. data/vendor/libgit2/src/transports/local.c +88 -65
  272. data/vendor/libgit2/src/transports/smart.c +91 -19
  273. data/vendor/libgit2/src/transports/smart.h +13 -5
  274. data/vendor/libgit2/src/transports/smart_pkt.c +24 -14
  275. data/vendor/libgit2/src/transports/smart_protocol.c +268 -113
  276. data/vendor/libgit2/src/transports/ssh.c +284 -186
  277. data/vendor/libgit2/src/transports/winhttp.c +279 -198
  278. data/vendor/libgit2/src/tree-cache.c +21 -23
  279. data/vendor/libgit2/src/tree-cache.h +1 -0
  280. data/vendor/libgit2/src/tree.c +109 -92
  281. data/vendor/libgit2/src/tree.h +2 -3
  282. data/vendor/libgit2/src/unix/map.c +7 -1
  283. data/vendor/libgit2/src/unix/posix.h +0 -1
  284. data/vendor/libgit2/src/userdiff.h +208 -0
  285. data/vendor/libgit2/src/util.c +16 -112
  286. data/vendor/libgit2/src/util.h +107 -3
  287. data/vendor/libgit2/src/vector.c +72 -17
  288. data/vendor/libgit2/src/vector.h +32 -5
  289. data/vendor/libgit2/src/win32/dir.c +15 -40
  290. data/vendor/libgit2/src/win32/dir.h +3 -2
  291. data/vendor/libgit2/src/win32/error.c +5 -31
  292. data/vendor/libgit2/src/win32/findfile.c +47 -66
  293. data/vendor/libgit2/src/win32/findfile.h +1 -12
  294. data/vendor/libgit2/src/win32/git2.rc +40 -0
  295. data/vendor/libgit2/src/win32/map.c +7 -1
  296. data/vendor/libgit2/src/win32/mingw-compat.h +3 -0
  297. data/vendor/libgit2/src/win32/posix.h +17 -11
  298. data/vendor/libgit2/src/win32/posix_w32.c +424 -292
  299. data/vendor/libgit2/src/win32/precompiled.h +6 -2
  300. data/vendor/libgit2/src/win32/pthread.c +141 -18
  301. data/vendor/libgit2/src/win32/pthread.h +50 -8
  302. data/vendor/libgit2/src/win32/reparse.h +57 -0
  303. data/vendor/libgit2/src/win32/utf-conv.c +117 -60
  304. data/vendor/libgit2/src/win32/utf-conv.h +81 -6
  305. data/vendor/libgit2/src/win32/version.h +21 -4
  306. data/vendor/libgit2/src/win32/w32_util.c +139 -0
  307. data/vendor/libgit2/src/win32/w32_util.h +54 -0
  308. data/vendor/libgit2/src/zstream.c +156 -0
  309. data/vendor/libgit2/src/zstream.h +39 -0
  310. metadata +84 -167
  311. data/Rakefile +0 -61
  312. data/ext/rugged/rugged_diff_patch.c +0 -169
  313. data/lib/rugged/diff/patch.rb +0 -28
  314. data/test/blob_test.rb +0 -341
  315. data/test/branch_test.rb +0 -199
  316. data/test/commit_test.rb +0 -104
  317. data/test/config_test.rb +0 -45
  318. data/test/coverage/cover.rb +0 -133
  319. data/test/diff_test.rb +0 -777
  320. data/test/errors_test.rb +0 -34
  321. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  322. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  323. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  324. data/test/fixtures/archive.tar.gz +0 -0
  325. data/test/fixtures/attr/attr0 +0 -1
  326. data/test/fixtures/attr/attr1 +0 -29
  327. data/test/fixtures/attr/attr2 +0 -21
  328. data/test/fixtures/attr/attr3 +0 -4
  329. data/test/fixtures/attr/binfile +0 -1
  330. data/test/fixtures/attr/dir/file +0 -0
  331. data/test/fixtures/attr/file +0 -1
  332. data/test/fixtures/attr/gitattributes +0 -29
  333. data/test/fixtures/attr/gitignore +0 -2
  334. data/test/fixtures/attr/ign +0 -1
  335. data/test/fixtures/attr/macro_bad +0 -1
  336. data/test/fixtures/attr/macro_test +0 -1
  337. data/test/fixtures/attr/root_test1 +0 -1
  338. data/test/fixtures/attr/root_test2 +0 -6
  339. data/test/fixtures/attr/root_test3 +0 -19
  340. data/test/fixtures/attr/root_test4.txt +0 -14
  341. data/test/fixtures/attr/sub/abc +0 -37
  342. data/test/fixtures/attr/sub/dir/file +0 -0
  343. data/test/fixtures/attr/sub/file +0 -1
  344. data/test/fixtures/attr/sub/ign/file +0 -1
  345. data/test/fixtures/attr/sub/ign/sub/file +0 -1
  346. data/test/fixtures/attr/sub/sub/dir +0 -0
  347. data/test/fixtures/attr/sub/sub/file +0 -1
  348. data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
  349. data/test/fixtures/attr/sub/subdir_test1 +0 -2
  350. data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
  351. data/test/fixtures/diff/another.txt +0 -38
  352. data/test/fixtures/diff/readme.txt +0 -36
  353. data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
  354. data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
  355. data/test/fixtures/mergedrepo/one.txt +0 -10
  356. data/test/fixtures/mergedrepo/two.txt +0 -12
  357. data/test/fixtures/status/current_file +0 -1
  358. data/test/fixtures/status/ignored_file +0 -1
  359. data/test/fixtures/status/modified_file +0 -2
  360. data/test/fixtures/status/new_file +0 -1
  361. data/test/fixtures/status/staged_changes +0 -2
  362. data/test/fixtures/status/staged_changes_modified_file +0 -3
  363. data/test/fixtures/status/staged_delete_modified_file +0 -1
  364. data/test/fixtures/status/staged_new_file +0 -1
  365. data/test/fixtures/status/staged_new_file_modified_file +0 -2
  366. data/test/fixtures/status/subdir/current_file +0 -1
  367. data/test/fixtures/status/subdir/modified_file +0 -2
  368. data/test/fixtures/status/subdir/new_file +0 -1
  369. data/test/fixtures/status/subdir.txt +0 -2
  370. data/test/fixtures/status//350/277/231 +0 -1
  371. data/test/fixtures/testrepo.git/HEAD +0 -1
  372. data/test/fixtures/testrepo.git/config +0 -13
  373. data/test/fixtures/testrepo.git/description +0 -1
  374. data/test/fixtures/testrepo.git/index +0 -0
  375. data/test/fixtures/testrepo.git/info/exclude +0 -6
  376. data/test/fixtures/testrepo.git/logs/HEAD +0 -3
  377. data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
  378. data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
  379. data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
  380. data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
  381. data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
  382. data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
  383. data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
  384. data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
  385. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
  386. data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
  387. data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
  388. data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
  389. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  390. data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
  391. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
  392. data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
  393. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  394. data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
  395. data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -0
  396. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  397. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  398. data/test/fixtures/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
  399. data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
  400. data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
  401. data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
  402. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
  403. data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
  404. data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
  405. data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
  406. data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  407. data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
  408. data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
  409. data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
  410. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
  411. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
  412. data/test/fixtures/testrepo.git/packed-refs +0 -2
  413. data/test/fixtures/testrepo.git/refs/heads/master +0 -1
  414. data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
  415. data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
  416. data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
  417. data/test/fixtures/text_file.md +0 -464
  418. data/test/fixtures/unsymlinked.git/HEAD +0 -1
  419. data/test/fixtures/unsymlinked.git/config +0 -6
  420. data/test/fixtures/unsymlinked.git/description +0 -1
  421. data/test/fixtures/unsymlinked.git/info/exclude +0 -2
  422. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  423. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  424. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  425. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  426. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  427. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  428. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  429. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  430. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  431. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
  432. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  433. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  434. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  435. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  436. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
  437. data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
  438. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
  439. data/test/index_test.rb +0 -333
  440. data/test/lib_test.rb +0 -127
  441. data/test/note_test.rb +0 -158
  442. data/test/object_test.rb +0 -43
  443. data/test/reference_test.rb +0 -207
  444. data/test/remote_test.rb +0 -324
  445. data/test/repo_pack_test.rb +0 -24
  446. data/test/repo_reset_test.rb +0 -82
  447. data/test/repo_test.rb +0 -402
  448. data/test/tag_test.rb +0 -68
  449. data/test/test_helper.rb +0 -92
  450. data/test/tree_test.rb +0 -91
  451. data/test/walker_test.rb +0 -88
  452. data/vendor/libgit2/src/amiga/map.c +0 -48
  453. data/vendor/libgit2/src/compress.c +0 -53
@@ -26,6 +26,7 @@
26
26
  #include "oid.h"
27
27
  #include "index.h"
28
28
  #include "filebuf.h"
29
+ #include "config.h"
29
30
 
30
31
  #include "git2/types.h"
31
32
  #include "git2/repository.h"
@@ -41,6 +42,7 @@
41
42
  #include "git2/sys/index.h"
42
43
 
43
44
  #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0)
45
+ #define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode)
44
46
 
45
47
  typedef enum {
46
48
  TREE_IDX_ANCESTOR = 0,
@@ -58,7 +60,7 @@ struct merge_diff_df_data {
58
60
 
59
61
  /* Merge base computation */
60
62
 
61
- int git_merge_base_many(git_oid *out, git_repository *repo, const git_oid input_array[], size_t length)
63
+ int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[])
62
64
  {
63
65
  git_revwalk *walk;
64
66
  git_vector list;
@@ -112,6 +114,31 @@ cleanup:
112
114
  return error;
113
115
  }
114
116
 
117
+ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[])
118
+ {
119
+ git_oid result;
120
+ unsigned int i;
121
+ int error = -1;
122
+
123
+ assert(out && repo && input_array);
124
+
125
+ if (length < 2) {
126
+ giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length);
127
+ return -1;
128
+ }
129
+
130
+ result = input_array[0];
131
+ for (i = 1; i < length; i++) {
132
+ error = git_merge_base(&result, repo, &result, &input_array[i]);
133
+ if (error < 0)
134
+ return error;
135
+ }
136
+
137
+ *out = result;
138
+
139
+ return 0;
140
+ }
141
+
115
142
  int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two)
116
143
  {
117
144
  git_revwalk *walk;
@@ -159,10 +186,10 @@ on_error:
159
186
 
160
187
  static int interesting(git_pqueue *list)
161
188
  {
162
- unsigned int i;
163
- /* element 0 isn't used - we need to start at 1 */
164
- for (i = 1; i < list->size; i++) {
165
- git_commit_list_node *commit = list->d[i];
189
+ size_t i;
190
+
191
+ for (i = 0; i < git_pqueue_size(list); i++) {
192
+ git_commit_list_node *commit = git_pqueue_get(list, i);
166
193
  if ((commit->flags & STALE) == 0)
167
194
  return 1;
168
195
  }
@@ -178,13 +205,19 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
178
205
  git_commit_list *result = NULL, *tmp = NULL;
179
206
  git_pqueue list;
180
207
 
208
+ /* If there's only the one commit, there can be no merge bases */
209
+ if (twos->length == 0) {
210
+ *out = NULL;
211
+ return 0;
212
+ }
213
+
181
214
  /* if the commit is repeated, we have a our merge base already */
182
215
  git_vector_foreach(twos, i, two) {
183
216
  if (one == two)
184
217
  return git_commit_list_insert(one, out) ? 0 : -1;
185
218
  }
186
219
 
187
- if (git_pqueue_init(&list, twos->length * 2, git_commit_list_time_cmp) < 0)
220
+ if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0)
188
221
  return -1;
189
222
 
190
223
  if (git_commit_list_parse(walk, one) < 0)
@@ -203,10 +236,11 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
203
236
 
204
237
  /* as long as there are non-STALE commits */
205
238
  while (interesting(&list)) {
206
- git_commit_list_node *commit;
239
+ git_commit_list_node *commit = git_pqueue_pop(&list);
207
240
  int flags;
208
241
 
209
- commit = git_pqueue_pop(&list);
242
+ if (commit == NULL)
243
+ break;
210
244
 
211
245
  flags = commit->flags & (PARENT1 | PARENT2 | STALE);
212
246
  if (flags == (PARENT1 | PARENT2)) {
@@ -253,7 +287,8 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
253
287
  return 0;
254
288
  }
255
289
 
256
- int git_repository_mergehead_foreach(git_repository *repo,
290
+ int git_repository_mergehead_foreach(
291
+ git_repository *repo,
257
292
  git_repository_mergehead_foreach_cb cb,
258
293
  void *payload)
259
294
  {
@@ -285,8 +320,8 @@ int git_repository_mergehead_foreach(git_repository *repo,
285
320
  if ((error = git_oid_fromstr(&oid, line)) < 0)
286
321
  goto cleanup;
287
322
 
288
- if (cb(&oid, payload) < 0) {
289
- error = GIT_EUSER;
323
+ if ((error = cb(&oid, payload)) != 0) {
324
+ giterr_set_after_callback(error);
290
325
  goto cleanup;
291
326
  }
292
327
 
@@ -314,7 +349,7 @@ GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry
314
349
  return (b->path == NULL) ? 0 : 1;
315
350
 
316
351
  if ((value = a->mode - b->mode) == 0 &&
317
- (value = git_oid__cmp(&a->oid, &b->oid)) == 0)
352
+ (value = git_oid__cmp(&a->id, &b->id)) == 0)
318
353
  value = strcmp(a->path, b->path);
319
354
 
320
355
  return value;
@@ -445,7 +480,6 @@ static int merge_conflict_resolve_one_removed(
445
480
  return error;
446
481
  }
447
482
 
448
-
449
483
  static int merge_conflict_resolve_one_renamed(
450
484
  int *resolved,
451
485
  git_merge_diff_list *diff_list,
@@ -476,12 +510,12 @@ static int merge_conflict_resolve_one_renamed(
476
510
  conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED)
477
511
  return 0;
478
512
 
479
- ours_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->our_entry.oid) != 0);
480
- theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->their_entry.oid) != 0);
513
+ ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0);
514
+ theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0);
481
515
 
482
516
  /* if both are modified (and not to a common target) require a merge */
483
517
  if (ours_changed && theirs_changed &&
484
- git_oid__cmp(&conflict->our_entry.oid, &conflict->their_entry.oid) != 0)
518
+ git_oid__cmp(&conflict->our_entry.id, &conflict->their_entry.id) != 0)
485
519
  return 0;
486
520
 
487
521
  if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL)
@@ -509,12 +543,11 @@ static int merge_conflict_resolve_automerge(
509
543
  int *resolved,
510
544
  git_merge_diff_list *diff_list,
511
545
  const git_merge_diff *conflict,
512
- unsigned int automerge_flags)
546
+ unsigned int merge_file_favor)
513
547
  {
514
- git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
515
- ours = GIT_MERGE_FILE_INPUT_INIT,
516
- theirs = GIT_MERGE_FILE_INPUT_INIT;
517
- git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT;
548
+ const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL;
549
+ git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
550
+ git_merge_file_result result = {0};
518
551
  git_index_entry *index_entry;
519
552
  git_odb *odb = NULL;
520
553
  git_oid automerge_oid;
@@ -524,13 +557,20 @@ static int merge_conflict_resolve_automerge(
524
557
 
525
558
  *resolved = 0;
526
559
 
527
- if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE)
560
+ if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ||
561
+ !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry))
528
562
  return 0;
529
563
 
530
564
  /* Reject D/F conflicts */
531
565
  if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
532
566
  return 0;
533
567
 
568
+ /* Reject submodules. */
569
+ if (S_ISGITLINK(conflict->ancestor_entry.mode) ||
570
+ S_ISGITLINK(conflict->our_entry.mode) ||
571
+ S_ISGITLINK(conflict->their_entry.mode))
572
+ return 0;
573
+
534
574
  /* Reject link/file conflicts. */
535
575
  if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) ||
536
576
  (S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode)))
@@ -546,13 +586,23 @@ static int merge_conflict_resolve_automerge(
546
586
  strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0)
547
587
  return 0;
548
588
 
589
+ /* Reject binary conflicts */
590
+ if (conflict->binary)
591
+ return 0;
592
+
593
+ ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ?
594
+ &conflict->ancestor_entry : NULL;
595
+ ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ?
596
+ &conflict->our_entry : NULL;
597
+ theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ?
598
+ &conflict->their_entry : NULL;
599
+
600
+ opts.favor = merge_file_favor;
601
+
549
602
  if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 ||
550
- (error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 ||
551
- (error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 ||
552
- (error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 ||
553
- (error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 ||
603
+ (error = git_merge_file_from_index(&result, diff_list->repo, ancestor, ours, theirs, &opts)) < 0 ||
554
604
  !result.automergeable ||
555
- (error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0)
605
+ (error = git_odb_write(&automerge_oid, odb, result.ptr, result.len, GIT_OBJ_BLOB)) < 0)
556
606
  goto done;
557
607
 
558
608
  if ((index_entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL)
@@ -563,7 +613,7 @@ static int merge_conflict_resolve_automerge(
563
613
 
564
614
  index_entry->file_size = result.len;
565
615
  index_entry->mode = result.mode;
566
- git_oid_cpy(&index_entry->oid, &automerge_oid);
616
+ git_oid_cpy(&index_entry->id, &automerge_oid);
567
617
 
568
618
  git_vector_insert(&diff_list->staged, index_entry);
569
619
  git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict);
@@ -571,9 +621,6 @@ static int merge_conflict_resolve_automerge(
571
621
  *resolved = 1;
572
622
 
573
623
  done:
574
- git_merge_file_input_free(&ancestor);
575
- git_merge_file_input_free(&ours);
576
- git_merge_file_input_free(&theirs);
577
624
  git_merge_file_result_free(&result);
578
625
  git_odb_free(odb);
579
626
 
@@ -584,7 +631,7 @@ static int merge_conflict_resolve(
584
631
  int *out,
585
632
  git_merge_diff_list *diff_list,
586
633
  const git_merge_diff *conflict,
587
- unsigned int automerge_flags)
634
+ unsigned int merge_file_favor)
588
635
  {
589
636
  int resolved = 0;
590
637
  int error = 0;
@@ -594,16 +641,14 @@ static int merge_conflict_resolve(
594
641
  if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0)
595
642
  goto done;
596
643
 
597
- if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) {
598
- if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
599
- goto done;
644
+ if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
645
+ goto done;
600
646
 
601
- if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
602
- goto done;
647
+ if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
648
+ goto done;
603
649
 
604
- if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, automerge_flags)) < 0)
605
- goto done;
606
- }
650
+ if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, merge_file_favor)) < 0)
651
+ goto done;
607
652
 
608
653
  *out = resolved;
609
654
 
@@ -625,7 +670,7 @@ static int index_entry_similarity_exact(
625
670
  git_index_entry *b,
626
671
  size_t b_idx,
627
672
  void **cache,
628
- const git_merge_tree_opts *opts)
673
+ const git_merge_options *opts)
629
674
  {
630
675
  GIT_UNUSED(repo);
631
676
  GIT_UNUSED(a_idx);
@@ -633,7 +678,7 @@ static int index_entry_similarity_exact(
633
678
  GIT_UNUSED(cache);
634
679
  GIT_UNUSED(opts);
635
680
 
636
- if (git_oid__cmp(&a->oid, &b->oid) == 0)
681
+ if (git_oid__cmp(&a->id, &b->id) == 0)
637
682
  return 100;
638
683
 
639
684
  return 0;
@@ -643,7 +688,7 @@ static int index_entry_similarity_calc(
643
688
  void **out,
644
689
  git_repository *repo,
645
690
  git_index_entry *entry,
646
- const git_merge_tree_opts *opts)
691
+ const git_merge_options *opts)
647
692
  {
648
693
  git_blob *blob;
649
694
  git_diff_file diff_file = {{{0}}};
@@ -652,10 +697,10 @@ static int index_entry_similarity_calc(
652
697
 
653
698
  *out = NULL;
654
699
 
655
- if ((error = git_blob_lookup(&blob, repo, &entry->oid)) < 0)
700
+ if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0)
656
701
  return error;
657
702
 
658
- git_oid_cpy(&diff_file.oid, &entry->oid);
703
+ git_oid_cpy(&diff_file.id, &entry->id);
659
704
  diff_file.path = entry->path;
660
705
  diff_file.size = entry->file_size;
661
706
  diff_file.mode = entry->mode;
@@ -683,7 +728,7 @@ static int index_entry_similarity_inexact(
683
728
  git_index_entry *b,
684
729
  size_t b_idx,
685
730
  void **cache,
686
- const git_merge_tree_opts *opts)
731
+ const git_merge_options *opts)
687
732
  {
688
733
  int score = 0;
689
734
  int error = 0;
@@ -720,9 +765,9 @@ static int merge_diff_mark_similarity(
720
765
  git_merge_diff_list *diff_list,
721
766
  struct merge_diff_similarity *similarity_ours,
722
767
  struct merge_diff_similarity *similarity_theirs,
723
- int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_tree_opts *),
768
+ int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_options *),
724
769
  void **cache,
725
- const git_merge_tree_opts *opts)
770
+ const git_merge_options *opts)
726
771
  {
727
772
  size_t i, j;
728
773
  git_merge_diff *conflict_src, *conflict_tgt;
@@ -823,7 +868,7 @@ static void merge_diff_mark_rename_conflict(
823
868
  bool theirs_renamed,
824
869
  size_t theirs_source_idx,
825
870
  git_merge_diff *target,
826
- const git_merge_tree_opts *opts)
871
+ const git_merge_options *opts)
827
872
  {
828
873
  git_merge_diff *ours_source = NULL, *theirs_source = NULL;
829
874
 
@@ -893,7 +938,7 @@ static void merge_diff_list_coalesce_renames(
893
938
  git_merge_diff_list *diff_list,
894
939
  struct merge_diff_similarity *similarity_ours,
895
940
  struct merge_diff_similarity *similarity_theirs,
896
- const git_merge_tree_opts *opts)
941
+ const git_merge_options *opts)
897
942
  {
898
943
  size_t i;
899
944
  bool ours_renamed = 0, theirs_renamed = 0;
@@ -950,10 +995,12 @@ static void merge_diff_list_coalesce_renames(
950
995
  }
951
996
  }
952
997
 
953
- static int merge_diff_empty(const git_vector *conflicts, size_t idx)
998
+ static int merge_diff_empty(const git_vector *conflicts, size_t idx, void *p)
954
999
  {
955
1000
  git_merge_diff *conflict = conflicts->contents[idx];
956
1001
 
1002
+ GIT_UNUSED(p);
1003
+
957
1004
  return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) &&
958
1005
  !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) &&
959
1006
  !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry));
@@ -983,7 +1030,7 @@ static void merge_diff_list_count_candidates(
983
1030
  int git_merge_diff_list__find_renames(
984
1031
  git_repository *repo,
985
1032
  git_merge_diff_list *diff_list,
986
- const git_merge_tree_opts *opts)
1033
+ const git_merge_options *opts)
987
1034
  {
988
1035
  struct merge_diff_similarity *similarity_ours, *similarity_theirs;
989
1036
  void **cache = NULL;
@@ -1034,7 +1081,7 @@ int git_merge_diff_list__find_renames(
1034
1081
  merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts);
1035
1082
 
1036
1083
  /* And remove any entries that were merged and are now empty. */
1037
- git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty);
1084
+ git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty, NULL);
1038
1085
 
1039
1086
  done:
1040
1087
  if (cache != NULL) {
@@ -1145,7 +1192,45 @@ GIT_INLINE(int) merge_diff_detect_type(
1145
1192
  return 0;
1146
1193
  }
1147
1194
 
1148
- GIT_INLINE(int) index_entry_dup(
1195
+ GIT_INLINE(int) merge_diff_detect_binary(
1196
+ git_repository *repo,
1197
+ git_merge_diff *conflict)
1198
+ {
1199
+ git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
1200
+ int error = 0;
1201
+
1202
+ if (GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->ancestor_entry)) {
1203
+ if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor_entry.id)) < 0)
1204
+ goto done;
1205
+
1206
+ conflict->binary = git_blob_is_binary(ancestor_blob);
1207
+ }
1208
+
1209
+ if (!conflict->binary &&
1210
+ GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->our_entry)) {
1211
+ if ((error = git_blob_lookup(&our_blob, repo, &conflict->our_entry.id)) < 0)
1212
+ goto done;
1213
+
1214
+ conflict->binary = git_blob_is_binary(our_blob);
1215
+ }
1216
+
1217
+ if (!conflict->binary &&
1218
+ GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->their_entry)) {
1219
+ if ((error = git_blob_lookup(&their_blob, repo, &conflict->their_entry.id)) < 0)
1220
+ goto done;
1221
+
1222
+ conflict->binary = git_blob_is_binary(their_blob);
1223
+ }
1224
+
1225
+ done:
1226
+ git_blob_free(ancestor_blob);
1227
+ git_blob_free(our_blob);
1228
+ git_blob_free(their_blob);
1229
+
1230
+ return error;
1231
+ }
1232
+
1233
+ GIT_INLINE(int) index_entry_dup_pool(
1149
1234
  git_index_entry *out,
1150
1235
  git_pool *pool,
1151
1236
  const git_index_entry *src)
@@ -1174,7 +1259,7 @@ GIT_INLINE(int) merge_delta_type_from_index_entries(
1174
1259
  return GIT_DELTA_TYPECHANGE;
1175
1260
  else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode))
1176
1261
  return GIT_DELTA_TYPECHANGE;
1177
- else if (git_oid__cmp(&ancestor->oid, &other->oid) ||
1262
+ else if (git_oid__cmp(&ancestor->id, &other->id) ||
1178
1263
  ancestor->mode != other->mode)
1179
1264
  return GIT_DELTA_MODIFIED;
1180
1265
 
@@ -1191,9 +1276,9 @@ static git_merge_diff *merge_diff_from_index_entries(
1191
1276
  if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL)
1192
1277
  return NULL;
1193
1278
 
1194
- if (index_entry_dup(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 ||
1195
- index_entry_dup(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 ||
1196
- index_entry_dup(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0)
1279
+ if (index_entry_dup_pool(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 ||
1280
+ index_entry_dup_pool(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 ||
1281
+ index_entry_dup_pool(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0)
1197
1282
  return NULL;
1198
1283
 
1199
1284
  conflict->our_status = merge_delta_type_from_index_entries(
@@ -1206,7 +1291,7 @@ static git_merge_diff *merge_diff_from_index_entries(
1206
1291
 
1207
1292
  /* Merge trees */
1208
1293
 
1209
- static int merge_index_insert_conflict(
1294
+ static int merge_diff_list_insert_conflict(
1210
1295
  git_merge_diff_list *diff_list,
1211
1296
  struct merge_diff_df_data *merge_df_data,
1212
1297
  const git_index_entry *tree_items[3])
@@ -1216,13 +1301,14 @@ static int merge_index_insert_conflict(
1216
1301
  if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL ||
1217
1302
  merge_diff_detect_type(conflict) < 0 ||
1218
1303
  merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 ||
1304
+ merge_diff_detect_binary(diff_list->repo, conflict) < 0 ||
1219
1305
  git_vector_insert(&diff_list->conflicts, conflict) < 0)
1220
1306
  return -1;
1221
1307
 
1222
1308
  return 0;
1223
1309
  }
1224
1310
 
1225
- static int merge_index_insert_unmodified(
1311
+ static int merge_diff_list_insert_unmodified(
1226
1312
  git_merge_diff_list *diff_list,
1227
1313
  const git_index_entry *tree_items[3])
1228
1314
  {
@@ -1232,7 +1318,7 @@ static int merge_index_insert_unmodified(
1232
1318
  entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry));
1233
1319
  GITERR_CHECK_ALLOC(entry);
1234
1320
 
1235
- if ((error = index_entry_dup(entry, &diff_list->pool, tree_items[0])) >= 0)
1321
+ if ((error = index_entry_dup_pool(entry, &diff_list->pool, tree_items[0])) >= 0)
1236
1322
  error = git_vector_insert(&diff_list->staged, entry);
1237
1323
 
1238
1324
  return error;
@@ -1246,13 +1332,13 @@ int git_merge_diff_list__find_differences(
1246
1332
  {
1247
1333
  git_iterator *iterators[3] = {0};
1248
1334
  const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3];
1249
- git_vector_cmp entry_compare = git_index_entry__cmp;
1335
+ git_vector_cmp entry_compare = git_index_entry_cmp;
1250
1336
  struct merge_diff_df_data df_data = {0};
1251
1337
  int cur_item_modified;
1252
1338
  size_t i, j;
1253
1339
  int error = 0;
1254
1340
 
1255
- assert(diff_list && our_tree && their_tree);
1341
+ assert(diff_list && (our_tree || their_tree));
1256
1342
 
1257
1343
  if ((error = git_iterator_for_tree(&iterators[TREE_IDX_ANCESTOR], (git_tree *)ancestor_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
1258
1344
  (error = git_iterator_for_tree(&iterators[TREE_IDX_OURS], (git_tree *)our_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
@@ -1262,6 +1348,7 @@ int git_merge_diff_list__find_differences(
1262
1348
  /* Set up the iterators */
1263
1349
  for (i = 0; i < 3; i++) {
1264
1350
  error = git_iterator_current(&items[i], iterators[i]);
1351
+
1265
1352
  if (error < 0 && error != GIT_ITEROVER)
1266
1353
  goto done;
1267
1354
  }
@@ -1313,9 +1400,9 @@ int git_merge_diff_list__find_differences(
1313
1400
  break;
1314
1401
 
1315
1402
  if (cur_item_modified)
1316
- error = merge_index_insert_conflict(diff_list, &df_data, cur_items);
1403
+ error = merge_diff_list_insert_conflict(diff_list, &df_data, cur_items);
1317
1404
  else
1318
- error = merge_index_insert_unmodified(diff_list, cur_items);
1405
+ error = merge_diff_list_insert_unmodified(diff_list, cur_items);
1319
1406
  if (error < 0)
1320
1407
  goto done;
1321
1408
 
@@ -1325,6 +1412,7 @@ int git_merge_diff_list__find_differences(
1325
1412
  continue;
1326
1413
 
1327
1414
  error = git_iterator_advance(&items[i], iterators[i]);
1415
+
1328
1416
  if (error < 0 && error != GIT_ITEROVER)
1329
1417
  goto done;
1330
1418
  }
@@ -1370,10 +1458,10 @@ void git_merge_diff_list__free(git_merge_diff_list *diff_list)
1370
1458
  git__free(diff_list);
1371
1459
  }
1372
1460
 
1373
- static int merge_tree_normalize_opts(
1461
+ static int merge_normalize_opts(
1374
1462
  git_repository *repo,
1375
- git_merge_tree_opts *opts,
1376
- const git_merge_tree_opts *given)
1463
+ git_merge_options *opts,
1464
+ const git_merge_options *given)
1377
1465
  {
1378
1466
  git_config *cfg = NULL;
1379
1467
  int error = 0;
@@ -1384,9 +1472,9 @@ static int merge_tree_normalize_opts(
1384
1472
  return error;
1385
1473
 
1386
1474
  if (given != NULL)
1387
- memcpy(opts, given, sizeof(git_merge_tree_opts));
1475
+ memcpy(opts, given, sizeof(git_merge_options));
1388
1476
  else {
1389
- git_merge_tree_opts init = GIT_MERGE_TREE_OPTS_INIT;
1477
+ git_merge_options init = GIT_MERGE_OPTIONS_INIT;
1390
1478
  memcpy(opts, &init, sizeof(init));
1391
1479
 
1392
1480
  opts->flags = GIT_MERGE_TREE_FIND_RENAMES;
@@ -1394,19 +1482,13 @@ static int merge_tree_normalize_opts(
1394
1482
  }
1395
1483
 
1396
1484
  if (!opts->target_limit) {
1397
- int32_t limit = 0;
1398
-
1399
- opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT;
1400
-
1401
- if (git_config_get_int32(&limit, cfg, "merge.renameLimit") < 0) {
1402
- giterr_clear();
1485
+ int limit = git_config__get_int_force(cfg, "merge.renamelimit", 0);
1403
1486
 
1404
- if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0)
1405
- giterr_clear();
1406
- }
1487
+ if (!limit)
1488
+ limit = git_config__get_int_force(cfg, "diff.renamelimit", 0);
1407
1489
 
1408
- if (limit > 0)
1409
- opts->target_limit = limit;
1490
+ opts->target_limit = (limit <= 0) ?
1491
+ GIT_MERGE_TREE_TARGET_LIMIT : (unsigned int)limit;
1410
1492
  }
1411
1493
 
1412
1494
  /* assign the internal metric with whitespace flag as payload */
@@ -1452,7 +1534,7 @@ static int merge_index_insert_reuc(
1452
1534
  }
1453
1535
 
1454
1536
  mode[idx] = entry->mode;
1455
- oid[idx] = &entry->oid;
1537
+ oid[idx] = &entry->id;
1456
1538
 
1457
1539
  return git_index_reuc_add(index, entry->path,
1458
1540
  mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]);
@@ -1560,20 +1642,22 @@ int git_merge_trees(
1560
1642
  const git_tree *ancestor_tree,
1561
1643
  const git_tree *our_tree,
1562
1644
  const git_tree *their_tree,
1563
- const git_merge_tree_opts *given_opts)
1645
+ const git_merge_options *given_opts)
1564
1646
  {
1565
1647
  git_merge_diff_list *diff_list;
1566
- git_merge_tree_opts opts;
1648
+ git_merge_options opts;
1567
1649
  git_merge_diff *conflict;
1568
1650
  git_vector changes;
1569
1651
  size_t i;
1570
1652
  int error = 0;
1571
1653
 
1572
- assert(out && repo && our_tree && their_tree);
1654
+ assert(out && repo && (our_tree || their_tree));
1573
1655
 
1574
1656
  *out = NULL;
1575
1657
 
1576
- if ((error = merge_tree_normalize_opts(repo, &opts, given_opts)) < 0)
1658
+ GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
1659
+
1660
+ if ((error = merge_normalize_opts(repo, &opts, given_opts)) < 0)
1577
1661
  return error;
1578
1662
 
1579
1663
  diff_list = git_merge_diff_list__alloc(repo);
@@ -1589,7 +1673,7 @@ int git_merge_trees(
1589
1673
  git_vector_foreach(&changes, i, conflict) {
1590
1674
  int resolved = 0;
1591
1675
 
1592
- if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.automerge_flags)) < 0)
1676
+ if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.file_favor)) < 0)
1593
1677
  goto done;
1594
1678
 
1595
1679
  if (!resolved)
@@ -1607,6 +1691,40 @@ done:
1607
1691
  return error;
1608
1692
  }
1609
1693
 
1694
+ int git_merge_commits(
1695
+ git_index **out,
1696
+ git_repository *repo,
1697
+ const git_commit *our_commit,
1698
+ const git_commit *their_commit,
1699
+ const git_merge_options *opts)
1700
+ {
1701
+ git_oid ancestor_oid;
1702
+ git_commit *ancestor_commit = NULL;
1703
+ git_tree *our_tree = NULL, *their_tree = NULL, *ancestor_tree = NULL;
1704
+ int error = 0;
1705
+
1706
+ if ((error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))) < 0 &&
1707
+ error == GIT_ENOTFOUND)
1708
+ giterr_clear();
1709
+ else if (error < 0 ||
1710
+ (error = git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)) < 0 ||
1711
+ (error = git_commit_tree(&ancestor_tree, ancestor_commit)) < 0)
1712
+ goto done;
1713
+
1714
+ if ((error = git_commit_tree(&our_tree, our_commit)) < 0 ||
1715
+ (error = git_commit_tree(&their_tree, their_commit)) < 0 ||
1716
+ (error = git_merge_trees(out, repo, ancestor_tree, our_tree, their_tree, opts)) < 0)
1717
+ goto done;
1718
+
1719
+ done:
1720
+ git_commit_free(ancestor_commit);
1721
+ git_tree_free(our_tree);
1722
+ git_tree_free(their_tree);
1723
+ git_tree_free(ancestor_tree);
1724
+
1725
+ return error;
1726
+ }
1727
+
1610
1728
  /* Merge setup / cleanup */
1611
1729
 
1612
1730
  static int write_orig_head(
@@ -1615,17 +1733,14 @@ static int write_orig_head(
1615
1733
  {
1616
1734
  git_filebuf file = GIT_FILEBUF_INIT;
1617
1735
  git_buf file_path = GIT_BUF_INIT;
1618
- char orig_oid_str[GIT_OID_HEXSZ + 1];
1619
1736
  int error = 0;
1620
1737
 
1621
1738
  assert(repo && our_head);
1622
1739
 
1623
- git_oid_tostr(orig_oid_str, GIT_OID_HEXSZ+1, &our_head->oid);
1624
-
1625
1740
  if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
1626
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) == 0 &&
1627
- (error = git_filebuf_printf(&file, "%s\n", orig_oid_str)) == 0)
1628
- error = git_filebuf_commit(&file, 0666);
1741
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
1742
+ (error = git_filebuf_printf(&file, "%s\n", our_head->oid_str)) == 0)
1743
+ error = git_filebuf_commit(&file);
1629
1744
 
1630
1745
  if (error < 0)
1631
1746
  git_filebuf_cleanup(&file);
@@ -1642,24 +1757,21 @@ static int write_merge_head(
1642
1757
  {
1643
1758
  git_filebuf file = GIT_FILEBUF_INIT;
1644
1759
  git_buf file_path = GIT_BUF_INIT;
1645
- char merge_oid_str[GIT_OID_HEXSZ + 1];
1646
1760
  size_t i;
1647
1761
  int error = 0;
1648
1762
 
1649
1763
  assert(repo && heads);
1650
1764
 
1651
1765
  if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_HEAD_FILE)) < 0 ||
1652
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0)
1766
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
1653
1767
  goto cleanup;
1654
1768
 
1655
1769
  for (i = 0; i < heads_len; i++) {
1656
- git_oid_tostr(merge_oid_str, GIT_OID_HEXSZ+1, &heads[i]->oid);
1657
-
1658
- if ((error = git_filebuf_printf(&file, "%s\n", merge_oid_str)) < 0)
1770
+ if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->oid_str)) < 0)
1659
1771
  goto cleanup;
1660
1772
  }
1661
1773
 
1662
- error = git_filebuf_commit(&file, 0666);
1774
+ error = git_filebuf_commit(&file);
1663
1775
 
1664
1776
  cleanup:
1665
1777
  if (error < 0)
@@ -1670,22 +1782,22 @@ cleanup:
1670
1782
  return error;
1671
1783
  }
1672
1784
 
1673
- static int write_merge_mode(git_repository *repo, unsigned int flags)
1785
+ static int write_merge_mode(git_repository *repo)
1674
1786
  {
1675
1787
  git_filebuf file = GIT_FILEBUF_INIT;
1676
1788
  git_buf file_path = GIT_BUF_INIT;
1677
1789
  int error = 0;
1678
1790
 
1679
- /* For future expansion */
1680
- GIT_UNUSED(flags);
1681
-
1682
1791
  assert(repo);
1683
1792
 
1684
1793
  if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MODE_FILE)) < 0 ||
1685
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0)
1794
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
1795
+ goto cleanup;
1796
+
1797
+ if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0)
1686
1798
  goto cleanup;
1687
1799
 
1688
- error = git_filebuf_commit(&file, 0666);
1800
+ error = git_filebuf_commit(&file);
1689
1801
 
1690
1802
  cleanup:
1691
1803
  if (error < 0)
@@ -1890,7 +2002,6 @@ static int write_merge_msg(
1890
2002
  {
1891
2003
  git_filebuf file = GIT_FILEBUF_INIT;
1892
2004
  git_buf file_path = GIT_BUF_INIT;
1893
- char oid_str[GIT_OID_HEXSZ + 1];
1894
2005
  struct merge_msg_entry *entries;
1895
2006
  git_vector matching = GIT_VECTOR_INIT;
1896
2007
  size_t i;
@@ -1902,14 +2013,16 @@ static int write_merge_msg(
1902
2013
  entries = git__calloc(heads_len, sizeof(struct merge_msg_entry));
1903
2014
  GITERR_CHECK_ALLOC(entries);
1904
2015
 
1905
- if (git_vector_init(&matching, heads_len, NULL) < 0)
2016
+ if (git_vector_init(&matching, heads_len, NULL) < 0) {
2017
+ git__free(entries);
1906
2018
  return -1;
2019
+ }
1907
2020
 
1908
2021
  for (i = 0; i < heads_len; i++)
1909
2022
  entries[i].merge_head = heads[i];
1910
2023
 
1911
2024
  if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
1912
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0 ||
2025
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 ||
1913
2026
  (error = git_filebuf_write(&file, "Merge ", 6)) < 0)
1914
2027
  goto cleanup;
1915
2028
 
@@ -1928,10 +2041,9 @@ static int write_merge_msg(
1928
2041
  if (!msg_entry_is_oid(&entries[i]))
1929
2042
  break;
1930
2043
 
1931
- git_oid_fmt(oid_str, &entries[i].merge_head->oid);
1932
- oid_str[GIT_OID_HEXSZ] = '\0';
1933
-
1934
- if ((error = git_filebuf_printf(&file, "%scommit '%s'", (i > 0) ? "; " : "", oid_str)) < 0)
2044
+ if ((error = git_filebuf_printf(&file,
2045
+ "%scommit '%s'", (i > 0) ? "; " : "",
2046
+ entries[i].merge_head->oid_str)) < 0)
1935
2047
  goto cleanup;
1936
2048
 
1937
2049
  entries[i].written = 1;
@@ -1978,15 +2090,13 @@ static int write_merge_msg(
1978
2090
  if (merge_msg_entry_written(&entries[i]))
1979
2091
  continue;
1980
2092
 
1981
- git_oid_fmt(oid_str, &entries[i].merge_head->oid);
1982
- oid_str[GIT_OID_HEXSZ] = '\0';
1983
-
1984
- if ((error = git_filebuf_printf(&file, "; commit '%s'", oid_str)) < 0)
2093
+ if ((error = git_filebuf_printf(&file, "; commit '%s'",
2094
+ entries[i].merge_head->oid_str)) < 0)
1985
2095
  goto cleanup;
1986
2096
  }
1987
2097
 
1988
2098
  if ((error = git_filebuf_printf(&file, "\n")) < 0 ||
1989
- (error = git_filebuf_commit(&file, 0666)) < 0)
2099
+ (error = git_filebuf_commit(&file)) < 0)
1990
2100
  goto cleanup;
1991
2101
 
1992
2102
  cleanup:
@@ -2005,51 +2115,615 @@ int git_merge__setup(
2005
2115
  git_repository *repo,
2006
2116
  const git_merge_head *our_head,
2007
2117
  const git_merge_head *heads[],
2008
- size_t heads_len,
2009
- unsigned int flags)
2118
+ size_t heads_len)
2010
2119
  {
2011
2120
  int error = 0;
2012
2121
 
2013
2122
  assert (repo && our_head && heads);
2014
-
2123
+
2015
2124
  if ((error = write_orig_head(repo, our_head)) == 0 &&
2016
2125
  (error = write_merge_head(repo, heads, heads_len)) == 0 &&
2017
- (error = write_merge_mode(repo, flags)) == 0) {
2126
+ (error = write_merge_mode(repo)) == 0) {
2018
2127
  error = write_merge_msg(repo, heads, heads_len);
2019
2128
  }
2020
2129
 
2021
2130
  return error;
2022
2131
  }
2023
2132
 
2024
- int git_repository_merge_cleanup(git_repository *repo)
2133
+ /* Merge branches */
2134
+
2135
+ static int merge_ancestor_head(
2136
+ git_merge_head **ancestor_head,
2137
+ git_repository *repo,
2138
+ const git_merge_head *our_head,
2139
+ const git_merge_head **their_heads,
2140
+ size_t their_heads_len)
2025
2141
  {
2142
+ git_oid *oids, ancestor_oid;
2143
+ size_t i;
2026
2144
  int error = 0;
2027
- git_buf merge_head_path = GIT_BUF_INIT,
2028
- merge_mode_path = GIT_BUF_INIT,
2029
- merge_msg_path = GIT_BUF_INIT;
2030
2145
 
2031
- assert(repo);
2146
+ assert(repo && our_head && their_heads);
2032
2147
 
2033
- if (git_buf_joinpath(&merge_head_path, repo->path_repository, GIT_MERGE_HEAD_FILE) < 0 ||
2034
- git_buf_joinpath(&merge_mode_path, repo->path_repository, GIT_MERGE_MODE_FILE) < 0 ||
2035
- git_buf_joinpath(&merge_msg_path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
2036
- return -1;
2148
+ oids = git__calloc(their_heads_len + 1, sizeof(git_oid));
2149
+ GITERR_CHECK_ALLOC(oids);
2037
2150
 
2038
- if (git_path_isfile(merge_head_path.ptr)) {
2039
- if ((error = p_unlink(merge_head_path.ptr)) < 0)
2040
- goto cleanup;
2151
+ git_oid_cpy(&oids[0], git_commit_id(our_head->commit));
2152
+
2153
+ for (i = 0; i < their_heads_len; i++)
2154
+ git_oid_cpy(&oids[i + 1], &their_heads[i]->oid);
2155
+
2156
+ if ((error = git_merge_base_many(&ancestor_oid, repo, their_heads_len + 1, oids)) < 0)
2157
+ goto on_error;
2158
+
2159
+ error = git_merge_head_from_id(ancestor_head, repo, &ancestor_oid);
2160
+
2161
+ on_error:
2162
+ git__free(oids);
2163
+ return error;
2164
+ }
2165
+
2166
+ const char *merge_their_label(const char *branchname)
2167
+ {
2168
+ const char *slash;
2169
+
2170
+ if ((slash = strrchr(branchname, '/')) == NULL)
2171
+ return branchname;
2172
+
2173
+ if (*(slash+1) == '\0')
2174
+ return "theirs";
2175
+
2176
+ return slash+1;
2177
+ }
2178
+
2179
+ static int merge_normalize_checkout_opts(
2180
+ git_repository *repo,
2181
+ git_checkout_options *checkout_opts,
2182
+ const git_checkout_options *given_checkout_opts,
2183
+ const git_merge_head *ancestor_head,
2184
+ const git_merge_head *our_head,
2185
+ size_t their_heads_len,
2186
+ const git_merge_head **their_heads)
2187
+ {
2188
+ int error = 0;
2189
+
2190
+ GIT_UNUSED(repo);
2191
+
2192
+ if (given_checkout_opts != NULL)
2193
+ memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options));
2194
+ else {
2195
+ git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
2196
+ default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE |
2197
+ GIT_CHECKOUT_ALLOW_CONFLICTS;
2198
+
2199
+ memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options));
2200
+ }
2201
+
2202
+ /* TODO: for multiple ancestors in merge-recursive, this is "merged common ancestors" */
2203
+ if (!checkout_opts->ancestor_label) {
2204
+ if (ancestor_head && ancestor_head->commit)
2205
+ checkout_opts->ancestor_label = git_commit_summary(ancestor_head->commit);
2206
+ else
2207
+ checkout_opts->ancestor_label = "ancestor";
2208
+ }
2209
+
2210
+ if (!checkout_opts->our_label) {
2211
+ if (our_head && our_head->ref_name)
2212
+ checkout_opts->our_label = our_head->ref_name;
2213
+ else
2214
+ checkout_opts->our_label = "ours";
2215
+ }
2216
+
2217
+ if (!checkout_opts->their_label) {
2218
+ if (their_heads_len == 1 && their_heads[0]->ref_name)
2219
+ checkout_opts->their_label = merge_their_label(their_heads[0]->ref_name);
2220
+ else if (their_heads_len == 1)
2221
+ checkout_opts->their_label = their_heads[0]->oid_str;
2222
+ else
2223
+ checkout_opts->their_label = "theirs";
2224
+ }
2225
+
2226
+ return error;
2227
+ }
2228
+
2229
+ static int merge_affected_paths(git_vector *paths, git_repository *repo, git_index *index_new)
2230
+ {
2231
+ git_tree *head_tree = NULL;
2232
+ git_iterator *iter_head = NULL, *iter_new = NULL;
2233
+ git_diff *merged_list = NULL;
2234
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
2235
+ git_diff_delta *delta;
2236
+ size_t i;
2237
+ const git_index_entry *e;
2238
+ char *path;
2239
+ int error = 0;
2240
+
2241
+ if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
2242
+ (error = git_iterator_for_tree(&iter_head, head_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2243
+ (error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2244
+ (error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0)
2245
+ goto done;
2246
+
2247
+ git_vector_foreach(&merged_list->deltas, i, delta) {
2248
+ path = git__strdup(delta->new_file.path);
2249
+ GITERR_CHECK_ALLOC(path);
2250
+
2251
+ if ((error = git_vector_insert(paths, path)) < 0)
2252
+ goto on_error;
2253
+ }
2254
+
2255
+ for (i = 0; i < git_index_entrycount(index_new); i++) {
2256
+ e = git_index_get_byindex(index_new, i);
2257
+
2258
+ if (git_index_entry_stage(e) != 0 &&
2259
+ (git_vector_last(paths) == NULL ||
2260
+ strcmp(git_vector_last(paths), e->path) != 0)) {
2261
+
2262
+ path = git__strdup(e->path);
2263
+ GITERR_CHECK_ALLOC(path);
2264
+
2265
+ if ((error = git_vector_insert(paths, path)) < 0)
2266
+ goto on_error;
2267
+ }
2268
+ }
2269
+
2270
+ goto done;
2271
+
2272
+ on_error:
2273
+ git_vector_foreach(paths, i, path)
2274
+ git__free(path);
2275
+
2276
+ git_vector_clear(paths);
2277
+
2278
+ done:
2279
+ git_tree_free(head_tree);
2280
+ git_iterator_free(iter_head);
2281
+ git_iterator_free(iter_new);
2282
+ git_diff_free(merged_list);
2283
+
2284
+ return error;
2285
+ }
2286
+
2287
+ static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
2288
+ {
2289
+ git_tree *head_tree = NULL;
2290
+ git_index *index_repo = NULL;
2291
+ git_iterator *iter_repo = NULL, *iter_new = NULL;
2292
+ git_diff *staged_diff_list = NULL, *index_diff_list = NULL;
2293
+ git_diff_delta *delta;
2294
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
2295
+ git_vector staged_paths = GIT_VECTOR_INIT;
2296
+ size_t i;
2297
+ int error = 0;
2298
+
2299
+ GIT_UNUSED(merged_paths);
2300
+
2301
+ *conflicts = 0;
2302
+
2303
+ /* No staged changes may exist unless the change staged is identical to
2304
+ * the result of the merge. This allows one to apply to merge manually,
2305
+ * then run merge. Any other staged change would be overwritten by
2306
+ * a reset merge.
2307
+ */
2308
+ if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
2309
+ (error = git_repository_index(&index_repo, repo)) < 0 ||
2310
+ (error = git_diff_tree_to_index(&staged_diff_list, repo, head_tree, index_repo, &opts)) < 0)
2311
+ goto done;
2312
+
2313
+ if (staged_diff_list->deltas.length == 0)
2314
+ goto done;
2315
+
2316
+ git_vector_foreach(&staged_diff_list->deltas, i, delta) {
2317
+ if ((error = git_vector_insert(&staged_paths, (char *)delta->new_file.path)) < 0)
2318
+ goto done;
2319
+ }
2320
+
2321
+ opts.pathspec.count = staged_paths.length;
2322
+ opts.pathspec.strings = (char **)staged_paths.contents;
2323
+
2324
+ if ((error = git_iterator_for_index(&iter_repo, index_repo, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2325
+ (error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2326
+ (error = git_diff__from_iterators(&index_diff_list, repo, iter_repo, iter_new, &opts)) < 0)
2327
+ goto done;
2328
+
2329
+ *conflicts = index_diff_list->deltas.length;
2330
+
2331
+ done:
2332
+ git_tree_free(head_tree);
2333
+ git_index_free(index_repo);
2334
+ git_iterator_free(iter_repo);
2335
+ git_iterator_free(iter_new);
2336
+ git_diff_free(staged_diff_list);
2337
+ git_diff_free(index_diff_list);
2338
+ git_vector_free(&staged_paths);
2339
+
2340
+ return error;
2341
+ }
2342
+
2343
+ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
2344
+ {
2345
+ git_index *index_repo = NULL;
2346
+ git_diff *wd_diff_list = NULL;
2347
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
2348
+ int error = 0;
2349
+
2350
+ GIT_UNUSED(index_new);
2351
+
2352
+ *conflicts = 0;
2353
+
2354
+ opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
2355
+
2356
+ /* Workdir changes may exist iff they do not conflict with changes that
2357
+ * will be applied by the merge (including conflicts). Ensure that there
2358
+ * are no changes in the workdir to these paths.
2359
+ */
2360
+ opts.pathspec.count = merged_paths->length;
2361
+ opts.pathspec.strings = (char **)merged_paths->contents;
2362
+
2363
+ if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, index_repo, &opts)) < 0)
2364
+ goto done;
2365
+
2366
+ *conflicts = wd_diff_list->deltas.length;
2367
+
2368
+ done:
2369
+ git_index_free(index_repo);
2370
+ git_diff_free(wd_diff_list);
2371
+
2372
+ return error;
2373
+ }
2374
+
2375
+ int git_merge__indexes(git_repository *repo, git_index *index_new)
2376
+ {
2377
+ git_index *index_repo = NULL;
2378
+ int index_repo_caps = 0;
2379
+ git_vector paths = GIT_VECTOR_INIT;
2380
+ size_t index_conflicts = 0, wd_conflicts = 0, conflicts, i;
2381
+ char *path;
2382
+ const git_index_entry *e;
2383
+ const git_index_name_entry *name;
2384
+ const git_index_reuc_entry *reuc;
2385
+ int error = 0;
2386
+
2387
+ if ((error = git_repository_index(&index_repo, repo)) < 0)
2388
+ goto done;
2389
+
2390
+ /* Set the index to case sensitive to handle the merge */
2391
+ index_repo_caps = git_index_caps(index_repo);
2392
+
2393
+ if ((error = git_index_set_caps(index_repo, (index_repo_caps & ~GIT_INDEXCAP_IGNORE_CASE))) < 0)
2394
+ goto done;
2395
+
2396
+ /* Make sure the index and workdir state do not prevent merging */
2397
+ if ((error = merge_affected_paths(&paths, repo, index_new)) < 0 ||
2398
+ (error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 ||
2399
+ (error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0)
2400
+ goto done;
2401
+
2402
+ if ((conflicts = index_conflicts + wd_conflicts) > 0) {
2403
+ giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge",
2404
+ conflicts, (conflicts != 1) ? "s" : "");
2405
+ error = GIT_EMERGECONFLICT;
2406
+
2407
+ goto done;
2408
+ }
2409
+
2410
+ /* Remove removed items from the index */
2411
+ git_vector_foreach(&paths, i, path) {
2412
+ if (git_index_get_bypath(index_new, path, 0) == NULL) {
2413
+ if ((error = git_index_remove(index_repo, path, 0)) < 0 &&
2414
+ error != GIT_ENOTFOUND)
2415
+ goto done;
2416
+ }
2417
+ }
2418
+
2419
+ /* Add updated items to the index */
2420
+ git_vector_foreach(&paths, i, path) {
2421
+ if ((e = git_index_get_bypath(index_new, path, 0)) != NULL) {
2422
+ if ((error = git_index_add(index_repo, e)) < 0)
2423
+ goto done;
2424
+ }
2041
2425
  }
2042
2426
 
2043
- if (git_path_isfile(merge_mode_path.ptr))
2044
- (void)p_unlink(merge_mode_path.ptr);
2427
+ /* Add conflicts */
2428
+ git_index_conflict_cleanup(index_repo);
2429
+
2430
+ for (i = 0; i < git_index_entrycount(index_new); i++) {
2431
+ e = git_index_get_byindex(index_new, i);
2432
+
2433
+ if (git_index_entry_stage(e) != 0 &&
2434
+ (error = git_index_add(index_repo, e)) < 0)
2435
+ goto done;
2436
+ }
2437
+
2438
+ /* Add name entries */
2439
+ git_index_name_clear(index_repo);
2440
+
2441
+ for (i = 0; i < git_index_name_entrycount(index_new); i++) {
2442
+ name = git_index_name_get_byindex(index_new, i);
2443
+
2444
+ if ((error = git_index_name_add(index_repo,
2445
+ name->ancestor, name->ours, name->theirs)) < 0)
2446
+ goto done;
2447
+ }
2448
+
2449
+ /* Add the reuc */
2450
+ git_index_reuc_clear(index_repo);
2451
+
2452
+ for (i = 0; i < git_index_reuc_entrycount(index_new); i++) {
2453
+ reuc = (git_index_reuc_entry *)git_index_reuc_get_byindex(index_new, i);
2454
+
2455
+ if ((error = git_index_reuc_add(index_repo, reuc->path,
2456
+ reuc->mode[0], &reuc->oid[0],
2457
+ reuc->mode[1], &reuc->oid[1],
2458
+ reuc->mode[2], &reuc->oid[2])) < 0)
2459
+ goto done;
2460
+ }
2461
+
2462
+ done:
2463
+ if (index_repo != NULL)
2464
+ git_index_set_caps(index_repo, index_repo_caps);
2465
+
2466
+ git_index_free(index_repo);
2467
+ git_vector_free_deep(&paths);
2468
+
2469
+ return error;
2470
+ }
2471
+
2472
+ int git_merge__append_conflicts_to_merge_msg(
2473
+ git_repository *repo,
2474
+ git_index *index)
2475
+ {
2476
+ git_filebuf file = GIT_FILEBUF_INIT;
2477
+ git_buf file_path = GIT_BUF_INIT;
2478
+ const char *last = NULL;
2479
+ size_t i;
2480
+ int error;
2481
+
2482
+ if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
2483
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0)
2484
+ goto cleanup;
2485
+
2486
+ if (git_index_has_conflicts(index))
2487
+ git_filebuf_printf(&file, "\nConflicts:\n");
2045
2488
 
2046
- if (git_path_isfile(merge_msg_path.ptr))
2047
- (void)p_unlink(merge_msg_path.ptr);
2489
+ for (i = 0; i < git_index_entrycount(index); i++) {
2490
+ const git_index_entry *e = git_index_get_byindex(index, i);
2491
+
2492
+ if (git_index_entry_stage(e) == 0)
2493
+ continue;
2494
+
2495
+ if (last == NULL || strcmp(e->path, last) != 0)
2496
+ git_filebuf_printf(&file, "\t%s\n", e->path);
2497
+
2498
+ last = e->path;
2499
+ }
2500
+
2501
+ error = git_filebuf_commit(&file);
2048
2502
 
2049
2503
  cleanup:
2050
- git_buf_free(&merge_msg_path);
2051
- git_buf_free(&merge_mode_path);
2052
- git_buf_free(&merge_head_path);
2504
+ if (error < 0)
2505
+ git_filebuf_cleanup(&file);
2506
+
2507
+ git_buf_free(&file_path);
2508
+
2509
+ return error;
2510
+ }
2511
+
2512
+
2513
+ static int merge_state_cleanup(git_repository *repo)
2514
+ {
2515
+ const char *state_files[] = {
2516
+ GIT_MERGE_HEAD_FILE,
2517
+ GIT_MERGE_MODE_FILE,
2518
+ GIT_MERGE_MSG_FILE,
2519
+ };
2520
+
2521
+ return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
2522
+ }
2523
+
2524
+ static int merge_heads(
2525
+ git_merge_head **ancestor_head_out,
2526
+ git_merge_head **our_head_out,
2527
+ git_repository *repo,
2528
+ const git_merge_head **their_heads,
2529
+ size_t their_heads_len)
2530
+ {
2531
+ git_merge_head *ancestor_head = NULL, *our_head = NULL;
2532
+ git_reference *our_ref = NULL;
2533
+ int error = 0;
2534
+
2535
+ *ancestor_head_out = NULL;
2536
+ *our_head_out = NULL;
2537
+
2538
+ if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
2539
+ goto done;
2540
+
2541
+ if ((error = git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE)) < 0 ||
2542
+ (error = git_merge_head_from_ref(&our_head, repo, our_ref)) < 0)
2543
+ goto done;
2544
+
2545
+ if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) {
2546
+ if (error != GIT_ENOTFOUND)
2547
+ goto done;
2548
+
2549
+ giterr_clear();
2550
+ error = 0;
2551
+ }
2552
+
2553
+ *ancestor_head_out = ancestor_head;
2554
+ *our_head_out = our_head;
2555
+
2556
+ done:
2557
+ if (error < 0) {
2558
+ git_merge_head_free(ancestor_head);
2559
+ git_merge_head_free(our_head);
2560
+ }
2561
+
2562
+ git_reference_free(our_ref);
2563
+
2564
+ return error;
2565
+ }
2566
+
2567
+ static int merge_preference(git_merge_preference_t *out, git_repository *repo)
2568
+ {
2569
+ git_config *config;
2570
+ const char *value;
2571
+ int bool_value, error = 0;
2572
+
2573
+ *out = GIT_MERGE_PREFERENCE_NONE;
2574
+
2575
+ if ((error = git_repository_config_snapshot(&config, repo)) < 0)
2576
+ goto done;
2577
+
2578
+ if ((error = git_config_get_string(&value, config, "merge.ff")) < 0) {
2579
+ if (error == GIT_ENOTFOUND) {
2580
+ giterr_clear();
2581
+ error = 0;
2582
+ }
2583
+
2584
+ goto done;
2585
+ }
2586
+
2587
+ if (git_config_parse_bool(&bool_value, value) == 0) {
2588
+ if (!bool_value)
2589
+ *out |= GIT_MERGE_PREFERENCE_NO_FASTFORWARD;
2590
+ } else {
2591
+ if (strcasecmp(value, "only") == 0)
2592
+ *out |= GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY;
2593
+ }
2594
+
2595
+ done:
2596
+ git_config_free(config);
2597
+ return error;
2598
+ }
2599
+
2600
+ int git_merge_analysis(
2601
+ git_merge_analysis_t *analysis_out,
2602
+ git_merge_preference_t *preference_out,
2603
+ git_repository *repo,
2604
+ const git_merge_head **their_heads,
2605
+ size_t their_heads_len)
2606
+ {
2607
+ git_merge_head *ancestor_head = NULL, *our_head = NULL;
2608
+ int error = 0;
2609
+
2610
+ assert(analysis_out && preference_out && repo && their_heads);
2611
+
2612
+ if (their_heads_len != 1) {
2613
+ giterr_set(GITERR_MERGE, "Can only merge a single branch");
2614
+ error = -1;
2615
+ goto done;
2616
+ }
2617
+
2618
+ *analysis_out = GIT_MERGE_ANALYSIS_NONE;
2619
+
2620
+ if ((error = merge_preference(preference_out, repo)) < 0)
2621
+ goto done;
2622
+
2623
+ if (git_repository_head_unborn(repo)) {
2624
+ *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN;
2625
+ goto done;
2626
+ }
2627
+
2628
+ if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0)
2629
+ goto done;
2630
+
2631
+ /* We're up-to-date if we're trying to merge our own common ancestor. */
2632
+ if (ancestor_head && git_oid_equal(&ancestor_head->oid, &their_heads[0]->oid))
2633
+ *analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE;
2634
+
2635
+ /* We're fastforwardable if we're our own common ancestor. */
2636
+ else if (ancestor_head && git_oid_equal(&ancestor_head->oid, &our_head->oid))
2637
+ *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL;
2638
+
2639
+ /* Otherwise, just a normal merge is possible. */
2640
+ else
2641
+ *analysis_out |= GIT_MERGE_ANALYSIS_NORMAL;
2642
+
2643
+ done:
2644
+ git_merge_head_free(ancestor_head);
2645
+ git_merge_head_free(our_head);
2646
+ return error;
2647
+ }
2648
+
2649
+ int git_merge(
2650
+ git_repository *repo,
2651
+ const git_merge_head **their_heads,
2652
+ size_t their_heads_len,
2653
+ const git_merge_options *merge_opts,
2654
+ const git_checkout_options *given_checkout_opts)
2655
+ {
2656
+ git_reference *our_ref = NULL;
2657
+ git_checkout_options checkout_opts;
2658
+ git_merge_head *ancestor_head = NULL, *our_head = NULL;
2659
+ git_tree *ancestor_tree = NULL, *our_tree = NULL, **their_trees = NULL;
2660
+ git_index *index_new = NULL, *index_repo = NULL;
2661
+ size_t i;
2662
+ int error = 0;
2663
+
2664
+ assert(repo && their_heads);
2665
+
2666
+ if (their_heads_len != 1) {
2667
+ giterr_set(GITERR_MERGE, "Can only merge a single branch");
2668
+ return -1;
2669
+ }
2670
+
2671
+ their_trees = git__calloc(their_heads_len, sizeof(git_tree *));
2672
+ GITERR_CHECK_ALLOC(their_trees);
2673
+
2674
+ if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0)
2675
+ goto on_error;
2676
+
2677
+ if ((error = merge_normalize_checkout_opts(repo, &checkout_opts, given_checkout_opts,
2678
+ ancestor_head, our_head, their_heads_len, their_heads)) < 0)
2679
+ goto on_error;
2680
+
2681
+ /* Write the merge files to the repository. */
2682
+ if ((error = git_merge__setup(repo, our_head, their_heads, their_heads_len)) < 0)
2683
+ goto on_error;
2684
+
2685
+ if (ancestor_head != NULL &&
2686
+ (error = git_commit_tree(&ancestor_tree, ancestor_head->commit)) < 0)
2687
+ goto on_error;
2688
+
2689
+ if ((error = git_commit_tree(&our_tree, our_head->commit)) < 0)
2690
+ goto on_error;
2691
+
2692
+ for (i = 0; i < their_heads_len; i++) {
2693
+ if ((error = git_commit_tree(&their_trees[i], their_heads[i]->commit)) < 0)
2694
+ goto on_error;
2695
+ }
2696
+
2697
+ /* TODO: recursive, octopus, etc... */
2698
+
2699
+ if ((error = git_merge_trees(&index_new, repo, ancestor_tree, our_tree, their_trees[0], merge_opts)) < 0 ||
2700
+ (error = git_merge__indexes(repo, index_new)) < 0 ||
2701
+ (error = git_repository_index(&index_repo, repo)) < 0 ||
2702
+ (error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 ||
2703
+ (error = git_checkout_index(repo, index_repo, &checkout_opts)) < 0)
2704
+ goto on_error;
2705
+
2706
+ goto done;
2707
+
2708
+ on_error:
2709
+ merge_state_cleanup(repo);
2710
+
2711
+ done:
2712
+ git_index_free(index_new);
2713
+ git_index_free(index_repo);
2714
+
2715
+ git_tree_free(ancestor_tree);
2716
+ git_tree_free(our_tree);
2717
+
2718
+ for (i = 0; i < their_heads_len; i++)
2719
+ git_tree_free(their_trees[i]);
2720
+
2721
+ git__free(their_trees);
2722
+
2723
+ git_merge_head_free(our_head);
2724
+ git_merge_head_free(ancestor_head);
2725
+
2726
+ git_reference_free(our_ref);
2053
2727
 
2054
2728
  return error;
2055
2729
  }
@@ -2085,6 +2759,9 @@ static int merge_head_init(
2085
2759
 
2086
2760
  git_oid_cpy(&head->oid, oid);
2087
2761
 
2762
+ git_oid_fmt(head->oid_str, oid);
2763
+ head->oid_str[GIT_OID_HEXSZ] = '\0';
2764
+
2088
2765
  if ((error = git_commit_lookup(&head->commit, repo, &head->oid)) < 0) {
2089
2766
  git_merge_head_free(head);
2090
2767
  return error;
@@ -2097,7 +2774,7 @@ static int merge_head_init(
2097
2774
  int git_merge_head_from_ref(
2098
2775
  git_merge_head **out,
2099
2776
  git_repository *repo,
2100
- git_reference *ref)
2777
+ const git_reference *ref)
2101
2778
  {
2102
2779
  git_reference *resolved;
2103
2780
  int error = 0;
@@ -2116,7 +2793,7 @@ int git_merge_head_from_ref(
2116
2793
  return error;
2117
2794
  }
2118
2795
 
2119
- int git_merge_head_from_oid(
2796
+ int git_merge_head_from_id(
2120
2797
  git_merge_head **out,
2121
2798
  git_repository *repo,
2122
2799
  const git_oid *oid)
@@ -2138,6 +2815,14 @@ int git_merge_head_from_fetchhead(
2138
2815
  return merge_head_init(out, repo, branch_name, remote_url, oid);
2139
2816
  }
2140
2817
 
2818
+ const git_oid *git_merge_head_id(
2819
+ const git_merge_head *head)
2820
+ {
2821
+ assert(head);
2822
+
2823
+ return &head->oid;
2824
+ }
2825
+
2141
2826
  void git_merge_head_free(git_merge_head *head)
2142
2827
  {
2143
2828
  if (head == NULL)
@@ -2154,3 +2839,25 @@ void git_merge_head_free(git_merge_head *head)
2154
2839
 
2155
2840
  git__free(head);
2156
2841
  }
2842
+
2843
+ int git_merge_init_options(git_merge_options *opts, unsigned int version)
2844
+ {
2845
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2846
+ opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT);
2847
+ return 0;
2848
+ }
2849
+
2850
+ int git_merge_file_init_input(git_merge_file_input *input, unsigned int version)
2851
+ {
2852
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2853
+ input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT);
2854
+ return 0;
2855
+ }
2856
+
2857
+ int git_merge_file_init_options(
2858
+ git_merge_file_options *opts, unsigned int version)
2859
+ {
2860
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2861
+ opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT);
2862
+ return 0;
2863
+ }