rugged 0.24.6.1 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/ext/rugged/extconf.rb +9 -2
  4. data/ext/rugged/rugged.c +85 -21
  5. data/ext/rugged/rugged.h +7 -21
  6. data/ext/rugged/rugged_backend.c +3 -20
  7. data/ext/rugged/rugged_blame.c +7 -24
  8. data/ext/rugged/rugged_blob.c +136 -59
  9. data/ext/rugged/rugged_branch.c +3 -20
  10. data/ext/rugged/rugged_branch_collection.c +3 -20
  11. data/ext/rugged/rugged_commit.c +251 -101
  12. data/ext/rugged/rugged_config.c +3 -20
  13. data/ext/rugged/rugged_cred.c +3 -20
  14. data/ext/rugged/rugged_diff.c +3 -20
  15. data/ext/rugged/rugged_diff_delta.c +3 -20
  16. data/ext/rugged/rugged_diff_hunk.c +3 -20
  17. data/ext/rugged/rugged_diff_line.c +3 -20
  18. data/ext/rugged/rugged_index.c +46 -229
  19. data/ext/rugged/rugged_note.c +3 -20
  20. data/ext/rugged/rugged_object.c +3 -20
  21. data/ext/rugged/rugged_patch.c +192 -34
  22. data/ext/rugged/rugged_rebase.c +90 -48
  23. data/ext/rugged/rugged_reference.c +4 -21
  24. data/ext/rugged/rugged_reference_collection.c +3 -20
  25. data/ext/rugged/rugged_remote.c +70 -42
  26. data/ext/rugged/rugged_remote_collection.c +3 -20
  27. data/ext/rugged/rugged_repo.c +50 -59
  28. data/ext/rugged/rugged_revwalk.c +4 -21
  29. data/ext/rugged/rugged_settings.c +3 -20
  30. data/ext/rugged/rugged_signature.c +3 -20
  31. data/ext/rugged/rugged_submodule.c +4 -21
  32. data/ext/rugged/rugged_submodule_collection.c +3 -20
  33. data/ext/rugged/rugged_tag.c +3 -20
  34. data/ext/rugged/rugged_tag_collection.c +3 -20
  35. data/ext/rugged/rugged_tree.c +189 -184
  36. data/lib/rugged/attributes.rb +5 -0
  37. data/lib/rugged/blob.rb +5 -0
  38. data/lib/rugged/branch.rb +6 -1
  39. data/lib/rugged/commit.rb +5 -0
  40. data/lib/rugged/console.rb +5 -0
  41. data/lib/rugged/credentials.rb +5 -0
  42. data/lib/rugged/diff/delta.rb +5 -0
  43. data/lib/rugged/diff/hunk.rb +5 -0
  44. data/lib/rugged/diff/line.rb +5 -0
  45. data/lib/rugged/diff.rb +5 -0
  46. data/lib/rugged/index.rb +120 -0
  47. data/lib/rugged/object.rb +5 -0
  48. data/lib/rugged/patch.rb +5 -0
  49. data/lib/rugged/reference.rb +5 -0
  50. data/lib/rugged/remote.rb +5 -0
  51. data/lib/rugged/repository.rb +9 -4
  52. data/lib/rugged/submodule_collection.rb +5 -0
  53. data/lib/rugged/tag.rb +5 -0
  54. data/lib/rugged/tree.rb +156 -1
  55. data/lib/rugged/version.rb +6 -1
  56. data/lib/rugged/walker.rb +5 -0
  57. data/lib/rugged.rb +5 -0
  58. data/vendor/libgit2/CMakeLists.txt +12 -2
  59. data/vendor/libgit2/include/git2/blob.h +39 -28
  60. data/vendor/libgit2/include/git2/commit.h +76 -0
  61. data/vendor/libgit2/include/git2/common.h +21 -1
  62. data/vendor/libgit2/include/git2/describe.h +5 -2
  63. data/vendor/libgit2/include/git2/diff.h +62 -7
  64. data/vendor/libgit2/include/git2/errors.h +2 -1
  65. data/vendor/libgit2/include/git2/index.h +25 -0
  66. data/vendor/libgit2/include/git2/merge.h +10 -1
  67. data/vendor/libgit2/include/git2/odb.h +47 -1
  68. data/vendor/libgit2/include/git2/pack.h +4 -4
  69. data/vendor/libgit2/include/git2/patch.h +1 -1
  70. data/vendor/libgit2/include/git2/proxy.h +92 -0
  71. data/vendor/libgit2/include/git2/refs.h +11 -0
  72. data/vendor/libgit2/include/git2/remote.h +21 -8
  73. data/vendor/libgit2/include/git2/repository.h +20 -1
  74. data/vendor/libgit2/include/git2/revwalk.h +4 -6
  75. data/vendor/libgit2/include/git2/signature.h +13 -0
  76. data/vendor/libgit2/include/git2/submodule.h +11 -3
  77. data/vendor/libgit2/include/git2/sys/merge.h +177 -0
  78. data/vendor/libgit2/include/git2/sys/odb_backend.h +11 -0
  79. data/vendor/libgit2/include/git2/sys/remote.h +16 -0
  80. data/vendor/libgit2/include/git2/sys/stream.h +2 -1
  81. data/vendor/libgit2/include/git2/sys/time.h +31 -0
  82. data/vendor/libgit2/include/git2/sys/transport.h +3 -1
  83. data/vendor/libgit2/include/git2/tag.h +9 -0
  84. data/vendor/libgit2/include/git2/transaction.h +9 -0
  85. data/vendor/libgit2/include/git2/tree.h +55 -0
  86. data/vendor/libgit2/include/git2/version.h +4 -4
  87. data/vendor/libgit2/include/git2.h +1 -0
  88. data/vendor/libgit2/src/annotated_commit.c +99 -80
  89. data/vendor/libgit2/src/annotated_commit.h +5 -2
  90. data/vendor/libgit2/src/apply.c +377 -0
  91. data/vendor/libgit2/src/apply.h +21 -0
  92. data/vendor/libgit2/src/array.h +0 -1
  93. data/vendor/libgit2/src/blob.c +71 -39
  94. data/vendor/libgit2/src/branch.c +7 -5
  95. data/vendor/libgit2/src/buffer.c +252 -20
  96. data/vendor/libgit2/src/buffer.h +8 -0
  97. data/vendor/libgit2/src/checkout.c +69 -42
  98. data/vendor/libgit2/src/clone.c +0 -8
  99. data/vendor/libgit2/src/commit.c +193 -49
  100. data/vendor/libgit2/src/commit_list.c +8 -3
  101. data/vendor/libgit2/src/commit_list.h +1 -0
  102. data/vendor/libgit2/src/common.h +2 -1
  103. data/vendor/libgit2/src/config.c +3 -3
  104. data/vendor/libgit2/src/config_file.c +20 -10
  105. data/vendor/libgit2/src/crlf.c +1 -0
  106. data/vendor/libgit2/src/curl_stream.c +106 -6
  107. data/vendor/libgit2/src/delta.c +238 -62
  108. data/vendor/libgit2/src/delta.h +79 -58
  109. data/vendor/libgit2/src/describe.c +1 -1
  110. data/vendor/libgit2/src/diff.c +32 -1554
  111. data/vendor/libgit2/src/diff.h +14 -122
  112. data/vendor/libgit2/src/diff_driver.c +4 -6
  113. data/vendor/libgit2/src/diff_file.c +3 -0
  114. data/vendor/libgit2/src/diff_generate.c +1613 -0
  115. data/vendor/libgit2/src/diff_generate.h +123 -0
  116. data/vendor/libgit2/src/diff_parse.c +101 -0
  117. data/vendor/libgit2/src/diff_parse.h +18 -0
  118. data/vendor/libgit2/src/diff_print.c +263 -144
  119. data/vendor/libgit2/src/diff_stats.c +21 -12
  120. data/vendor/libgit2/src/diff_tform.c +1 -0
  121. data/vendor/libgit2/src/diff_tform.h +22 -0
  122. data/vendor/libgit2/src/diff_xdiff.c +9 -9
  123. data/vendor/libgit2/src/diff_xdiff.h +5 -5
  124. data/vendor/libgit2/src/fetchhead.c +8 -8
  125. data/vendor/libgit2/src/filebuf.c +6 -1
  126. data/vendor/libgit2/src/filebuf.h +1 -0
  127. data/vendor/libgit2/src/fileops.c +22 -1
  128. data/vendor/libgit2/src/fileops.h +8 -2
  129. data/vendor/libgit2/src/fnmatch.c +18 -5
  130. data/vendor/libgit2/src/global.c +21 -4
  131. data/vendor/libgit2/src/global.h +6 -0
  132. data/vendor/libgit2/src/graph.c +1 -1
  133. data/vendor/libgit2/src/index.c +159 -46
  134. data/vendor/libgit2/src/index.h +2 -0
  135. data/vendor/libgit2/src/iterator.c +1573 -1468
  136. data/vendor/libgit2/src/iterator.h +52 -69
  137. data/vendor/libgit2/src/merge.c +163 -64
  138. data/vendor/libgit2/src/merge.h +61 -2
  139. data/vendor/libgit2/src/merge_driver.c +397 -0
  140. data/vendor/libgit2/src/merge_driver.h +60 -0
  141. data/vendor/libgit2/src/merge_file.c +11 -49
  142. data/vendor/libgit2/src/netops.c +12 -10
  143. data/vendor/libgit2/src/object_api.c +19 -1
  144. data/vendor/libgit2/src/odb.c +228 -52
  145. data/vendor/libgit2/src/odb_loose.c +19 -1
  146. data/vendor/libgit2/src/odb_mempack.c +1 -1
  147. data/vendor/libgit2/src/odb_pack.c +27 -1
  148. data/vendor/libgit2/src/openssl_stream.c +4 -5
  149. data/vendor/libgit2/src/pack-objects.c +105 -76
  150. data/vendor/libgit2/src/pack-objects.h +13 -12
  151. data/vendor/libgit2/src/pack.c +16 -10
  152. data/vendor/libgit2/src/pack.h +2 -0
  153. data/vendor/libgit2/src/patch.c +216 -0
  154. data/vendor/libgit2/src/patch.h +66 -0
  155. data/vendor/libgit2/src/{diff_patch.c → patch_generate.c} +203 -376
  156. data/vendor/libgit2/src/patch_generate.h +68 -0
  157. data/vendor/libgit2/src/patch_parse.c +1159 -0
  158. data/vendor/libgit2/src/patch_parse.h +56 -0
  159. data/vendor/libgit2/src/path.c +38 -2
  160. data/vendor/libgit2/src/path.h +18 -0
  161. data/vendor/libgit2/src/pathspec.c +1 -1
  162. data/vendor/libgit2/src/pool.h +5 -0
  163. data/vendor/libgit2/src/pqueue.c +12 -5
  164. data/vendor/libgit2/src/pqueue.h +1 -0
  165. data/vendor/libgit2/src/proxy.c +32 -0
  166. data/vendor/libgit2/src/proxy.h +14 -0
  167. data/vendor/libgit2/src/push.c +1 -1
  168. data/vendor/libgit2/src/rebase.c +63 -36
  169. data/vendor/libgit2/src/refdb.c +4 -2
  170. data/vendor/libgit2/src/refdb_fs.c +82 -54
  171. data/vendor/libgit2/src/refs.c +13 -1
  172. data/vendor/libgit2/src/remote.c +20 -81
  173. data/vendor/libgit2/src/repository.c +212 -29
  174. data/vendor/libgit2/src/reset.c +1 -1
  175. data/vendor/libgit2/src/revparse.c +1 -1
  176. data/vendor/libgit2/src/revwalk.c +260 -184
  177. data/vendor/libgit2/src/settings.c +11 -3
  178. data/vendor/libgit2/src/signature.c +27 -2
  179. data/vendor/libgit2/src/sortedcache.c +14 -5
  180. data/vendor/libgit2/src/stash.c +1 -0
  181. data/vendor/libgit2/src/status.c +1 -0
  182. data/vendor/libgit2/src/stransport_stream.c +4 -2
  183. data/vendor/libgit2/src/stream.h +2 -2
  184. data/vendor/libgit2/src/submodule.c +16 -4
  185. data/vendor/libgit2/src/sysdir.c +1 -1
  186. data/vendor/libgit2/src/transport.c +3 -5
  187. data/vendor/libgit2/src/transports/http.c +38 -13
  188. data/vendor/libgit2/src/transports/local.c +4 -1
  189. data/vendor/libgit2/src/transports/smart.c +6 -0
  190. data/vendor/libgit2/src/transports/smart.h +1 -0
  191. data/vendor/libgit2/src/transports/smart_pkt.c +5 -13
  192. data/vendor/libgit2/src/transports/smart_protocol.c +22 -7
  193. data/vendor/libgit2/src/transports/winhttp.c +144 -11
  194. data/vendor/libgit2/src/tree.c +267 -2
  195. data/vendor/libgit2/src/unix/posix.h +10 -0
  196. data/vendor/libgit2/src/unix/pthread.h +2 -0
  197. data/vendor/libgit2/src/util.c +25 -2
  198. data/vendor/libgit2/src/util.h +10 -0
  199. data/vendor/libgit2/src/varint.c +44 -0
  200. data/vendor/libgit2/src/varint.h +15 -0
  201. data/vendor/libgit2/src/vector.c +58 -0
  202. data/vendor/libgit2/src/vector.h +8 -0
  203. data/vendor/libgit2/src/win32/posix.h +3 -0
  204. data/vendor/libgit2/src/win32/thread.c +18 -0
  205. data/vendor/libgit2/src/win32/thread.h +2 -0
  206. data/vendor/libgit2/src/win32/w32_util.h +1 -1
  207. data/vendor/libgit2/src/zstream.c +37 -8
  208. data/vendor/libgit2/src/zstream.h +8 -1
  209. metadata +100 -82
  210. data/vendor/libgit2/Makefile.embed +0 -60
  211. data/vendor/libgit2/src/delta-apply.c +0 -166
  212. data/vendor/libgit2/src/delta-apply.h +0 -62
  213. data/vendor/libgit2/src/diff_patch.h +0 -83
@@ -13,6 +13,7 @@
13
13
  #include "revwalk.h"
14
14
  #include "git2/revparse.h"
15
15
  #include "merge.h"
16
+ #include "vector.h"
16
17
 
17
18
  GIT__USE_OIDMAP
18
19
 
@@ -41,97 +42,6 @@ git_commit_list_node *git_revwalk__commit_lookup(
41
42
  return commit;
42
43
  }
43
44
 
44
- typedef git_array_t(git_commit_list_node*) commit_list_node_array;
45
-
46
- static bool interesting_arr(commit_list_node_array arr)
47
- {
48
- git_commit_list_node **n;
49
- size_t i = 0, size;
50
-
51
- size = git_array_size(arr);
52
- for (i = 0; i < size; i++) {
53
- n = git_array_get(arr, i);
54
- if (!*n)
55
- break;
56
-
57
- if (!(*n)->uninteresting)
58
- return true;
59
- }
60
-
61
- return false;
62
- }
63
-
64
- static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit)
65
- {
66
- int error;
67
- unsigned short i;
68
- commit_list_node_array pending = GIT_ARRAY_INIT;
69
- git_commit_list_node **tmp;
70
-
71
- assert(commit);
72
-
73
- do {
74
- commit->uninteresting = 1;
75
-
76
- if ((error = git_commit_list_parse(walk, commit)) < 0)
77
- return error;
78
-
79
- for (i = 0; i < commit->out_degree; ++i)
80
- if (!commit->parents[i]->uninteresting) {
81
- git_commit_list_node **node = git_array_alloc(pending);
82
- GITERR_CHECK_ALLOC(node);
83
- *node = commit->parents[i];
84
- }
85
-
86
- tmp = git_array_pop(pending);
87
- commit = tmp ? *tmp : NULL;
88
-
89
- } while (commit != NULL && !interesting_arr(pending));
90
-
91
- git_array_clear(pending);
92
-
93
- return 0;
94
- }
95
-
96
- static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide)
97
- {
98
- int error;
99
-
100
- if (!hide && walk->hide_cb)
101
- hide = walk->hide_cb(&commit->oid, walk->hide_cb_payload);
102
-
103
- if (hide && mark_uninteresting(walk, commit) < 0)
104
- return -1;
105
-
106
- if (commit->seen)
107
- return 0;
108
-
109
- commit->seen = 1;
110
-
111
- if ((error = git_commit_list_parse(walk, commit)) < 0)
112
- return error;
113
-
114
- if (!hide)
115
- return walk->enqueue(walk, commit);
116
-
117
- return 0;
118
- }
119
-
120
- static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commit)
121
- {
122
- unsigned short i, max;
123
- int error = 0;
124
-
125
- max = commit->out_degree;
126
- if (walk->first_parent && commit->out_degree)
127
- max = 1;
128
-
129
- for (i = 0; i < max && !error; ++i)
130
- error = process_commit(walk, commit->parents[i], commit->uninteresting);
131
-
132
- return error;
133
- }
134
-
135
45
  static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
136
46
  {
137
47
  git_oid commit_id;
@@ -321,17 +231,12 @@ static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *com
321
231
 
322
232
  static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk)
323
233
  {
324
- int error;
325
234
  git_commit_list_node *next;
326
235
 
327
- while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL)
328
- if (!next->uninteresting) {
329
- if ((error = process_commit_parents(walk, next)) < 0)
330
- return error;
331
-
332
- *object_out = next;
333
- return 0;
334
- }
236
+ if ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {
237
+ *object_out = next;
238
+ return 0;
239
+ }
335
240
 
336
241
  giterr_clear();
337
242
  return GIT_ITEROVER;
@@ -339,17 +244,15 @@ static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk
339
244
 
340
245
  static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk *walk)
341
246
  {
342
- int error;
343
247
  git_commit_list_node *next;
344
248
 
345
- while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL)
249
+ while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) {
250
+ /* Some commits might become uninteresting after being added to the list */
346
251
  if (!next->uninteresting) {
347
- if ((error = process_commit_parents(walk, next)) < 0)
348
- return error;
349
-
350
252
  *object_out = next;
351
253
  return 0;
352
254
  }
255
+ }
353
256
 
354
257
  giterr_clear();
355
258
  return GIT_ITEROVER;
@@ -358,121 +261,283 @@ static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk
358
261
  static int revwalk_next_toposort(git_commit_list_node **object_out, git_revwalk *walk)
359
262
  {
360
263
  git_commit_list_node *next;
361
- unsigned short i, max;
362
264
 
363
- for (;;) {
364
- next = git_commit_list_pop(&walk->iterator_topo);
365
- if (next == NULL) {
366
- giterr_clear();
367
- return GIT_ITEROVER;
265
+ while ((next = git_commit_list_pop(&walk->iterator_topo)) != NULL) {
266
+ /* Some commits might become uninteresting after being added to the list */
267
+ if (!next->uninteresting) {
268
+ *object_out = next;
269
+ return 0;
368
270
  }
271
+ }
369
272
 
370
- if (next->in_degree > 0) {
371
- next->topo_delay = 1;
372
- continue;
273
+ giterr_clear();
274
+ return GIT_ITEROVER;
275
+ }
276
+
277
+ static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
278
+ {
279
+ *object_out = git_commit_list_pop(&walk->iterator_reverse);
280
+ return *object_out ? 0 : GIT_ITEROVER;
281
+ }
282
+
283
+ static void mark_parents_uninteresting(git_commit_list_node *commit)
284
+ {
285
+ unsigned short i;
286
+ git_commit_list *parents = NULL;
287
+
288
+ for (i = 0; i < commit->out_degree; i++)
289
+ git_commit_list_insert(commit->parents[i], &parents);
290
+
291
+
292
+ while (parents) {
293
+ commit = git_commit_list_pop(&parents);
294
+
295
+ while (commit) {
296
+ if (commit->uninteresting)
297
+ break;
298
+
299
+ commit->uninteresting = 1;
300
+ /*
301
+ * If we've reached this commit some other way
302
+ * already, we need to mark its parents uninteresting
303
+ * as well.
304
+ */
305
+ if (!commit->parents)
306
+ break;
307
+
308
+ for (i = 0; i < commit->out_degree; i++)
309
+ git_commit_list_insert(commit->parents[i], &parents);
310
+ commit = commit->parents[0];
373
311
  }
312
+ }
313
+ }
374
314
 
315
+ static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, git_commit_list **list)
316
+ {
317
+ unsigned short i;
318
+ int error;
375
319
 
376
- max = next->out_degree;
377
- if (walk->first_parent && next->out_degree)
378
- max = 1;
320
+ if (commit->added)
321
+ return 0;
379
322
 
380
- for (i = 0; i < max; ++i) {
381
- git_commit_list_node *parent = next->parents[i];
323
+ commit->added = 1;
324
+
325
+ /*
326
+ * Go full on in the uninteresting case as we want to include
327
+ * as many of these as we can.
328
+ *
329
+ * Usually we haven't parsed the parent of a parent, but if we
330
+ * have it we reached it via other means so we want to mark
331
+ * its parents recursively too.
332
+ */
333
+ if (commit->uninteresting) {
334
+ for (i = 0; i < commit->out_degree; i++) {
335
+ git_commit_list_node *p = commit->parents[i];
336
+ p->uninteresting = 1;
382
337
 
383
- if (--parent->in_degree == 0 && parent->topo_delay) {
384
- parent->topo_delay = 0;
385
- if (git_commit_list_insert(parent, &walk->iterator_topo) == NULL)
386
- return -1;
387
- }
338
+ /* git does it gently here, but we don't like missing objects */
339
+ if ((error = git_commit_list_parse(walk, p)) < 0)
340
+ return error;
341
+
342
+ if (p->parents)
343
+ mark_parents_uninteresting(p);
344
+
345
+ p->seen = 1;
346
+ git_commit_list_insert_by_date(p, list);
388
347
  }
389
348
 
390
- *object_out = next;
391
349
  return 0;
392
350
  }
351
+
352
+ /*
353
+ * Now on to what we do if the commit is indeed
354
+ * interesting. Here we do want things like first-parent take
355
+ * effect as this is what we'll be showing.
356
+ */
357
+ for (i = 0; i < commit->out_degree; i++) {
358
+ git_commit_list_node *p = commit->parents[i];
359
+
360
+ if ((error = git_commit_list_parse(walk, p)) < 0)
361
+ return error;
362
+
363
+ if (walk->hide_cb && walk->hide_cb(&p->oid, walk->hide_cb_payload))
364
+ continue;
365
+
366
+ if (!p->seen) {
367
+ p->seen = 1;
368
+ git_commit_list_insert_by_date(p, list);
369
+ }
370
+
371
+ if (walk->first_parent)
372
+ break;
373
+ }
374
+ return 0;
393
375
  }
394
376
 
395
- static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
377
+ static int everybody_uninteresting(git_commit_list *orig)
396
378
  {
397
- *object_out = git_commit_list_pop(&walk->iterator_reverse);
398
- return *object_out ? 0 : GIT_ITEROVER;
379
+ git_commit_list *list = orig;
380
+
381
+ while (list) {
382
+ git_commit_list_node *commit = list->item;
383
+ list = list->next;
384
+ if (!commit->uninteresting)
385
+ return 0;
386
+ }
387
+
388
+ return 1;
399
389
  }
400
390
 
391
+ /* How many unintersting commits we want to look at after we run out of interesting ones */
392
+ #define SLOP 5
401
393
 
402
- static int interesting(git_pqueue *list)
394
+ static int still_interesting(git_commit_list *list, int64_t time, int slop)
403
395
  {
404
- size_t i;
396
+ /* The empty list is pretty boring */
397
+ if (!list)
398
+ return 0;
405
399
 
406
- for (i = 0; i < git_pqueue_size(list); i++) {
407
- git_commit_list_node *commit = git_pqueue_get(list, i);
408
- if (!commit->uninteresting)
409
- return 1;
410
- }
400
+ /*
401
+ * If the destination list has commits with an earlier date
402
+ * than our source we want to continue looking.
403
+ */
404
+ if (time <= list->item->time)
405
+ return SLOP;
411
406
 
412
- return 0;
407
+ /* If we find interesting commits, we reset the slop count */
408
+ if (!everybody_uninteresting(list))
409
+ return SLOP;
410
+
411
+ /* Everything's uninteresting, reduce the count */
412
+ return slop - 1;
413
413
  }
414
414
 
415
- static int contains(git_pqueue *list, git_commit_list_node *node)
415
+ static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits)
416
416
  {
417
- size_t i;
417
+ int error, slop = SLOP;
418
+ int64_t time = ~0ll;
419
+ git_commit_list *list = commits;
420
+ git_commit_list *newlist = NULL;
421
+ git_commit_list **p = &newlist;
422
+
423
+ while (list) {
424
+ git_commit_list_node *commit = git_commit_list_pop(&list);
425
+
426
+ if ((error = add_parents_to_list(walk, commit, &list)) < 0)
427
+ return error;
428
+
429
+ if (commit->uninteresting) {
430
+ mark_parents_uninteresting(commit);
431
+
432
+ slop = still_interesting(list, time, slop);
433
+ if (slop)
434
+ continue;
435
+
436
+ break;
437
+ }
438
+
439
+ if (!commit->uninteresting && walk->hide_cb && walk->hide_cb(&commit->oid, walk->hide_cb_payload))
440
+ continue;
418
441
 
419
- for (i = 0; i < git_pqueue_size(list); i++) {
420
- git_commit_list_node *commit = git_pqueue_get(list, i);
421
- if (commit == node)
422
- return 1;
442
+ time = commit->time;
443
+ p = &git_commit_list_insert(commit, p)->next;
423
444
  }
424
445
 
446
+ git_commit_list_free(&list);
447
+ *out = newlist;
425
448
  return 0;
426
449
  }
427
450
 
428
- static int premark_uninteresting(git_revwalk *walk)
451
+ static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, git_commit_list *list)
429
452
  {
430
- int error = 0;
453
+ git_commit_list *ll = NULL, *newlist, **pptr;
454
+ git_commit_list_node *next;
455
+ git_pqueue queue;
456
+ git_vector_cmp queue_cmp = NULL;
431
457
  unsigned short i;
432
- git_pqueue q;
433
- git_commit_list *list;
434
- git_commit_list_node *commit, *parent;
458
+ int error;
435
459
 
436
- if ((error = git_pqueue_init(&q, 0, 8, git_commit_list_time_cmp)) < 0)
437
- return error;
460
+ if (walk->sorting & GIT_SORT_TIME)
461
+ queue_cmp = git_commit_list_time_cmp;
438
462
 
439
- for (list = walk->user_input; list; list = list->next) {
440
- if ((error = git_commit_list_parse(walk, list->item)) < 0)
441
- goto cleanup;
463
+ if ((error = git_pqueue_init(&queue, 0, 8, queue_cmp)))
464
+ return error;
442
465
 
443
- if ((error = git_pqueue_insert(&q, list->item)) < 0)
444
- goto cleanup;
466
+ /*
467
+ * Start by resetting the in-degree to 1 for the commits in
468
+ * our list. We want to go through this list again, so we
469
+ * store it in the commit list as we extract it from the lower
470
+ * machinery.
471
+ */
472
+ for (ll = list; ll; ll = ll->next) {
473
+ ll->item->in_degree = 1;
445
474
  }
446
475
 
447
- while (interesting(&q)) {
448
- commit = git_pqueue_pop(&q);
449
-
450
- for (i = 0; i < commit->out_degree; i++) {
451
- parent = commit->parents[i];
476
+ /*
477
+ * Count up how many children each commit has. We limit
478
+ * ourselves to those commits in the original list (in-degree
479
+ * of 1) avoiding setting it for any parent that was hidden.
480
+ */
481
+ for(ll = list; ll; ll = ll->next) {
482
+ for (i = 0; i < ll->item->out_degree; ++i) {
483
+ git_commit_list_node *parent = ll->item->parents[i];
484
+ if (parent->in_degree)
485
+ parent->in_degree++;
486
+ }
487
+ }
452
488
 
453
- if ((error = git_commit_list_parse(walk, parent)) < 0)
489
+ /*
490
+ * Now we find the tips i.e. those not reachable from any other node
491
+ * i.e. those which still have an in-degree of 1.
492
+ */
493
+ for(ll = list; ll; ll = ll->next) {
494
+ if (ll->item->in_degree == 1) {
495
+ if ((error = git_pqueue_insert(&queue, ll->item)))
454
496
  goto cleanup;
497
+ }
498
+ }
499
+
500
+ /*
501
+ * We need to output the tips in the order that they came out of the
502
+ * traversal, so if we're not doing time-sorting, we need to reverse the
503
+ * pqueue in order to get them to come out as we inserted them.
504
+ */
505
+ if ((walk->sorting & GIT_SORT_TIME) == 0)
506
+ git_pqueue_reverse(&queue);
455
507
 
456
- if (commit->uninteresting)
457
- parent->uninteresting = 1;
458
508
 
459
- if (contains(&q, parent))
509
+ pptr = &newlist;
510
+ newlist = NULL;
511
+ while ((next = git_pqueue_pop(&queue)) != NULL) {
512
+ for (i = 0; i < next->out_degree; ++i) {
513
+ git_commit_list_node *parent = next->parents[i];
514
+ if (parent->in_degree == 0)
460
515
  continue;
461
516
 
462
- if ((error = git_pqueue_insert(&q, parent)) < 0)
463
- goto cleanup;
517
+ if (--parent->in_degree == 1) {
518
+ if ((error = git_pqueue_insert(&queue, parent)))
519
+ goto cleanup;
520
+ }
464
521
  }
522
+
523
+ /* All the children of 'item' have been emitted (since we got to it via the priority queue) */
524
+ next->in_degree = 0;
525
+
526
+ pptr = &git_commit_list_insert(next, pptr)->next;
465
527
  }
466
528
 
529
+ *out = newlist;
530
+ error = 0;
531
+
467
532
  cleanup:
468
- git_pqueue_free(&q);
533
+ git_pqueue_free(&queue);
469
534
  return error;
470
535
  }
471
536
 
472
537
  static int prepare_walk(git_revwalk *walk)
473
538
  {
474
539
  int error;
475
- git_commit_list *list;
540
+ git_commit_list *list, *commits = NULL;
476
541
  git_commit_list_node *next;
477
542
 
478
543
  /* If there were no pushes, we know that the walk is already over */
@@ -481,32 +546,42 @@ static int prepare_walk(git_revwalk *walk)
481
546
  return GIT_ITEROVER;
482
547
  }
483
548
 
484
- if (walk->did_hide && (error = premark_uninteresting(walk)) < 0)
485
- return error;
486
-
487
549
  for (list = walk->user_input; list; list = list->next) {
488
- if (process_commit(walk, list->item, list->item->uninteresting) < 0)
489
- return -1;
490
- }
550
+ git_commit_list_node *commit = list->item;
551
+ if ((error = git_commit_list_parse(walk, commit)) < 0)
552
+ return error;
491
553
 
554
+ if (commit->uninteresting)
555
+ mark_parents_uninteresting(commit);
492
556
 
493
- if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
494
- unsigned short i;
557
+ if (!commit->seen) {
558
+ commit->seen = 1;
559
+ git_commit_list_insert(commit, &commits);
560
+ }
561
+ }
495
562
 
496
- while ((error = walk->get_next(&next, walk)) == 0) {
497
- for (i = 0; i < next->out_degree; ++i) {
498
- git_commit_list_node *parent = next->parents[i];
499
- parent->in_degree++;
500
- }
563
+ if ((error = limit_list(&commits, walk, commits)) < 0)
564
+ return error;
501
565
 
502
- if (git_commit_list_insert(next, &walk->iterator_topo) == NULL)
503
- return -1;
504
- }
566
+ if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
567
+ error = sort_in_topological_order(&walk->iterator_topo, walk, commits);
568
+ git_commit_list_free(&commits);
505
569
 
506
- if (error != GIT_ITEROVER)
570
+ if (error < 0)
507
571
  return error;
508
572
 
509
573
  walk->get_next = &revwalk_next_toposort;
574
+ } else if (walk->sorting & GIT_SORT_TIME) {
575
+ for (list = commits; list && !error; list = list->next)
576
+ error = walk->enqueue(walk, list->item);
577
+
578
+ git_commit_list_free(&commits);
579
+
580
+ if (error < 0)
581
+ return error;
582
+ } else {
583
+ walk->iterator_rand = commits;
584
+ walk->get_next = revwalk_next_unsorted;
510
585
  }
511
586
 
512
587
  if (walk->sorting & GIT_SORT_REVERSE) {
@@ -632,6 +707,7 @@ void git_revwalk_reset(git_revwalk *walk)
632
707
  commit->in_degree = 0;
633
708
  commit->topo_delay = 0;
634
709
  commit->uninteresting = 0;
710
+ commit->added = 0;
635
711
  commit->flags = 0;
636
712
  });
637
713
 
@@ -23,7 +23,7 @@ void git_libgit2_version(int *major, int *minor, int *rev)
23
23
  *rev = LIBGIT2_VER_REVISION;
24
24
  }
25
25
 
26
- int git_libgit2_features()
26
+ int git_libgit2_features(void)
27
27
  {
28
28
  return 0
29
29
  #ifdef GIT_THREADS
@@ -73,12 +73,12 @@ static int config_level_to_sysdir(int config_level)
73
73
  extern char *git__user_agent;
74
74
  extern char *git__ssl_ciphers;
75
75
 
76
- const char *git_libgit2__user_agent()
76
+ const char *git_libgit2__user_agent(void)
77
77
  {
78
78
  return git__user_agent;
79
79
  }
80
80
 
81
- const char *git_libgit2__ssl_ciphers()
81
+ const char *git_libgit2__ssl_ciphers(void)
82
82
  {
83
83
  return git__ssl_ciphers;
84
84
  }
@@ -209,6 +209,14 @@ int git_libgit2_opts(int key, ...)
209
209
  #endif
210
210
  break;
211
211
 
212
+ case GIT_OPT_GET_USER_AGENT:
213
+ {
214
+ git_buf *out = va_arg(ap, git_buf *);
215
+ git_buf_sanitize(out);
216
+ error = git_buf_sets(out, git__user_agent);
217
+ }
218
+ break;
219
+
212
220
  default:
213
221
  giterr_set(GITERR_INVALID, "invalid option key");
214
222
  error = -1;
@@ -200,7 +200,8 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
200
200
 
201
201
  memset(sig, 0, sizeof(git_signature));
202
202
 
203
- if ((buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
203
+ if (ender &&
204
+ (buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
204
205
  return signature_error("no newline given");
205
206
 
206
207
  if (header) {
@@ -250,7 +251,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
250
251
  * only store timezone if it's not overflowing;
251
252
  * see http://www.worldtimezone.com/faq.html
252
253
  */
253
- if (hours < 14 && mins < 59) {
254
+ if (hours <= 14 && mins <= 59) {
254
255
  sig->when.offset = (hours * 60) + mins;
255
256
  if (tz_start[0] == '-')
256
257
  sig->when.offset = -sig->when.offset;
@@ -262,6 +263,30 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
262
263
  return 0;
263
264
  }
264
265
 
266
+ int git_signature_from_buffer(git_signature **out, const char *buf)
267
+ {
268
+ git_signature *sig;
269
+ const char *buf_end;
270
+ int error;
271
+
272
+ assert(out && buf);
273
+
274
+ *out = NULL;
275
+
276
+ sig = git__calloc(1, sizeof(git_signature));
277
+ GITERR_CHECK_ALLOC(sig);
278
+
279
+ buf_end = buf + strlen(buf);
280
+ error = git_signature__parse(sig, &buf, buf_end, NULL, '\0');
281
+
282
+ if (error)
283
+ git__free(sig);
284
+ else
285
+ *out = sig;
286
+
287
+ return error;
288
+ }
289
+
265
290
  void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig)
266
291
  {
267
292
  int offset, hours, mins;
@@ -200,6 +200,7 @@ void git_sortedcache_runlock(git_sortedcache *sc)
200
200
  int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
201
201
  {
202
202
  int error, fd;
203
+ struct stat st;
203
204
 
204
205
  if ((error = git_sortedcache_wlock(sc)) < 0)
205
206
  return error;
@@ -207,19 +208,27 @@ int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
207
208
  if ((error = git_futils_filestamp_check(&sc->stamp, sc->path)) <= 0)
208
209
  goto unlock;
209
210
 
210
- if (!git__is_sizet(sc->stamp.size)) {
211
- giterr_set(GITERR_INVALID, "Unable to load file larger than size_t");
211
+ if ((fd = git_futils_open_ro(sc->path)) < 0) {
212
+ error = fd;
213
+ goto unlock;
214
+ }
215
+
216
+ if (p_fstat(fd, &st) < 0) {
217
+ giterr_set(GITERR_OS, "failed to stat file");
212
218
  error = -1;
219
+ (void)p_close(fd);
213
220
  goto unlock;
214
221
  }
215
222
 
216
- if ((fd = git_futils_open_ro(sc->path)) < 0) {
217
- error = fd;
223
+ if (!git__is_sizet(st.st_size)) {
224
+ giterr_set(GITERR_INVALID, "Unable to load file larger than size_t");
225
+ error = -1;
226
+ (void)p_close(fd);
218
227
  goto unlock;
219
228
  }
220
229
 
221
230
  if (buf)
222
- error = git_futils_readbuffer_fd(buf, fd, (size_t)sc->stamp.size);
231
+ error = git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size);
223
232
 
224
233
  (void)p_close(fd);
225
234
 
@@ -23,6 +23,7 @@
23
23
  #include "iterator.h"
24
24
  #include "merge.h"
25
25
  #include "diff.h"
26
+ #include "diff_generate.h"
26
27
 
27
28
  static int create_error(int error, const char *msg)
28
29
  {