rugged 0.17.0.b7 → 0.18.0.b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +88 -32
  3. data/ext/rugged/extconf.rb +4 -2
  4. data/ext/rugged/rugged.c +72 -10
  5. data/ext/rugged/rugged.h +14 -10
  6. data/ext/rugged/rugged_blob.c +8 -10
  7. data/ext/rugged/rugged_branch.c +11 -14
  8. data/ext/rugged/rugged_commit.c +31 -24
  9. data/ext/rugged/rugged_config.c +2 -2
  10. data/ext/rugged/rugged_index.c +133 -198
  11. data/ext/rugged/rugged_note.c +372 -0
  12. data/ext/rugged/rugged_object.c +50 -22
  13. data/ext/rugged/rugged_reference.c +122 -130
  14. data/ext/rugged/rugged_remote.c +72 -29
  15. data/ext/rugged/rugged_repo.c +402 -20
  16. data/ext/rugged/rugged_revwalk.c +7 -3
  17. data/ext/rugged/rugged_settings.c +110 -0
  18. data/ext/rugged/rugged_signature.c +23 -7
  19. data/ext/rugged/rugged_tag.c +32 -16
  20. data/ext/rugged/rugged_tree.c +44 -15
  21. data/lib/rugged.rb +1 -0
  22. data/lib/rugged/index.rb +8 -0
  23. data/lib/rugged/remote.rb +13 -0
  24. data/lib/rugged/repository.rb +3 -3
  25. data/lib/rugged/version.rb +1 -1
  26. data/test/blob_test.rb +13 -15
  27. data/test/branch_test.rb +32 -67
  28. data/test/commit_test.rb +50 -12
  29. data/test/config_test.rb +12 -11
  30. data/test/coverage/HEAD.json +1 -1
  31. data/test/coverage/cover.rb +40 -21
  32. data/test/errors_test.rb +34 -0
  33. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  34. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  35. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  36. data/test/fixtures/testrepo.git/logs/refs/notes/commits +1 -0
  37. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +1 -0
  38. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  39. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +1 -0
  40. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  41. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  42. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +3 -0
  43. data/test/fixtures/testrepo.git/refs/notes/commits +1 -0
  44. data/test/index_test.rb +65 -69
  45. data/test/lib_test.rb +76 -11
  46. data/test/note_test.rb +158 -0
  47. data/test/object_test.rb +8 -11
  48. data/test/reference_test.rb +77 -85
  49. data/test/remote_test.rb +86 -8
  50. data/test/repo_pack_test.rb +9 -7
  51. data/test/repo_reset_test.rb +80 -0
  52. data/test/repo_test.rb +176 -53
  53. data/test/tag_test.rb +44 -7
  54. data/test/test_helper.rb +63 -35
  55. data/test/tree_test.rb +34 -13
  56. data/test/walker_test.rb +14 -14
  57. data/vendor/libgit2/Makefile.embed +1 -1
  58. data/vendor/libgit2/deps/http-parser/http_parser.c +974 -578
  59. data/vendor/libgit2/deps/http-parser/http_parser.h +106 -70
  60. data/vendor/libgit2/deps/regex/regcomp.c +7 -6
  61. data/vendor/libgit2/deps/regex/regex_internal.c +1 -1
  62. data/vendor/libgit2/deps/regex/regex_internal.h +12 -3
  63. data/vendor/libgit2/deps/regex/regexec.c +5 -5
  64. data/vendor/libgit2/include/git2.h +5 -1
  65. data/vendor/libgit2/include/git2/attr.h +4 -2
  66. data/vendor/libgit2/include/git2/blob.h +39 -12
  67. data/vendor/libgit2/include/git2/branch.h +123 -35
  68. data/vendor/libgit2/include/git2/checkout.h +206 -48
  69. data/vendor/libgit2/include/git2/clone.h +72 -27
  70. data/vendor/libgit2/include/git2/commit.h +20 -17
  71. data/vendor/libgit2/include/git2/common.h +67 -1
  72. data/vendor/libgit2/include/git2/config.h +81 -60
  73. data/vendor/libgit2/include/git2/cred_helpers.h +53 -0
  74. data/vendor/libgit2/include/git2/diff.h +459 -150
  75. data/vendor/libgit2/include/git2/errors.h +9 -1
  76. data/vendor/libgit2/include/git2/graph.h +41 -0
  77. data/vendor/libgit2/include/git2/ignore.h +7 -6
  78. data/vendor/libgit2/include/git2/index.h +323 -97
  79. data/vendor/libgit2/include/git2/indexer.h +27 -59
  80. data/vendor/libgit2/include/git2/inttypes.h +4 -0
  81. data/vendor/libgit2/include/git2/merge.h +13 -3
  82. data/vendor/libgit2/include/git2/message.h +14 -8
  83. data/vendor/libgit2/include/git2/net.h +9 -7
  84. data/vendor/libgit2/include/git2/notes.h +88 -29
  85. data/vendor/libgit2/include/git2/object.h +16 -6
  86. data/vendor/libgit2/include/git2/odb.h +80 -17
  87. data/vendor/libgit2/include/git2/odb_backend.h +47 -11
  88. data/vendor/libgit2/include/git2/oid.h +26 -17
  89. data/vendor/libgit2/include/git2/pack.h +62 -8
  90. data/vendor/libgit2/include/git2/push.h +131 -0
  91. data/vendor/libgit2/include/git2/refdb.h +103 -0
  92. data/vendor/libgit2/include/git2/refdb_backend.h +109 -0
  93. data/vendor/libgit2/include/git2/reflog.h +30 -21
  94. data/vendor/libgit2/include/git2/refs.h +215 -193
  95. data/vendor/libgit2/include/git2/refspec.h +22 -2
  96. data/vendor/libgit2/include/git2/remote.h +158 -37
  97. data/vendor/libgit2/include/git2/repository.h +150 -31
  98. data/vendor/libgit2/include/git2/reset.h +43 -9
  99. data/vendor/libgit2/include/git2/revparse.h +48 -4
  100. data/vendor/libgit2/include/git2/revwalk.h +25 -10
  101. data/vendor/libgit2/include/git2/signature.h +20 -12
  102. data/vendor/libgit2/include/git2/stash.h +121 -0
  103. data/vendor/libgit2/include/git2/status.h +122 -53
  104. data/vendor/libgit2/include/git2/strarray.h +17 -11
  105. data/vendor/libgit2/include/git2/submodule.h +42 -7
  106. data/vendor/libgit2/include/git2/tag.h +72 -59
  107. data/vendor/libgit2/include/git2/threads.h +4 -2
  108. data/vendor/libgit2/include/git2/trace.h +68 -0
  109. data/vendor/libgit2/include/git2/transport.h +328 -0
  110. data/vendor/libgit2/include/git2/tree.h +149 -120
  111. data/vendor/libgit2/include/git2/types.h +13 -12
  112. data/vendor/libgit2/include/git2/version.h +3 -3
  113. data/vendor/libgit2/src/amiga/map.c +2 -2
  114. data/vendor/libgit2/src/attr.c +58 -48
  115. data/vendor/libgit2/src/attr.h +4 -18
  116. data/vendor/libgit2/src/attr_file.c +30 -6
  117. data/vendor/libgit2/src/attr_file.h +6 -8
  118. data/vendor/libgit2/src/attrcache.h +24 -0
  119. data/vendor/libgit2/src/blob.c +30 -7
  120. data/vendor/libgit2/src/blob.h +1 -1
  121. data/vendor/libgit2/src/branch.c +361 -68
  122. data/vendor/libgit2/src/branch.h +17 -0
  123. data/vendor/libgit2/src/bswap.h +1 -1
  124. data/vendor/libgit2/src/buf_text.c +291 -0
  125. data/vendor/libgit2/src/buf_text.h +122 -0
  126. data/vendor/libgit2/src/buffer.c +27 -101
  127. data/vendor/libgit2/src/buffer.h +54 -39
  128. data/vendor/libgit2/src/cache.c +15 -6
  129. data/vendor/libgit2/src/cache.h +1 -1
  130. data/vendor/libgit2/src/cc-compat.h +3 -1
  131. data/vendor/libgit2/src/checkout.c +1165 -222
  132. data/vendor/libgit2/src/checkout.h +24 -0
  133. data/vendor/libgit2/src/clone.c +171 -86
  134. data/vendor/libgit2/src/commit.c +44 -45
  135. data/vendor/libgit2/src/commit.h +3 -3
  136. data/vendor/libgit2/src/commit_list.c +194 -0
  137. data/vendor/libgit2/src/commit_list.h +49 -0
  138. data/vendor/libgit2/src/common.h +44 -10
  139. data/vendor/libgit2/src/compress.c +1 -1
  140. data/vendor/libgit2/src/compress.h +1 -1
  141. data/vendor/libgit2/src/config.c +211 -124
  142. data/vendor/libgit2/src/config.h +23 -4
  143. data/vendor/libgit2/src/config_cache.c +2 -2
  144. data/vendor/libgit2/src/config_file.c +129 -53
  145. data/vendor/libgit2/src/config_file.h +10 -8
  146. data/vendor/libgit2/src/crlf.c +66 -67
  147. data/vendor/libgit2/src/date.c +12 -12
  148. data/vendor/libgit2/src/delta-apply.c +14 -1
  149. data/vendor/libgit2/src/delta-apply.h +18 -1
  150. data/vendor/libgit2/src/delta.c +40 -107
  151. data/vendor/libgit2/src/delta.h +19 -17
  152. data/vendor/libgit2/src/diff.c +347 -496
  153. data/vendor/libgit2/src/diff.h +27 -1
  154. data/vendor/libgit2/src/diff_output.c +564 -249
  155. data/vendor/libgit2/src/diff_output.h +15 -8
  156. data/vendor/libgit2/src/diff_tform.c +687 -0
  157. data/vendor/libgit2/src/errors.c +27 -36
  158. data/vendor/libgit2/src/fetch.c +13 -351
  159. data/vendor/libgit2/src/fetch.h +13 -3
  160. data/vendor/libgit2/src/fetchhead.c +295 -0
  161. data/vendor/libgit2/src/fetchhead.h +34 -0
  162. data/vendor/libgit2/src/filebuf.c +42 -15
  163. data/vendor/libgit2/src/filebuf.h +4 -2
  164. data/vendor/libgit2/src/fileops.c +466 -113
  165. data/vendor/libgit2/src/fileops.h +154 -28
  166. data/vendor/libgit2/src/filter.c +3 -75
  167. data/vendor/libgit2/src/filter.h +1 -29
  168. data/vendor/libgit2/src/fnmatch.c +1 -1
  169. data/vendor/libgit2/src/fnmatch.h +1 -1
  170. data/vendor/libgit2/src/global.c +54 -10
  171. data/vendor/libgit2/src/global.h +10 -1
  172. data/vendor/libgit2/src/graph.c +178 -0
  173. data/vendor/libgit2/src/hash.c +25 -52
  174. data/vendor/libgit2/src/hash.h +21 -9
  175. data/vendor/libgit2/src/{sha1/sha1.c → hash/hash_generic.c} +20 -12
  176. data/vendor/libgit2/src/hash/hash_generic.h +24 -0
  177. data/vendor/libgit2/src/hash/hash_openssl.h +45 -0
  178. data/vendor/libgit2/src/hash/hash_win32.c +291 -0
  179. data/vendor/libgit2/src/hash/hash_win32.h +140 -0
  180. data/vendor/libgit2/src/hashsig.c +368 -0
  181. data/vendor/libgit2/src/hashsig.h +72 -0
  182. data/vendor/libgit2/src/ignore.c +22 -15
  183. data/vendor/libgit2/src/ignore.h +6 -1
  184. data/vendor/libgit2/src/index.c +770 -171
  185. data/vendor/libgit2/src/index.h +13 -5
  186. data/vendor/libgit2/src/indexer.c +286 -431
  187. data/vendor/libgit2/src/iterator.c +854 -466
  188. data/vendor/libgit2/src/iterator.h +134 -109
  189. data/vendor/libgit2/src/map.h +1 -1
  190. data/vendor/libgit2/src/merge.c +296 -0
  191. data/vendor/libgit2/src/merge.h +22 -0
  192. data/vendor/libgit2/src/message.c +1 -1
  193. data/vendor/libgit2/src/message.h +1 -1
  194. data/vendor/libgit2/src/mwindow.c +35 -30
  195. data/vendor/libgit2/src/mwindow.h +2 -2
  196. data/vendor/libgit2/src/netops.c +162 -98
  197. data/vendor/libgit2/src/netops.h +50 -15
  198. data/vendor/libgit2/src/notes.c +109 -58
  199. data/vendor/libgit2/src/notes.h +2 -1
  200. data/vendor/libgit2/src/object.c +46 -57
  201. data/vendor/libgit2/src/object.h +1 -8
  202. data/vendor/libgit2/src/odb.c +151 -40
  203. data/vendor/libgit2/src/odb.h +5 -1
  204. data/vendor/libgit2/src/odb_loose.c +4 -5
  205. data/vendor/libgit2/src/odb_pack.c +122 -80
  206. data/vendor/libgit2/src/offmap.h +65 -0
  207. data/vendor/libgit2/src/oid.c +12 -4
  208. data/vendor/libgit2/src/oidmap.h +1 -1
  209. data/vendor/libgit2/src/pack-objects.c +88 -61
  210. data/vendor/libgit2/src/pack-objects.h +8 -8
  211. data/vendor/libgit2/src/pack.c +293 -28
  212. data/vendor/libgit2/src/pack.h +49 -4
  213. data/vendor/libgit2/src/path.c +103 -14
  214. data/vendor/libgit2/src/path.h +23 -7
  215. data/vendor/libgit2/src/pathspec.c +168 -0
  216. data/vendor/libgit2/src/pathspec.h +40 -0
  217. data/vendor/libgit2/src/pool.c +29 -4
  218. data/vendor/libgit2/src/pool.h +8 -1
  219. data/vendor/libgit2/src/posix.c +26 -27
  220. data/vendor/libgit2/src/posix.h +2 -3
  221. data/vendor/libgit2/src/pqueue.c +23 -1
  222. data/vendor/libgit2/src/pqueue.h +23 -1
  223. data/vendor/libgit2/src/push.c +653 -0
  224. data/vendor/libgit2/src/push.h +51 -0
  225. data/vendor/libgit2/src/refdb.c +185 -0
  226. data/vendor/libgit2/src/refdb.h +46 -0
  227. data/vendor/libgit2/src/refdb_fs.c +1024 -0
  228. data/vendor/libgit2/src/refdb_fs.h +15 -0
  229. data/vendor/libgit2/src/reflog.c +77 -45
  230. data/vendor/libgit2/src/reflog.h +1 -3
  231. data/vendor/libgit2/src/refs.c +366 -1326
  232. data/vendor/libgit2/src/refs.h +22 -13
  233. data/vendor/libgit2/src/refspec.c +46 -7
  234. data/vendor/libgit2/src/refspec.h +11 -1
  235. data/vendor/libgit2/src/remote.c +758 -120
  236. data/vendor/libgit2/src/remote.h +10 -5
  237. data/vendor/libgit2/src/repo_template.h +6 -6
  238. data/vendor/libgit2/src/repository.c +315 -96
  239. data/vendor/libgit2/src/repository.h +5 -3
  240. data/vendor/libgit2/src/reset.c +99 -81
  241. data/vendor/libgit2/src/revparse.c +157 -84
  242. data/vendor/libgit2/src/revwalk.c +68 -470
  243. data/vendor/libgit2/src/revwalk.h +44 -0
  244. data/vendor/libgit2/src/sha1_lookup.c +1 -1
  245. data/vendor/libgit2/src/sha1_lookup.h +1 -1
  246. data/vendor/libgit2/src/signature.c +68 -200
  247. data/vendor/libgit2/src/signature.h +1 -1
  248. data/vendor/libgit2/src/stash.c +663 -0
  249. data/vendor/libgit2/src/status.c +101 -79
  250. data/vendor/libgit2/src/strmap.h +1 -1
  251. data/vendor/libgit2/src/submodule.c +67 -51
  252. data/vendor/libgit2/src/submodule.h +1 -1
  253. data/vendor/libgit2/src/tag.c +35 -29
  254. data/vendor/libgit2/src/tag.h +1 -1
  255. data/vendor/libgit2/src/thread-utils.c +1 -1
  256. data/vendor/libgit2/src/thread-utils.h +2 -2
  257. data/vendor/libgit2/src/trace.c +39 -0
  258. data/vendor/libgit2/src/trace.h +56 -0
  259. data/vendor/libgit2/src/transport.c +81 -34
  260. data/vendor/libgit2/src/transports/cred.c +60 -0
  261. data/vendor/libgit2/src/transports/cred_helpers.c +49 -0
  262. data/vendor/libgit2/src/transports/git.c +234 -127
  263. data/vendor/libgit2/src/transports/http.c +761 -433
  264. data/vendor/libgit2/src/transports/local.c +460 -64
  265. data/vendor/libgit2/src/transports/smart.c +345 -0
  266. data/vendor/libgit2/src/transports/smart.h +179 -0
  267. data/vendor/libgit2/src/{pkt.c → transports/smart_pkt.c} +131 -12
  268. data/vendor/libgit2/src/transports/smart_protocol.c +856 -0
  269. data/vendor/libgit2/src/transports/winhttp.c +1136 -0
  270. data/vendor/libgit2/src/tree-cache.c +2 -2
  271. data/vendor/libgit2/src/tree-cache.h +1 -1
  272. data/vendor/libgit2/src/tree.c +239 -166
  273. data/vendor/libgit2/src/tree.h +11 -2
  274. data/vendor/libgit2/src/tsort.c +39 -23
  275. data/vendor/libgit2/src/unix/map.c +1 -1
  276. data/vendor/libgit2/src/unix/posix.h +12 -2
  277. data/vendor/libgit2/src/unix/realpath.c +30 -0
  278. data/vendor/libgit2/src/util.c +250 -13
  279. data/vendor/libgit2/src/util.h +71 -14
  280. data/vendor/libgit2/src/vector.c +123 -60
  281. data/vendor/libgit2/src/vector.h +24 -22
  282. data/vendor/libgit2/src/win32/dir.c +1 -1
  283. data/vendor/libgit2/src/win32/dir.h +1 -1
  284. data/vendor/libgit2/src/win32/error.c +77 -0
  285. data/vendor/libgit2/src/win32/error.h +13 -0
  286. data/vendor/libgit2/src/win32/findfile.c +143 -54
  287. data/vendor/libgit2/src/win32/findfile.h +10 -6
  288. data/vendor/libgit2/src/win32/map.c +1 -1
  289. data/vendor/libgit2/src/win32/mingw-compat.h +1 -1
  290. data/vendor/libgit2/src/win32/msvc-compat.h +10 -1
  291. data/vendor/libgit2/src/win32/posix.h +10 -1
  292. data/vendor/libgit2/src/win32/posix_w32.c +132 -63
  293. data/vendor/libgit2/src/win32/precompiled.c +1 -1
  294. data/vendor/libgit2/src/win32/pthread.c +1 -1
  295. data/vendor/libgit2/src/win32/pthread.h +1 -1
  296. data/vendor/libgit2/src/win32/utf-conv.c +5 -5
  297. data/vendor/libgit2/src/win32/utf-conv.h +3 -3
  298. data/vendor/libgit2/src/win32/version.h +20 -0
  299. metadata +308 -252
  300. data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
  301. data/test/fixtures/testrepo.git/objects/7f/043268ea43ce18e3540acaabf9e090c91965b0 +0 -0
  302. data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
  303. data/test/index_test.rb~ +0 -218
  304. data/vendor/libgit2/src/pkt.h +0 -91
  305. data/vendor/libgit2/src/ppc/sha1.c +0 -70
  306. data/vendor/libgit2/src/ppc/sha1.h +0 -26
  307. data/vendor/libgit2/src/protocol.c +0 -110
  308. data/vendor/libgit2/src/protocol.h +0 -21
  309. data/vendor/libgit2/src/sha1.h +0 -33
  310. data/vendor/libgit2/src/transport.h +0 -148
@@ -46,11 +46,12 @@ extern unsigned long git_delta_sizeof_index(struct git_delta_index *index);
46
46
  * returned and *delta_size is updated with its size. The returned buffer
47
47
  * must be freed by the caller.
48
48
  */
49
- extern void *
50
- git_delta_create(const struct git_delta_index *index,
51
- const void *buf, unsigned long bufsize,
52
- unsigned long *delta_size,
53
- unsigned long max_delta_size);
49
+ extern void *git_delta_create(
50
+ const struct git_delta_index *index,
51
+ const void *buf,
52
+ unsigned long bufsize,
53
+ unsigned long *delta_size,
54
+ unsigned long max_delta_size);
54
55
 
55
56
  /*
56
57
  * diff_delta: create a delta from source buffer to target buffer
@@ -60,15 +61,16 @@ git_delta_create(const struct git_delta_index *index,
60
61
  * pointer to the buffer with the delta data is returned and *delta_size is
61
62
  * updated with its size. The returned buffer must be freed by the caller.
62
63
  */
63
- GIT_INLINE(void *)
64
- git_delta(const void *src_buf, unsigned long src_bufsize,
65
- const void *trg_buf, unsigned long trg_bufsize,
66
- unsigned long *delta_size, unsigned long max_delta_size)
64
+ GIT_INLINE(void *) git_delta(
65
+ const void *src_buf, unsigned long src_bufsize,
66
+ const void *trg_buf, unsigned long trg_bufsize,
67
+ unsigned long *delta_size,
68
+ unsigned long max_delta_size)
67
69
  {
68
70
  struct git_delta_index *index = git_delta_create_index(src_buf, src_bufsize);
69
71
  if (index) {
70
- void *delta = git_delta_create(index, trg_buf, trg_bufsize,
71
- delta_size, max_delta_size);
72
+ void *delta = git_delta_create(
73
+ index, trg_buf, trg_bufsize, delta_size, max_delta_size);
72
74
  git_delta_free_index(index);
73
75
  return delta;
74
76
  }
@@ -82,9 +84,10 @@ git_delta(const void *src_buf, unsigned long src_bufsize,
82
84
  * *trg_bufsize is updated with its size. On failure a NULL pointer is
83
85
  * returned. The returned buffer must be freed by the caller.
84
86
  */
85
- extern void *git_delta_patch(const void *src_buf, unsigned long src_size,
86
- const void *delta_buf, unsigned long delta_size,
87
- unsigned long *dst_size);
87
+ extern void *git_delta_patch(
88
+ const void *src_buf, unsigned long src_size,
89
+ const void *delta_buf, unsigned long delta_size,
90
+ unsigned long *dst_size);
88
91
 
89
92
  /* the smallest possible delta size is 4 bytes */
90
93
  #define GIT_DELTA_SIZE_MIN 4
@@ -93,9 +96,8 @@ extern void *git_delta_patch(const void *src_buf, unsigned long src_size,
93
96
  * This must be called twice on the delta data buffer, first to get the
94
97
  * expected source buffer size, and again to get the target buffer size.
95
98
  */
96
- GIT_INLINE(unsigned long)
97
- git_delta_get_hdr_size(const unsigned char **datap,
98
- const unsigned char *top)
99
+ GIT_INLINE(unsigned long) git_delta_get_hdr_size(
100
+ const unsigned char **datap, const unsigned char *top)
99
101
  {
100
102
  const unsigned char *data = *datap;
101
103
  unsigned long cmd, size = 0;
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2012 the libgit2 contributors
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
3
  *
4
4
  * This file is part of libgit2, distributed under the GNU GPL v2 with
5
5
  * a Linking Exception. For full terms see the included COPYING file.
@@ -10,76 +10,10 @@
10
10
  #include "config.h"
11
11
  #include "attr_file.h"
12
12
  #include "filter.h"
13
+ #include "pathspec.h"
13
14
 
14
- static char *diff_prefix_from_pathspec(const git_strarray *pathspec)
15
- {
16
- git_buf prefix = GIT_BUF_INIT;
17
- const char *scan;
18
-
19
- if (git_buf_common_prefix(&prefix, pathspec) < 0)
20
- return NULL;
21
-
22
- /* diff prefix will only be leading non-wildcards */
23
- for (scan = prefix.ptr; *scan; ++scan) {
24
- if (git__iswildcard(*scan) &&
25
- (scan == prefix.ptr || (*(scan - 1) != '\\')))
26
- break;
27
- }
28
- git_buf_truncate(&prefix, scan - prefix.ptr);
29
-
30
- if (prefix.size <= 0) {
31
- git_buf_free(&prefix);
32
- return NULL;
33
- }
34
-
35
- git_buf_unescape(&prefix);
36
-
37
- return git_buf_detach(&prefix);
38
- }
39
-
40
- static bool diff_pathspec_is_interesting(const git_strarray *pathspec)
41
- {
42
- const char *str;
43
-
44
- if (pathspec == NULL || pathspec->count == 0)
45
- return false;
46
- if (pathspec->count > 1)
47
- return true;
48
-
49
- str = pathspec->strings[0];
50
- if (!str || !str[0] || (!str[1] && (str[0] == '*' || str[0] == '.')))
51
- return false;
52
- return true;
53
- }
54
-
55
- static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path)
56
- {
57
- unsigned int i;
58
- git_attr_fnmatch *match;
59
-
60
- if (!diff->pathspec.length)
61
- return true;
62
-
63
- git_vector_foreach(&diff->pathspec, i, match) {
64
- int result = strcmp(match->pattern, path) ? FNM_NOMATCH : 0;
65
-
66
- if (((diff->opts.flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH) == 0) &&
67
- result == FNM_NOMATCH)
68
- result = p_fnmatch(match->pattern, path, 0);
69
-
70
- /* if we didn't match, look for exact dirname prefix match */
71
- if (result == FNM_NOMATCH &&
72
- (match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 &&
73
- strncmp(path, match->pattern, match->length) == 0 &&
74
- path[match->length] == '/')
75
- result = 0;
76
-
77
- if (result == 0)
78
- return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? false : true;
79
- }
80
-
81
- return false;
82
- }
15
+ #define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0)
16
+ #define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0)
83
17
 
84
18
  static git_diff_delta *diff_delta__alloc(
85
19
  git_diff_list *diff,
@@ -98,7 +32,7 @@ static git_diff_delta *diff_delta__alloc(
98
32
 
99
33
  delta->new_file.path = delta->old_file.path;
100
34
 
101
- if (diff->opts.flags & GIT_DIFF_REVERSE) {
35
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
102
36
  switch (status) {
103
37
  case GIT_DELTA_ADDED: status = GIT_DELTA_DELETED; break;
104
38
  case GIT_DELTA_DELETED: status = GIT_DELTA_ADDED; break;
@@ -110,83 +44,16 @@ static git_diff_delta *diff_delta__alloc(
110
44
  return delta;
111
45
  }
112
46
 
113
- static git_diff_delta *diff_delta__dup(
114
- const git_diff_delta *d, git_pool *pool)
115
- {
116
- git_diff_delta *delta = git__malloc(sizeof(git_diff_delta));
117
- if (!delta)
118
- return NULL;
119
-
120
- memcpy(delta, d, sizeof(git_diff_delta));
121
-
122
- delta->old_file.path = git_pool_strdup(pool, d->old_file.path);
123
- if (delta->old_file.path == NULL)
124
- goto fail;
125
-
126
- if (d->new_file.path != d->old_file.path) {
127
- delta->new_file.path = git_pool_strdup(pool, d->new_file.path);
128
- if (delta->new_file.path == NULL)
129
- goto fail;
130
- } else {
131
- delta->new_file.path = delta->old_file.path;
132
- }
133
-
134
- return delta;
135
-
136
- fail:
137
- git__free(delta);
138
- return NULL;
139
- }
140
-
141
- static git_diff_delta *diff_delta__merge_like_cgit(
142
- const git_diff_delta *a, const git_diff_delta *b, git_pool *pool)
47
+ static int diff_notify(
48
+ const git_diff_list *diff,
49
+ const git_diff_delta *delta,
50
+ const char *matched_pathspec)
143
51
  {
144
- git_diff_delta *dup;
145
-
146
- /* Emulate C git for merging two diffs (a la 'git diff <sha>').
147
- *
148
- * When C git does a diff between the work dir and a tree, it actually
149
- * diffs with the index but uses the workdir contents. This emulates
150
- * those choices so we can emulate the type of diff.
151
- *
152
- * We have three file descriptions here, let's call them:
153
- * f1 = a->old_file
154
- * f2 = a->new_file AND b->old_file
155
- * f3 = b->new_file
156
- */
157
-
158
- /* if f2 == f3 or f2 is deleted, then just dup the 'a' diff */
159
- if (b->status == GIT_DELTA_UNMODIFIED || a->status == GIT_DELTA_DELETED)
160
- return diff_delta__dup(a, pool);
161
-
162
- /* otherwise, base this diff on the 'b' diff */
163
- if ((dup = diff_delta__dup(b, pool)) == NULL)
164
- return NULL;
165
-
166
- /* If 'a' status is uninteresting, then we're done */
167
- if (a->status == GIT_DELTA_UNMODIFIED)
168
- return dup;
169
-
170
- assert(a->status != GIT_DELTA_UNMODIFIED);
171
- assert(b->status != GIT_DELTA_UNMODIFIED);
172
-
173
- /* A cgit exception is that the diff of a file that is only in the
174
- * index (i.e. not in HEAD nor workdir) is given as empty.
175
- */
176
- if (dup->status == GIT_DELTA_DELETED) {
177
- if (a->status == GIT_DELTA_ADDED)
178
- dup->status = GIT_DELTA_UNMODIFIED;
179
- /* else don't overwrite DELETE status */
180
- } else {
181
- dup->status = a->status;
182
- }
183
-
184
- git_oid_cpy(&dup->old_file.oid, &a->old_file.oid);
185
- dup->old_file.mode = a->old_file.mode;
186
- dup->old_file.size = a->old_file.size;
187
- dup->old_file.flags = a->old_file.flags;
52
+ if (!diff->opts.notify_cb)
53
+ return 0;
188
54
 
189
- return dup;
55
+ return diff->opts.notify_cb(
56
+ diff, delta, matched_pathspec, diff->opts.notify_payload);
190
57
  }
191
58
 
192
59
  static int diff_delta__from_one(
@@ -195,16 +62,26 @@ static int diff_delta__from_one(
195
62
  const git_index_entry *entry)
196
63
  {
197
64
  git_diff_delta *delta;
65
+ const char *matched_pathspec;
66
+ int notify_res;
198
67
 
199
68
  if (status == GIT_DELTA_IGNORED &&
200
- (diff->opts.flags & GIT_DIFF_INCLUDE_IGNORED) == 0)
69
+ DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_IGNORED))
201
70
  return 0;
202
71
 
203
72
  if (status == GIT_DELTA_UNTRACKED &&
204
- (diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
73
+ DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED))
74
+ return 0;
75
+
76
+ if (entry->mode == GIT_FILEMODE_COMMIT &&
77
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
205
78
  return 0;
206
79
 
207
- if (!diff_path_matches_pathspec(diff, entry->path))
80
+ if (!git_pathspec_match_path(
81
+ &diff->pathspec, entry->path,
82
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
83
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE),
84
+ &matched_pathspec))
208
85
  return 0;
209
86
 
210
87
  delta = diff_delta__alloc(diff, status, entry->path);
@@ -223,18 +100,22 @@ static int diff_delta__from_one(
223
100
  git_oid_cpy(&delta->new_file.oid, &entry->oid);
224
101
  }
225
102
 
226
- delta->old_file.flags |= GIT_DIFF_FILE_VALID_OID;
103
+ delta->old_file.flags |= GIT_DIFF_FLAG_VALID_OID;
227
104
 
228
105
  if (delta->status == GIT_DELTA_DELETED ||
229
106
  !git_oid_iszero(&delta->new_file.oid))
230
- delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID;
107
+ delta->new_file.flags |= GIT_DIFF_FLAG_VALID_OID;
231
108
 
232
- if (git_vector_insert(&diff->deltas, delta) < 0) {
109
+ notify_res = diff_notify(diff, delta, matched_pathspec);
110
+
111
+ if (notify_res)
112
+ git__free(delta);
113
+ else if (git_vector_insert(&diff->deltas, delta) < 0) {
233
114
  git__free(delta);
234
115
  return -1;
235
116
  }
236
117
 
237
- return 0;
118
+ return notify_res < 0 ? GIT_EUSER : 0;
238
119
  }
239
120
 
240
121
  static int diff_delta__from_two(
@@ -244,15 +125,22 @@ static int diff_delta__from_two(
244
125
  uint32_t old_mode,
245
126
  const git_index_entry *new_entry,
246
127
  uint32_t new_mode,
247
- git_oid *new_oid)
128
+ git_oid *new_oid,
129
+ const char *matched_pathspec)
248
130
  {
249
131
  git_diff_delta *delta;
132
+ int notify_res;
250
133
 
251
134
  if (status == GIT_DELTA_UNMODIFIED &&
252
- (diff->opts.flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
135
+ DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED))
136
+ return 0;
137
+
138
+ if (old_entry->mode == GIT_FILEMODE_COMMIT &&
139
+ new_entry->mode == GIT_FILEMODE_COMMIT &&
140
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
253
141
  return 0;
254
142
 
255
- if ((diff->opts.flags & GIT_DIFF_REVERSE) != 0) {
143
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
256
144
  uint32_t temp_mode = old_mode;
257
145
  const git_index_entry *temp_entry = old_entry;
258
146
  old_entry = new_entry;
@@ -267,28 +155,32 @@ static int diff_delta__from_two(
267
155
  git_oid_cpy(&delta->old_file.oid, &old_entry->oid);
268
156
  delta->old_file.size = old_entry->file_size;
269
157
  delta->old_file.mode = old_mode;
270
- delta->old_file.flags |= GIT_DIFF_FILE_VALID_OID;
158
+ delta->old_file.flags |= GIT_DIFF_FLAG_VALID_OID;
271
159
 
272
160
  git_oid_cpy(&delta->new_file.oid, &new_entry->oid);
273
161
  delta->new_file.size = new_entry->file_size;
274
162
  delta->new_file.mode = new_mode;
275
163
 
276
164
  if (new_oid) {
277
- if ((diff->opts.flags & GIT_DIFF_REVERSE) != 0)
165
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE))
278
166
  git_oid_cpy(&delta->old_file.oid, new_oid);
279
167
  else
280
168
  git_oid_cpy(&delta->new_file.oid, new_oid);
281
169
  }
282
170
 
283
171
  if (new_oid || !git_oid_iszero(&new_entry->oid))
284
- delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID;
172
+ delta->new_file.flags |= GIT_DIFF_FLAG_VALID_OID;
285
173
 
286
- if (git_vector_insert(&diff->deltas, delta) < 0) {
174
+ notify_res = diff_notify(diff, delta, matched_pathspec);
175
+
176
+ if (notify_res)
177
+ git__free(delta);
178
+ else if (git_vector_insert(&diff->deltas, delta) < 0) {
287
179
  git__free(delta);
288
180
  return -1;
289
181
  }
290
182
 
291
- return 0;
183
+ return notify_res < 0 ? GIT_EUSER : 0;
292
184
  }
293
185
 
294
186
  static git_diff_delta *diff_delta__last_for_item(
@@ -309,6 +201,11 @@ static git_diff_delta *diff_delta__last_for_item(
309
201
  if (git_oid_cmp(&delta->new_file.oid, &item->oid) == 0)
310
202
  return delta;
311
203
  break;
204
+ case GIT_DELTA_UNTRACKED:
205
+ if (diff->strcomp(delta->new_file.path, item->path) == 0 &&
206
+ git_oid_cmp(&delta->new_file.oid, &item->oid) == 0)
207
+ return delta;
208
+ break;
312
209
  case GIT_DELTA_MODIFIED:
313
210
  if (git_oid_cmp(&delta->old_file.oid, &item->oid) == 0 ||
314
211
  git_oid_cmp(&delta->new_file.oid, &item->oid) == 0)
@@ -332,13 +229,34 @@ static char *diff_strdup_prefix(git_pool *pool, const char *prefix)
332
229
  return git_pool_strndup(pool, prefix, len + 1);
333
230
  }
334
231
 
335
- static int diff_delta__cmp(const void *a, const void *b)
232
+ int git_diff_delta__cmp(const void *a, const void *b)
336
233
  {
337
234
  const git_diff_delta *da = a, *db = b;
338
235
  int val = strcmp(da->old_file.path, db->old_file.path);
339
236
  return val ? val : ((int)da->status - (int)db->status);
340
237
  }
341
238
 
239
+ bool git_diff_delta__should_skip(
240
+ const git_diff_options *opts, const git_diff_delta *delta)
241
+ {
242
+ uint32_t flags = opts ? opts->flags : 0;
243
+
244
+ if (delta->status == GIT_DELTA_UNMODIFIED &&
245
+ (flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
246
+ return true;
247
+
248
+ if (delta->status == GIT_DELTA_IGNORED &&
249
+ (flags & GIT_DIFF_INCLUDE_IGNORED) == 0)
250
+ return true;
251
+
252
+ if (delta->status == GIT_DELTA_UNTRACKED &&
253
+ (flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
254
+ return true;
255
+
256
+ return false;
257
+ }
258
+
259
+
342
260
  static int config_bool(git_config *cfg, const char *name, int defvalue)
343
261
  {
344
262
  int val = defvalue;
@@ -353,7 +271,6 @@ static git_diff_list *git_diff_list_alloc(
353
271
  git_repository *repo, const git_diff_options *opts)
354
272
  {
355
273
  git_config *cfg;
356
- size_t i;
357
274
  git_diff_list *diff = git__calloc(1, sizeof(git_diff_list));
358
275
  if (diff == NULL)
359
276
  return NULL;
@@ -361,7 +278,7 @@ static git_diff_list *git_diff_list_alloc(
361
278
  GIT_REFCOUNT_INC(diff);
362
279
  diff->repo = repo;
363
280
 
364
- if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0 ||
281
+ if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 ||
365
282
  git_pool_init(&diff->pool, 1, 0) < 0)
366
283
  goto fail;
367
284
 
@@ -378,11 +295,31 @@ static git_diff_list *git_diff_list_alloc(
378
295
  diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME;
379
296
  /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
380
297
 
381
- if (opts == NULL)
298
+ /* TODO: there are certain config settings where even if we were
299
+ * not given an options structure, we need the diff list to have one
300
+ * so that we can store the altered default values.
301
+ *
302
+ * - diff.ignoreSubmodules
303
+ * - diff.mnemonicprefix
304
+ * - diff.noprefix
305
+ */
306
+
307
+ if (opts == NULL) {
308
+ /* Make sure we default to 3 lines */
309
+ diff->opts.context_lines = 3;
382
310
  return diff;
311
+ }
383
312
 
384
313
  memcpy(&diff->opts, opts, sizeof(git_diff_options));
385
- memset(&diff->opts.pathspec, 0, sizeof(diff->opts.pathspec));
314
+
315
+ if(opts->flags & GIT_DIFF_IGNORE_FILEMODE)
316
+ diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS;
317
+
318
+ /* pathspec init will do nothing for empty pathspec */
319
+ if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0)
320
+ goto fail;
321
+
322
+ /* TODO: handle config diff.mnemonicprefix, diff.noprefix */
386
323
 
387
324
  diff->opts.old_prefix = diff_strdup_prefix(&diff->pool,
388
325
  opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT);
@@ -392,45 +329,16 @@ static git_diff_list *git_diff_list_alloc(
392
329
  if (!diff->opts.old_prefix || !diff->opts.new_prefix)
393
330
  goto fail;
394
331
 
395
- if (diff->opts.flags & GIT_DIFF_REVERSE) {
396
- char *swap = diff->opts.old_prefix;
332
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
333
+ const char *swap = diff->opts.old_prefix;
397
334
  diff->opts.old_prefix = diff->opts.new_prefix;
398
335
  diff->opts.new_prefix = swap;
399
336
  }
400
337
 
401
338
  /* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */
402
- if (diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE_TREES)
339
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES))
403
340
  diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
404
341
 
405
- /* only copy pathspec if it is "interesting" so we can test
406
- * diff->pathspec.length > 0 to know if it is worth calling
407
- * fnmatch as we iterate.
408
- */
409
- if (!diff_pathspec_is_interesting(&opts->pathspec))
410
- return diff;
411
-
412
- if (git_vector_init(
413
- &diff->pathspec, (unsigned int)opts->pathspec.count, NULL) < 0)
414
- goto fail;
415
-
416
- for (i = 0; i < opts->pathspec.count; ++i) {
417
- int ret;
418
- const char *pattern = opts->pathspec.strings[i];
419
- git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch));
420
- if (!match)
421
- goto fail;
422
- match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE;
423
- ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern);
424
- if (ret == GIT_ENOTFOUND) {
425
- git__free(match);
426
- continue;
427
- } else if (ret < 0)
428
- goto fail;
429
-
430
- if (git_vector_insert(&diff->pathspec, match) < 0)
431
- goto fail;
432
- }
433
-
434
342
  return diff;
435
343
 
436
344
  fail:
@@ -441,7 +349,6 @@ fail:
441
349
  static void diff_list_free(git_diff_list *diff)
442
350
  {
443
351
  git_diff_delta *delta;
444
- git_attr_fnmatch *match;
445
352
  unsigned int i;
446
353
 
447
354
  git_vector_foreach(&diff->deltas, i, delta) {
@@ -450,12 +357,7 @@ static void diff_list_free(git_diff_list *diff)
450
357
  }
451
358
  git_vector_free(&diff->deltas);
452
359
 
453
- git_vector_foreach(&diff->pathspec, i, match) {
454
- git__free(match);
455
- diff->pathspec.contents[i] = NULL;
456
- }
457
- git_vector_free(&diff->pathspec);
458
-
360
+ git_pathspec_free(&diff->pathspec);
459
361
  git_pool_clear(&diff->pool);
460
362
  git__free(diff);
461
363
  }
@@ -473,25 +375,40 @@ void git_diff_list_addref(git_diff_list *diff)
473
375
  GIT_REFCOUNT_INC(diff);
474
376
  }
475
377
 
476
- static int oid_for_workdir_item(
378
+ int git_diff__oid_for_file(
477
379
  git_repository *repo,
478
- const git_index_entry *item,
380
+ const char *path,
381
+ uint16_t mode,
382
+ git_off_t size,
479
383
  git_oid *oid)
480
384
  {
481
385
  int result = 0;
482
386
  git_buf full_path = GIT_BUF_INIT;
483
387
 
484
388
  if (git_buf_joinpath(
485
- &full_path, git_repository_workdir(repo), item->path) < 0)
389
+ &full_path, git_repository_workdir(repo), path) < 0)
486
390
  return -1;
487
391
 
392
+ if (!mode) {
393
+ struct stat st;
394
+
395
+ if (p_stat(path, &st) < 0) {
396
+ giterr_set(GITERR_OS, "Could not stat '%s'", path);
397
+ result = -1;
398
+ goto cleanup;
399
+ }
400
+
401
+ mode = st.st_mode;
402
+ size = st.st_size;
403
+ }
404
+
488
405
  /* calculate OID for file if possible */
489
- if (S_ISGITLINK(item->mode)) {
406
+ if (S_ISGITLINK(mode)) {
490
407
  git_submodule *sm;
491
408
  const git_oid *sm_oid;
492
409
 
493
- if (!git_submodule_lookup(&sm, repo, item->path) &&
494
- (sm_oid = git_submodule_wd_oid(sm)) != NULL)
410
+ if (!git_submodule_lookup(&sm, repo, path) &&
411
+ (sm_oid = git_submodule_wd_id(sm)) != NULL)
495
412
  git_oid_cpy(oid, sm_oid);
496
413
  else {
497
414
  /* if submodule lookup failed probably just in an intermediate
@@ -500,23 +417,22 @@ static int oid_for_workdir_item(
500
417
  giterr_clear();
501
418
  memset(oid, 0, sizeof(*oid));
502
419
  }
503
- } else if (S_ISLNK(item->mode))
420
+ } else if (S_ISLNK(mode)) {
504
421
  result = git_odb__hashlink(oid, full_path.ptr);
505
- else if (!git__is_sizet(item->file_size)) {
506
- giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
422
+ } else if (!git__is_sizet(size)) {
423
+ giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path);
507
424
  result = -1;
508
425
  } else {
509
426
  git_vector filters = GIT_VECTOR_INIT;
510
427
 
511
- result = git_filters_load(
512
- &filters, repo, item->path, GIT_FILTER_TO_ODB);
428
+ result = git_filters_load(&filters, repo, path, GIT_FILTER_TO_ODB);
513
429
  if (result >= 0) {
514
430
  int fd = git_futils_open_ro(full_path.ptr);
515
431
  if (fd < 0)
516
432
  result = fd;
517
433
  else {
518
434
  result = git_odb__hashfd_filtered(
519
- oid, fd, (size_t)item->file_size, GIT_OBJ_BLOB, &filters);
435
+ oid, fd, (size_t)size, GIT_OBJ_BLOB, &filters);
520
436
  p_close(fd);
521
437
  }
522
438
  }
@@ -524,8 +440,8 @@ static int oid_for_workdir_item(
524
440
  git_filters_free(&filters);
525
441
  }
526
442
 
443
+ cleanup:
527
444
  git_buf_free(&full_path);
528
-
529
445
  return result;
530
446
  }
531
447
 
@@ -542,11 +458,16 @@ static int maybe_modified(
542
458
  git_delta_t status = GIT_DELTA_MODIFIED;
543
459
  unsigned int omode = oitem->mode;
544
460
  unsigned int nmode = nitem->mode;
545
- bool new_is_workdir = (new_iter->type == GIT_ITERATOR_WORKDIR);
461
+ bool new_is_workdir = (new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
462
+ const char *matched_pathspec;
546
463
 
547
464
  GIT_UNUSED(old_iter);
548
465
 
549
- if (!diff_path_matches_pathspec(diff, oitem->path))
466
+ if (!git_pathspec_match_path(
467
+ &diff->pathspec, oitem->path,
468
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
469
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE),
470
+ &matched_pathspec))
550
471
  return 0;
551
472
 
552
473
  /* on platforms with no symlinks, preserve mode of existing symlinks */
@@ -571,7 +492,7 @@ static int maybe_modified(
571
492
 
572
493
  /* if basic type of file changed, then split into delete and add */
573
494
  else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
574
- if ((diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE) != 0)
495
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE))
575
496
  status = GIT_DELTA_TYPECHANGE;
576
497
  else {
577
498
  if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
@@ -582,8 +503,7 @@ static int maybe_modified(
582
503
  }
583
504
 
584
505
  /* if oids and modes match, then file is unmodified */
585
- else if (git_oid_cmp(&oitem->oid, &nitem->oid) == 0 &&
586
- omode == nmode)
506
+ else if (git_oid_equal(&oitem->oid, &nitem->oid) && omode == nmode)
587
507
  status = GIT_DELTA_UNMODIFIED;
588
508
 
589
509
  /* if we have an unknown OID and a workdir iterator, then check some
@@ -606,24 +526,32 @@ static int maybe_modified(
606
526
  status = GIT_DELTA_UNMODIFIED;
607
527
 
608
528
  else if (S_ISGITLINK(nmode)) {
529
+ int err;
609
530
  git_submodule *sub;
610
531
 
611
- if ((diff->opts.flags & GIT_DIFF_IGNORE_SUBMODULES) != 0)
532
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
612
533
  status = GIT_DELTA_UNMODIFIED;
613
- else if (git_submodule_lookup(&sub, diff->repo, nitem->path) < 0)
614
- return -1;
615
- else if (git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
534
+ else if ((err = git_submodule_lookup(&sub, diff->repo, nitem->path)) < 0) {
535
+ if (err == GIT_EEXISTS)
536
+ status = GIT_DELTA_UNMODIFIED;
537
+ else
538
+ return err;
539
+ } else if (git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
616
540
  status = GIT_DELTA_UNMODIFIED;
617
541
  else {
618
542
  unsigned int sm_status = 0;
619
543
  if (git_submodule_status(&sm_status, sub) < 0)
620
544
  return -1;
621
- status = GIT_SUBMODULE_STATUS_IS_UNMODIFIED(sm_status)
545
+
546
+ /* check IS_WD_UNMODIFIED because this case is only used
547
+ * when the new side of the diff is the working directory
548
+ */
549
+ status = GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status)
622
550
  ? GIT_DELTA_UNMODIFIED : GIT_DELTA_MODIFIED;
623
551
 
624
552
  /* grab OID while we are here */
625
553
  if (git_oid_iszero(&nitem->oid)) {
626
- const git_oid *sm_oid = git_submodule_wd_oid(sub);
554
+ const git_oid *sm_oid = git_submodule_wd_id(sub);
627
555
  if (sm_oid != NULL) {
628
556
  git_oid_cpy(&noid, sm_oid);
629
557
  use_noid = &noid;
@@ -633,114 +561,124 @@ static int maybe_modified(
633
561
  }
634
562
  }
635
563
 
564
+ /* if mode is GITLINK and submodules are ignored, then skip */
565
+ else if (S_ISGITLINK(nmode) &&
566
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
567
+ status = GIT_DELTA_UNMODIFIED;
568
+
636
569
  /* if we got here and decided that the files are modified, but we
637
570
  * haven't calculated the OID of the new item, then calculate it now
638
571
  */
639
572
  if (status != GIT_DELTA_UNMODIFIED && git_oid_iszero(&nitem->oid)) {
640
- if (oid_for_workdir_item(diff->repo, nitem, &noid) < 0)
641
- return -1;
642
- else if (omode == nmode && git_oid_equal(&oitem->oid, &noid))
643
- status = GIT_DELTA_UNMODIFIED;
573
+ if (!use_noid) {
574
+ if (git_diff__oid_for_file(diff->repo,
575
+ nitem->path, nitem->mode, nitem->file_size, &noid) < 0)
576
+ return -1;
577
+ use_noid = &noid;
578
+ }
644
579
 
645
- /* store calculated oid so we don't have to recalc later */
646
- use_noid = &noid;
580
+ /* if oid matches, then mark unmodified (except submodules, where
581
+ * the filesystem content may be modified even if the oid still
582
+ * matches between the index and the workdir HEAD)
583
+ */
584
+ if (omode == nmode && !S_ISGITLINK(omode) &&
585
+ git_oid_equal(&oitem->oid, use_noid))
586
+ status = GIT_DELTA_UNMODIFIED;
647
587
  }
648
588
 
649
589
  return diff_delta__from_two(
650
- diff, status, oitem, omode, nitem, nmode, use_noid);
651
- }
652
-
653
- static int git_index_entry_cmp_case(const void *a, const void *b)
654
- {
655
- const git_index_entry *entry_a = a;
656
- const git_index_entry *entry_b = b;
657
-
658
- return strcmp(entry_a->path, entry_b->path);
659
- }
660
-
661
- static int git_index_entry_cmp_icase(const void *a, const void *b)
662
- {
663
- const git_index_entry *entry_a = a;
664
- const git_index_entry *entry_b = b;
665
-
666
- return strcasecmp(entry_a->path, entry_b->path);
590
+ diff, status, oitem, omode, nitem, nmode, use_noid, matched_pathspec);
667
591
  }
668
592
 
669
593
  static bool entry_is_prefixed(
594
+ git_diff_list *diff,
670
595
  const git_index_entry *item,
671
- git_iterator *prefix_iterator,
672
596
  const git_index_entry *prefix_item)
673
597
  {
674
598
  size_t pathlen;
675
599
 
676
- if (!prefix_item ||
677
- ITERATOR_PREFIXCMP(*prefix_iterator, prefix_item->path, item->path))
600
+ if (!item || diff->pfxcomp(item->path, prefix_item->path) != 0)
678
601
  return false;
679
602
 
680
- pathlen = strlen(item->path);
603
+ pathlen = strlen(prefix_item->path);
681
604
 
682
- return (item->path[pathlen - 1] == '/' ||
683
- prefix_item->path[pathlen] == '\0' ||
684
- prefix_item->path[pathlen] == '/');
605
+ return (prefix_item->path[pathlen - 1] == '/' ||
606
+ item->path[pathlen] == '\0' ||
607
+ item->path[pathlen] == '/');
685
608
  }
686
609
 
687
- static int diff_from_iterators(
688
- git_repository *repo,
689
- const git_diff_options *opts, /**< can be NULL for defaults */
610
+ static int diff_list_init_from_iterators(
611
+ git_diff_list *diff,
690
612
  git_iterator *old_iter,
691
- git_iterator *new_iter,
692
- git_diff_list **diff_ptr)
613
+ git_iterator *new_iter)
693
614
  {
694
- const git_index_entry *oitem, *nitem;
695
- git_buf ignore_prefix = GIT_BUF_INIT;
696
- git_diff_list *diff = git_diff_list_alloc(repo, opts);
697
- git_vector_cmp entry_compare;
698
-
699
- if (!diff)
700
- goto fail;
701
-
702
615
  diff->old_src = old_iter->type;
703
616
  diff->new_src = new_iter->type;
704
617
 
705
618
  /* Use case-insensitive compare if either iterator has
706
619
  * the ignore_case bit set */
707
- if (!old_iter->ignore_case && !new_iter->ignore_case) {
708
- entry_compare = git_index_entry_cmp_case;
620
+ if (!git_iterator_ignore_case(old_iter) &&
621
+ !git_iterator_ignore_case(new_iter))
622
+ {
709
623
  diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
624
+
625
+ diff->strcomp = git__strcmp;
626
+ diff->strncomp = git__strncmp;
627
+ diff->pfxcomp = git__prefixcmp;
628
+ diff->entrycomp = git_index_entry__cmp;
710
629
  } else {
711
- entry_compare = git_index_entry_cmp_icase;
712
630
  diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE;
713
631
 
714
- /* If one of the iterators doesn't have ignore_case set,
715
- * then that's unfortunate because we'll have to spool
716
- * its data, sort it icase, and then use that for our
717
- * merge join to the other iterator that is icase sorted */
718
- if (!old_iter->ignore_case) {
719
- if (git_iterator_spoolandsort(&old_iter, old_iter, git_index_entry_cmp_icase, true) < 0)
720
- goto fail;
721
- } else if (!new_iter->ignore_case) {
722
- if (git_iterator_spoolandsort(&new_iter, new_iter, git_index_entry_cmp_icase, true) < 0)
723
- goto fail;
724
- }
632
+ diff->strcomp = git__strcasecmp;
633
+ diff->strncomp = git__strncasecmp;
634
+ diff->pfxcomp = git__prefixcmp_icase;
635
+ diff->entrycomp = git_index_entry__cmp_icase;
636
+ }
637
+
638
+ return 0;
639
+ }
640
+
641
+ int git_diff__from_iterators(
642
+ git_diff_list **diff_ptr,
643
+ git_repository *repo,
644
+ git_iterator *old_iter,
645
+ git_iterator *new_iter,
646
+ const git_diff_options *opts)
647
+ {
648
+ int error = 0;
649
+ const git_index_entry *oitem, *nitem;
650
+ git_buf ignore_prefix = GIT_BUF_INIT;
651
+ git_diff_list *diff = git_diff_list_alloc(repo, opts);
652
+
653
+ *diff_ptr = NULL;
654
+
655
+ if (!diff || diff_list_init_from_iterators(diff, old_iter, new_iter) < 0)
656
+ goto fail;
657
+
658
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) {
659
+ if (git_iterator_set_ignore_case(old_iter, true) < 0 ||
660
+ git_iterator_set_ignore_case(new_iter, true) < 0)
661
+ goto fail;
725
662
  }
726
663
 
727
- if (git_iterator_current(old_iter, &oitem) < 0 ||
728
- git_iterator_current(new_iter, &nitem) < 0)
664
+ if (git_iterator_current(&oitem, old_iter) < 0 ||
665
+ git_iterator_current(&nitem, new_iter) < 0)
729
666
  goto fail;
730
667
 
731
668
  /* run iterators building diffs */
732
669
  while (oitem || nitem) {
670
+ int cmp = oitem ? (nitem ? diff->entrycomp(oitem, nitem) : -1) : 1;
733
671
 
734
672
  /* create DELETED records for old items not matched in new */
735
- if (oitem && (!nitem || entry_compare(oitem, nitem) < 0)) {
673
+ if (cmp < 0) {
736
674
  if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0)
737
675
  goto fail;
738
676
 
739
677
  /* if we are generating TYPECHANGE records then check for that
740
678
  * instead of just generating a DELETE record
741
679
  */
742
- if ((diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE_TREES) != 0 &&
743
- entry_is_prefixed(oitem, new_iter, nitem))
680
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) &&
681
+ entry_is_prefixed(diff, nitem, oitem))
744
682
  {
745
683
  /* this entry has become a tree! convert to TYPECHANGE */
746
684
  git_diff_delta *last = diff_delta__last_for_item(diff, oitem);
@@ -748,22 +686,33 @@ static int diff_from_iterators(
748
686
  last->status = GIT_DELTA_TYPECHANGE;
749
687
  last->new_file.mode = GIT_FILEMODE_TREE;
750
688
  }
689
+
690
+ /* If new_iter is a workdir iterator, then this situation
691
+ * will certainly be followed by a series of untracked items.
692
+ * Unless RECURSE_UNTRACKED_DIRS is set, skip over them...
693
+ */
694
+ if (S_ISDIR(nitem->mode) &&
695
+ DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS))
696
+ {
697
+ if (git_iterator_advance(&nitem, new_iter) < 0)
698
+ goto fail;
699
+ }
751
700
  }
752
701
 
753
- if (git_iterator_advance(old_iter, &oitem) < 0)
702
+ if (git_iterator_advance(&oitem, old_iter) < 0)
754
703
  goto fail;
755
704
  }
756
705
 
757
706
  /* create ADDED, TRACKED, or IGNORED records for new items not
758
707
  * matched in old (and/or descend into directories as needed)
759
708
  */
760
- else if (nitem && (!oitem || entry_compare(oitem, nitem) > 0)) {
709
+ else if (cmp > 0) {
761
710
  git_delta_t delta_type = GIT_DELTA_UNTRACKED;
711
+ bool contains_oitem = entry_is_prefixed(diff, oitem, nitem);
762
712
 
763
713
  /* check if contained in ignored parent directory */
764
714
  if (git_buf_len(&ignore_prefix) &&
765
- ITERATOR_PREFIXCMP(*old_iter, nitem->path,
766
- git_buf_cstr(&ignore_prefix)) == 0)
715
+ diff->pfxcomp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0)
767
716
  delta_type = GIT_DELTA_IGNORED;
768
717
 
769
718
  if (S_ISDIR(nitem->mode)) {
@@ -771,32 +720,48 @@ static int diff_from_iterators(
771
720
  * it or if the user requested the contents of untracked
772
721
  * directories and it is not under an ignored directory.
773
722
  */
774
- bool contains_tracked =
775
- entry_is_prefixed(nitem, old_iter, oitem);
776
- bool recurse_untracked =
723
+ bool recurse_into_dir =
777
724
  (delta_type == GIT_DELTA_UNTRACKED &&
778
- (diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0);
725
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) ||
726
+ (delta_type == GIT_DELTA_IGNORED &&
727
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS));
779
728
 
780
729
  /* do not advance into directories that contain a .git file */
781
- if (!contains_tracked && recurse_untracked) {
730
+ if (!contains_oitem && recurse_into_dir) {
782
731
  git_buf *full = NULL;
783
- if (git_iterator_current_workdir_path(new_iter, &full) < 0)
732
+ if (git_iterator_current_workdir_path(&full, new_iter) < 0)
784
733
  goto fail;
785
734
  if (git_path_contains_dir(full, DOT_GIT))
786
- recurse_untracked = false;
735
+ recurse_into_dir = false;
787
736
  }
788
737
 
789
- if (contains_tracked || recurse_untracked) {
790
- /* if this directory is ignored, remember it as the
791
- * "ignore_prefix" for processing contained items
792
- */
793
- if (delta_type == GIT_DELTA_UNTRACKED &&
794
- git_iterator_current_is_ignored(new_iter))
795
- git_buf_sets(&ignore_prefix, nitem->path);
738
+ /* if directory is ignored, remember ignore_prefix */
739
+ if ((contains_oitem || recurse_into_dir) &&
740
+ delta_type == GIT_DELTA_UNTRACKED &&
741
+ git_iterator_current_is_ignored(new_iter))
742
+ {
743
+ git_buf_sets(&ignore_prefix, nitem->path);
744
+ delta_type = GIT_DELTA_IGNORED;
745
+
746
+ /* skip recursion if we've just learned this is ignored */
747
+ if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS))
748
+ recurse_into_dir = false;
749
+ }
796
750
 
797
- if (git_iterator_advance_into_directory(new_iter, &nitem) < 0)
798
- goto fail;
751
+ if (contains_oitem || recurse_into_dir) {
752
+ /* advance into directory */
753
+ error = git_iterator_advance_into(&nitem, new_iter);
799
754
 
755
+ /* if directory is empty, can't advance into it, so skip */
756
+ if (error == GIT_ENOTFOUND) {
757
+ giterr_clear();
758
+ error = git_iterator_advance(&nitem, new_iter);
759
+
760
+ git_buf_clear(&ignore_prefix);
761
+ }
762
+
763
+ if (error < 0)
764
+ goto fail;
800
765
  continue;
801
766
  }
802
767
  }
@@ -816,8 +781,9 @@ static int diff_from_iterators(
816
781
  * checked before container directory exclusions are used to
817
782
  * skip the file.
818
783
  */
819
- else if (delta_type == GIT_DELTA_IGNORED) {
820
- if (git_iterator_advance(new_iter, &nitem) < 0)
784
+ else if (delta_type == GIT_DELTA_IGNORED &&
785
+ DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) {
786
+ if (git_iterator_advance(&nitem, new_iter) < 0)
821
787
  goto fail;
822
788
  continue; /* ignored parent directory, so skip completely */
823
789
  }
@@ -825,28 +791,28 @@ static int diff_from_iterators(
825
791
  else if (git_iterator_current_is_ignored(new_iter))
826
792
  delta_type = GIT_DELTA_IGNORED;
827
793
 
828
- else if (new_iter->type != GIT_ITERATOR_WORKDIR)
794
+ else if (new_iter->type != GIT_ITERATOR_TYPE_WORKDIR)
829
795
  delta_type = GIT_DELTA_ADDED;
830
796
 
831
797
  if (diff_delta__from_one(diff, delta_type, nitem) < 0)
832
798
  goto fail;
833
799
 
834
800
  /* if we are generating TYPECHANGE records then check for that
835
- * instead of just generating an ADD/UNTRACKED record
801
+ * instead of just generating an ADDED/UNTRACKED record
836
802
  */
837
803
  if (delta_type != GIT_DELTA_IGNORED &&
838
- (diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE_TREES) != 0 &&
839
- entry_is_prefixed(nitem, old_iter, oitem))
804
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) &&
805
+ contains_oitem)
840
806
  {
841
- /* this entry was a tree! convert to TYPECHANGE */
842
- git_diff_delta *last = diff_delta__last_for_item(diff, oitem);
807
+ /* this entry was prefixed with a tree - make TYPECHANGE */
808
+ git_diff_delta *last = diff_delta__last_for_item(diff, nitem);
843
809
  if (last) {
844
810
  last->status = GIT_DELTA_TYPECHANGE;
845
811
  last->old_file.mode = GIT_FILEMODE_TREE;
846
812
  }
847
813
  }
848
814
 
849
- if (git_iterator_advance(new_iter, &nitem) < 0)
815
+ if (git_iterator_advance(&nitem, new_iter) < 0)
850
816
  goto fail;
851
817
  }
852
818
 
@@ -854,231 +820,116 @@ static int diff_from_iterators(
854
820
  * (or ADDED and DELETED pair if type changed)
855
821
  */
856
822
  else {
857
- assert(oitem && nitem && entry_compare(oitem, nitem) == 0);
823
+ assert(oitem && nitem && cmp == 0);
858
824
 
859
825
  if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 ||
860
- git_iterator_advance(old_iter, &oitem) < 0 ||
861
- git_iterator_advance(new_iter, &nitem) < 0)
826
+ git_iterator_advance(&oitem, old_iter) < 0 ||
827
+ git_iterator_advance(&nitem, new_iter) < 0)
862
828
  goto fail;
863
829
  }
864
830
  }
865
831
 
866
- git_iterator_free(old_iter);
867
- git_iterator_free(new_iter);
868
- git_buf_free(&ignore_prefix);
869
-
870
832
  *diff_ptr = diff;
871
- return 0;
872
833
 
873
834
  fail:
874
- git_iterator_free(old_iter);
875
- git_iterator_free(new_iter);
835
+ if (!*diff_ptr) {
836
+ git_diff_list_free(diff);
837
+ error = -1;
838
+ }
839
+
876
840
  git_buf_free(&ignore_prefix);
877
841
 
878
- git_diff_list_free(diff);
879
- *diff_ptr = NULL;
880
- return -1;
842
+ return error;
881
843
  }
882
844
 
845
+ #define DIFF_FROM_ITERATORS(MAKE_FIRST, MAKE_SECOND) do { \
846
+ git_iterator *a = NULL, *b = NULL; \
847
+ char *pfx = opts ? git_pathspec_prefix(&opts->pathspec) : NULL; \
848
+ GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \
849
+ if (!(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
850
+ error = git_diff__from_iterators(diff, repo, a, b, opts); \
851
+ git__free(pfx); git_iterator_free(a); git_iterator_free(b); \
852
+ } while (0)
883
853
 
884
854
  int git_diff_tree_to_tree(
855
+ git_diff_list **diff,
885
856
  git_repository *repo,
886
- const git_diff_options *opts, /**< can be NULL for defaults */
887
857
  git_tree *old_tree,
888
858
  git_tree *new_tree,
889
- git_diff_list **diff)
859
+ const git_diff_options *opts)
890
860
  {
891
- git_iterator *a = NULL, *b = NULL;
892
- char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
861
+ int error = 0;
893
862
 
894
- assert(repo && old_tree && new_tree && diff);
863
+ assert(diff && repo);
895
864
 
896
- if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
897
- git_iterator_for_tree_range(&b, repo, new_tree, prefix, prefix) < 0)
898
- return -1;
865
+ DIFF_FROM_ITERATORS(
866
+ git_iterator_for_tree(&a, old_tree, 0, pfx, pfx),
867
+ git_iterator_for_tree(&b, new_tree, 0, pfx, pfx)
868
+ );
899
869
 
900
- git__free(prefix);
901
-
902
- return diff_from_iterators(repo, opts, a, b, diff);
870
+ return error;
903
871
  }
904
872
 
905
- int git_diff_index_to_tree(
873
+ int git_diff_tree_to_index(
874
+ git_diff_list **diff,
906
875
  git_repository *repo,
907
- const git_diff_options *opts,
908
876
  git_tree *old_tree,
909
- git_diff_list **diff)
877
+ git_index *index,
878
+ const git_diff_options *opts)
910
879
  {
911
- git_iterator *a = NULL, *b = NULL;
912
- char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
913
-
914
- assert(repo && diff);
880
+ int error = 0;
915
881
 
916
- if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 ||
917
- git_iterator_for_index_range(&b, repo, prefix, prefix) < 0)
918
- goto on_error;
882
+ assert(diff && repo);
919
883
 
920
- git__free(prefix);
884
+ if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
885
+ return error;
921
886
 
922
- return diff_from_iterators(repo, opts, a, b, diff);
887
+ DIFF_FROM_ITERATORS(
888
+ git_iterator_for_tree(&a, old_tree, 0, pfx, pfx),
889
+ git_iterator_for_index(&b, index, 0, pfx, pfx)
890
+ );
923
891
 
924
- on_error:
925
- git__free(prefix);
926
- git_iterator_free(a);
927
- return -1;
892
+ return error;
928
893
  }
929
894
 
930
- int git_diff_workdir_to_index(
895
+ int git_diff_index_to_workdir(
896
+ git_diff_list **diff,
931
897
  git_repository *repo,
932
- const git_diff_options *opts,
933
- git_diff_list **diff)
898
+ git_index *index,
899
+ const git_diff_options *opts)
934
900
  {
935
- git_iterator *a = NULL, *b = NULL;
936
- int error;
937
-
938
- char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
939
-
940
- assert(repo && diff);
901
+ int error = 0;
941
902
 
942
- if ((error = git_iterator_for_index_range(&a, repo, prefix, prefix)) < 0 ||
943
- (error = git_iterator_for_workdir_range(&b, repo, prefix, prefix)) < 0)
944
- goto on_error;
903
+ assert(diff && repo);
945
904
 
946
- git__free(prefix);
905
+ if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
906
+ return error;
947
907
 
948
- return diff_from_iterators(repo, opts, a, b, diff);
908
+ DIFF_FROM_ITERATORS(
909
+ git_iterator_for_index(&a, index, 0, pfx, pfx),
910
+ git_iterator_for_workdir(
911
+ &b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
912
+ );
949
913
 
950
- on_error:
951
- git__free(prefix);
952
- git_iterator_free(a);
953
914
  return error;
954
915
  }
955
916
 
956
917
 
957
- int git_diff_workdir_to_tree(
918
+ int git_diff_tree_to_workdir(
919
+ git_diff_list **diff,
958
920
  git_repository *repo,
959
- const git_diff_options *opts,
960
921
  git_tree *old_tree,
961
- git_diff_list **diff)
962
- {
963
- git_iterator *a = NULL, *b = NULL;
964
- int error;
965
-
966
- char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL;
967
-
968
- assert(repo && old_tree && diff);
969
-
970
- if ((error = git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix)) < 0 ||
971
- (error = git_iterator_for_workdir_range(&b, repo, prefix, prefix)) < 0)
972
- goto on_error;
973
-
974
- git__free(prefix);
975
-
976
- return diff_from_iterators(repo, opts, a, b, diff);
977
-
978
- on_error:
979
- git__free(prefix);
980
- git_iterator_free(a);
981
- return error;
982
- }
983
-
984
-
985
- bool git_diff_delta__should_skip(
986
- const git_diff_options *opts, const git_diff_delta *delta)
987
- {
988
- uint32_t flags = opts ? opts->flags : 0;
989
-
990
- if (delta->status == GIT_DELTA_UNMODIFIED &&
991
- (flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
992
- return true;
993
-
994
- if (delta->status == GIT_DELTA_IGNORED &&
995
- (flags & GIT_DIFF_INCLUDE_IGNORED) == 0)
996
- return true;
997
-
998
- if (delta->status == GIT_DELTA_UNTRACKED &&
999
- (flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
1000
- return true;
1001
-
1002
- return false;
1003
- }
1004
-
1005
-
1006
- int git_diff_merge(
1007
- git_diff_list *onto,
1008
- const git_diff_list *from)
922
+ const git_diff_options *opts)
1009
923
  {
1010
924
  int error = 0;
1011
- git_pool onto_pool;
1012
- git_vector onto_new;
1013
- git_diff_delta *delta;
1014
- bool ignore_case = false;
1015
- unsigned int i, j;
1016
-
1017
- assert(onto && from);
1018
-
1019
- if (!from->deltas.length)
1020
- return 0;
1021
-
1022
- if (git_vector_init(&onto_new, onto->deltas.length, diff_delta__cmp) < 0 ||
1023
- git_pool_init(&onto_pool, 1, 0) < 0)
1024
- return -1;
1025
925
 
1026
- if ((onto->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0 ||
1027
- (from->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0)
1028
- {
1029
- ignore_case = true;
1030
-
1031
- /* This function currently only supports merging diff lists that
1032
- * are sorted identically. */
1033
- assert((onto->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0 &&
1034
- (from->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0);
1035
- }
1036
-
1037
- for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) {
1038
- git_diff_delta *o = GIT_VECTOR_GET(&onto->deltas, i);
1039
- const git_diff_delta *f = GIT_VECTOR_GET(&from->deltas, j);
1040
- int cmp = !f ? -1 : !o ? 1 : STRCMP_CASESELECT(ignore_case, o->old_file.path, f->old_file.path);
1041
-
1042
- if (cmp < 0) {
1043
- delta = diff_delta__dup(o, &onto_pool);
1044
- i++;
1045
- } else if (cmp > 0) {
1046
- delta = diff_delta__dup(f, &onto_pool);
1047
- j++;
1048
- } else {
1049
- delta = diff_delta__merge_like_cgit(o, f, &onto_pool);
1050
- i++;
1051
- j++;
1052
- }
1053
-
1054
- /* the ignore rules for the target may not match the source
1055
- * or the result of a merged delta could be skippable...
1056
- */
1057
- if (git_diff_delta__should_skip(&onto->opts, delta)) {
1058
- git__free(delta);
1059
- continue;
1060
- }
1061
-
1062
- if ((error = !delta ? -1 : git_vector_insert(&onto_new, delta)) < 0)
1063
- break;
1064
- }
926
+ assert(diff && repo);
1065
927
 
1066
- if (!error) {
1067
- git_vector_swap(&onto->deltas, &onto_new);
1068
- git_pool_swap(&onto->pool, &onto_pool);
1069
- onto->new_src = from->new_src;
1070
-
1071
- /* prefix strings also come from old pool, so recreate those.*/
1072
- onto->opts.old_prefix =
1073
- git_pool_strdup_safe(&onto->pool, onto->opts.old_prefix);
1074
- onto->opts.new_prefix =
1075
- git_pool_strdup_safe(&onto->pool, onto->opts.new_prefix);
1076
- }
1077
-
1078
- git_vector_foreach(&onto_new, i, delta)
1079
- git__free(delta);
1080
- git_vector_free(&onto_new);
1081
- git_pool_clear(&onto_pool);
928
+ DIFF_FROM_ITERATORS(
929
+ git_iterator_for_tree(&a, old_tree, 0, pfx, pfx),
930
+ git_iterator_for_workdir(
931
+ &b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
932
+ );
1082
933
 
1083
934
  return error;
1084
935
  }