Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "revwalk.h"
9 -
10 - #include "commit.h"
11 - #include "odb.h"
12 - #include "pool.h"
13 -
14 - #include "git2/revparse.h"
15 - #include "merge.h"
16 - #include "vector.h"
17 -
18 - static int get_revision(git_commit_list_node **out, git_revwalk *walk, git_commit_list **list);
19 -
20 5211 2 git_commit_list_node *git_revwalk__commit_lookup(
21 - git_revwalk *walk, const git_oid *oid)
22 - {
23 - git_commit_list_node *commit;
24 -
25 - /* lookup and reserve space if not already present */
26 5211 2,3 if ((commit = git_oidmap_get(walk->commits, oid)) != NULL)
27 1459 4 return commit;
28 -
29 3752 5 commit = git_commit_list_alloc_node(walk);
30 3752 6 if (commit == NULL)
31 ##### 7 return NULL;
32 -
33 3752 8 git_oid_cpy(&commit->oid, oid);
34 -
35 3752 9,10 if ((git_oidmap_set(walk->commits, &commit->oid, commit)) < 0)
36 ##### 11 return NULL;
37 -
38 3752 12 return commit;
39 - }
40 -
41 1073 2 int git_revwalk__push_commit(git_revwalk *walk, const git_oid *oid, const git_revwalk__push_options *opts)
42 - {
43 - git_oid commit_id;
44 - int error;
45 - git_object *obj, *oobj;
46 - git_commit_list_node *commit;
47 - git_commit_list *list;
48 -
49 1073 2,3 if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJECT_ANY)) < 0)
50 45 4 return error;
51 -
52 1028 5 error = git_object_peel(&obj, oobj, GIT_OBJECT_COMMIT);
53 1028 6 git_object_free(oobj);
54 -
55 1028 7-9 if (error == GIT_ENOTFOUND || error == GIT_EINVALIDSPEC || error == GIT_EPEEL) {
56 - /* If this comes from e.g. push_glob("tags"), ignore this */
57 18 10 if (opts->from_glob)
58 17 11 return 0;
59 -
60 1 12 git_error_set(GIT_ERROR_INVALID, "object is not a committish");
61 1 13 return error;
62 - }
63 1010 14 if (error < 0)
64 ##### 15 return error;
65 -
66 1010 16,17 git_oid_cpy(&commit_id, git_object_id(obj));
67 1010 18 git_object_free(obj);
68 -
69 1010 19 commit = git_revwalk__commit_lookup(walk, &commit_id);
70 1010 20 if (commit == NULL)
71 ##### 21 return -1; /* error already reported by failed lookup */
72 -
73 - /* A previous hide already told us we don't want this commit */
74 1010 22 if (commit->uninteresting)
75 1 23 return 0;
76 -
77 1009 24 if (opts->uninteresting) {
78 62 25 walk->limited = 1;
79 62 25 walk->did_hide = 1;
80 - } else {
81 947 26 walk->did_push = 1;
82 - }
83 -
84 1009 27 commit->uninteresting = opts->uninteresting;
85 1009 27 list = walk->user_input;
86 1009 27,29 if ((opts->insert_by_date &&
87 1009 28,31 git_commit_list_insert_by_date(commit, &list) == NULL) ||
88 1009 30 git_commit_list_insert(commit, &list) == NULL) {
89 ##### 32 git_error_set_oom();
90 ##### 33 return -1;
91 - }
92 -
93 1009 34 walk->user_input = list;
94 -
95 1009 34 return 0;
96 - }
97 -
98 804 2 int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
99 - {
100 804 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
101 -
102 804 2-4 assert(walk && oid);
103 -
104 804 5 return git_revwalk__push_commit(walk, oid, &opts);
105 - }
106 -
107 -
108 99 2 int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
109 - {
110 99 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
111 99 2-4 assert(walk && oid);
112 -
113 99 5 opts.uninteresting = 1;
114 99 5 return git_revwalk__push_commit(walk, oid, &opts);
115 - }
116 -
117 168 2 int git_revwalk__push_ref(git_revwalk *walk, const char *refname, const git_revwalk__push_options *opts)
118 - {
119 - git_oid oid;
120 -
121 168 2,3 if (git_reference_name_to_id(&oid, walk->repo, refname) < 0)
122 ##### 4 return -1;
123 -
124 168 5 return git_revwalk__push_commit(walk, &oid, opts);
125 - }
126 -
127 44 2 int git_revwalk__push_glob(git_revwalk *walk, const char *glob, const git_revwalk__push_options *given_opts)
128 - {
129 44 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
130 44 2 int error = 0;
131 44 2 git_buf buf = GIT_BUF_INIT;
132 - git_reference *ref;
133 - git_reference_iterator *iter;
134 - size_t wildcard;
135 -
136 44 2-4 assert(walk && glob);
137 -
138 44 5 if (given_opts)
139 44 6 memcpy(&opts, given_opts, sizeof(opts));
140 -
141 - /* refs/ is implied if not given in the glob */
142 44 7,8 if (git__prefixcmp(glob, GIT_REFS_DIR) != 0)
143 4 9 git_buf_joinpath(&buf, GIT_REFS_DIR, glob);
144 - else
145 40 10 git_buf_puts(&buf, glob);
146 44 11-13 GIT_ERROR_CHECK_ALLOC_BUF(&buf);
147 -
148 - /* If no '?', '*' or '[' exist, we append '/ *' to the glob */
149 44 14 wildcard = strcspn(glob, "?*[");
150 44 14 if (!glob[wildcard])
151 3 15 git_buf_put(&buf, "/*", 2);
152 -
153 44 16,17 if ((error = git_reference_iterator_glob_new(&iter, walk->repo, buf.ptr)) < 0)
154 ##### 18 goto out;
155 -
156 44 19 opts.from_glob = true;
157 185 19,25,26 while ((error = git_reference_next(&ref, iter)) == 0) {
158 141 20,21 error = git_revwalk__push_ref(walk, git_reference_name(ref), &opts);
159 141 22 git_reference_free(ref);
160 141 23 if (error < 0)
161 ##### 24 break;
162 - }
163 44 27 git_reference_iterator_free(iter);
164 -
165 44 28 if (error == GIT_ITEROVER)
166 44 29 error = 0;
167 - out:
168 44 30 git_buf_dispose(&buf);
169 44 31 return error;
170 - }
171 -
172 8 2 int git_revwalk_push_glob(git_revwalk *walk, const char *glob)
173 - {
174 8 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
175 8 2-4 assert(walk && glob);
176 -
177 8 5 return git_revwalk__push_glob(walk, glob, &opts);
178 - }
179 -
180 ##### 2 int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
181 - {
182 ##### 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
183 ##### 2-4 assert(walk && glob);
184 -
185 ##### 5 opts.uninteresting = 1;
186 ##### 5 return git_revwalk__push_glob(walk, glob, &opts);
187 - }
188 -
189 6 2 int git_revwalk_push_head(git_revwalk *walk)
190 - {
191 6 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
192 6 2,3 assert(walk);
193 -
194 6 4 return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
195 - }
196 -
197 ##### 2 int git_revwalk_hide_head(git_revwalk *walk)
198 - {
199 ##### 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
200 ##### 2,3 assert(walk);
201 -
202 ##### 4 opts.uninteresting = 1;
203 ##### 4 return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
204 - }
205 -
206 14 2 int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
207 - {
208 14 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
209 14 2-4 assert(walk && refname);
210 -
211 14 5 return git_revwalk__push_ref(walk, refname, &opts);
212 - }
213 -
214 3 2 int git_revwalk_push_range(git_revwalk *walk, const char *range)
215 - {
216 3 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
217 - git_revspec revspec;
218 3 2 int error = 0;
219 -
220 3 2,3 if ((error = git_revparse(&revspec, walk->repo, range)))
221 ##### 4 return error;
222 -
223 3 5 if (!revspec.to) {
224 1 6 git_error_set(GIT_ERROR_INVALID, "invalid revspec: range not provided");
225 1 7 error = GIT_EINVALIDSPEC;
226 1 7 goto out;
227 - }
228 -
229 2 8 if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
230 - /* TODO: support "<commit>...<commit>" */
231 1 9 git_error_set(GIT_ERROR_INVALID, "symmetric differences not implemented in revwalk");
232 1 10 error = GIT_EINVALIDSPEC;
233 1 10 goto out;
234 - }
235 -
236 1 11 opts.uninteresting = 1;
237 1 11-13 if ((error = git_revwalk__push_commit(walk, git_object_id(revspec.from), &opts)))
238 ##### 14 goto out;
239 -
240 1 15 opts.uninteresting = 0;
241 1 15,16 error = git_revwalk__push_commit(walk, git_object_id(revspec.to), &opts);
242 -
243 - out:
244 3 17 git_object_free(revspec.from);
245 3 18 git_object_free(revspec.to);
246 3 19 return error;
247 - }
248 -
249 7 2 int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
250 - {
251 7 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
252 7 2-4 assert(walk && refname);
253 7 5 opts.uninteresting = 1;
254 7 5 return git_revwalk__push_ref(walk, refname, &opts);
255 - }
256 -
257 788 2 static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit)
258 - {
259 788 2 return git_pqueue_insert(&walk->iterator_time, commit);
260 - }
261 -
262 ##### 2 static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *commit)
263 - {
264 ##### 2 return git_commit_list_insert(commit, &walk->iterator_rand) ? 0 : -1;
265 - }
266 -
267 817 2 static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk)
268 - {
269 - git_commit_list_node *next;
270 -
271 818 2,5,6 while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {
272 - /* Some commits might become uninteresting after being added to the list */
273 757 3 if (!next->uninteresting) {
274 756 4 *object_out = next;
275 756 4 return 0;
276 - }
277 - }
278 -
279 61 7 git_error_clear();
280 61 8 return GIT_ITEROVER;
281 - }
282 -
283 364 2 static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk *walk)
284 - {
285 - int error;
286 - git_commit_list_node *next;
287 -
288 367 2,5,6 while (!(error = get_revision(&next, walk, &walk->iterator_rand))) {
289 - /* Some commits might become uninteresting after being added to the list */
290 300 3 if (!next->uninteresting) {
291 297 4 *object_out = next;
292 297 4 return 0;
293 - }
294 - }
295 -
296 67 7 return error;
297 - }
298 -
299 30 2 static int revwalk_next_toposort(git_commit_list_node **object_out, git_revwalk *walk)
300 - {
301 - int error;
302 - git_commit_list_node *next;
303 -
304 30 2,5,6 while (!(error = get_revision(&next, walk, &walk->iterator_topo))) {
305 - /* Some commits might become uninteresting after being added to the list */
306 24 3 if (!next->uninteresting) {
307 24 4 *object_out = next;
308 24 4 return 0;
309 - }
310 - }
311 -
312 6 7 return error;
313 - }
314 -
315 241 2 static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
316 - {
317 241 2 *object_out = git_commit_list_pop(&walk->iterator_reverse);
318 241 3 return *object_out ? 0 : GIT_ITEROVER;
319 - }
320 -
321 683 2 static void mark_parents_uninteresting(git_commit_list_node *commit)
322 - {
323 - unsigned short i;
324 683 2 git_commit_list *parents = NULL;
325 -
326 1271 2,4,5 for (i = 0; i < commit->out_degree; i++)
327 588 3 git_commit_list_insert(commit->parents[i], &parents);
328 -
329 -
330 1291 6,19 while (parents) {
331 608 7 commit = git_commit_list_pop(&parents);
332 -
333 657 8,18 while (commit) {
334 627 9 if (commit->uninteresting)
335 349 10 break;
336 -
337 278 11 commit->uninteresting = 1;
338 - /*
339 - * If we've reached this commit some other way
340 - * already, we need to mark its parents uninteresting
341 - * as well.
342 - */
343 278 11 if (!commit->parents)
344 229 12 break;
345 -
346 69 13,15,16 for (i = 0; i < commit->out_degree; i++)
347 20 14 git_commit_list_insert(commit->parents[i], &parents);
348 49 17 commit = commit->parents[0];
349 - }
350 - }
351 683 20 }
352 -
353 1455 2 static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, git_commit_list **list)
354 - {
355 - unsigned short i;
356 - int error;
357 -
358 1455 2 if (commit->added)
359 37 3 return 0;
360 -
361 1418 4 commit->added = 1;
362 -
363 - /*
364 - * Go full on in the uninteresting case as we want to include
365 - * as many of these as we can.
366 - *
367 - * Usually we haven't parsed the parent of a parent, but if we
368 - * have it we reached it via other means so we want to mark
369 - * its parents recursively too.
370 - */
371 1418 4 if (commit->uninteresting) {
372 584 5,12,13 for (i = 0; i < commit->out_degree; i++) {
373 280 6 git_commit_list_node *p = commit->parents[i];
374 280 6 p->uninteresting = 1;
375 -
376 - /* git does it gently here, but we don't like missing objects */
377 280 6,7 if ((error = git_commit_list_parse(walk, p)) < 0)
378 ##### 8 return error;
379 -
380 280 9 if (p->parents)
381 280 10 mark_parents_uninteresting(p);
382 -
383 280 11 p->seen = 1;
384 280 11 git_commit_list_insert_by_date(p, list);
385 - }
386 -
387 304 14 return 0;
388 - }
389 -
390 - /*
391 - * Now on to what we do if the commit is indeed
392 - * interesting. Here we do want things like first-parent take
393 - * effect as this is what we'll be showing.
394 - */
395 2147 15,27,28 for (i = 0; i < commit->out_degree; i++) {
396 1036 16 git_commit_list_node *p = commit->parents[i];
397 -
398 1036 16,17 if ((error = git_commit_list_parse(walk, p)) < 0)
399 ##### 18 return error;
400 -
401 1036 19-21 if (walk->hide_cb && walk->hide_cb(&p->oid, walk->hide_cb_payload))
402 8 22 continue;
403 -
404 1028 23 if (!p->seen) {
405 633 24 p->seen = 1;
406 633 24 git_commit_list_insert_by_date(p, list);
407 - }
408 -
409 1028 25 if (walk->first_parent)
410 3 26 break;
411 - }
412 1114 29 return 0;
413 - }
414 -
415 - /* How many unintersting commits we want to look at after we run out of interesting ones */
416 - #define SLOP 5
417 -
418 341 2 static int still_interesting(git_commit_list *list, int64_t time, int slop)
419 - {
420 - /* The empty list is pretty boring */
421 341 2 if (!list)
422 38 3 return 0;
423 -
424 - /*
425 - * If the destination list has commits with an earlier date than our
426 - * source, we want to reset the slop counter as we're not done.
427 - */
428 303 4 if (time <= list->item->time)
429 10 5 return SLOP;
430 -
431 785 6,10,11 for (; list; list = list->next) {
432 - /*
433 - * If the destination list still contains interesting commits we
434 - * want to continue looking.
435 - */
436 588 7,8 if (!list->item->uninteresting || list->item->time > time)
437 96 9 return SLOP;
438 - }
439 -
440 - /* Everything's uninteresting, reduce the count */
441 197 12 return slop - 1;
442 - }
443 -
444 134 2 static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits)
445 - {
446 134 2 int error, slop = SLOP;
447 134 2 int64_t time = INT64_MAX;
448 134 2 git_commit_list *list = commits;
449 134 2 git_commit_list *newlist = NULL;
450 134 2 git_commit_list **p = &newlist;
451 -
452 1451 2,19 while (list) {
453 1374 3 git_commit_list_node *commit = git_commit_list_pop(&list);
454 -
455 1374 4,5 if ((error = add_parents_to_list(walk, commit, &list)) < 0)
456 ##### 6 return error;
457 -
458 1374 7 if (commit->uninteresting) {
459 341 8 mark_parents_uninteresting(commit);
460 -
461 341 9 slop = still_interesting(list, time, slop);
462 341 10 if (slop)
463 284 11 continue;
464 -
465 57 12 break;
466 - }
467 -
468 1033 13-15 if (walk->hide_cb && walk->hide_cb(&commit->oid, walk->hide_cb_payload))
469 2 16 continue;
470 -
471 1031 17 time = commit->time;
472 1031 17,18 p = &git_commit_list_insert(commit, p)->next;
473 - }
474 -
475 134 20 git_commit_list_free(&list);
476 134 21 *out = newlist;
477 134 21 return 0;
478 - }
479 -
480 397 2 static int get_revision(git_commit_list_node **out, git_revwalk *walk, git_commit_list **list)
481 - {
482 - int error;
483 - git_commit_list_node *commit;
484 -
485 397 2 commit = git_commit_list_pop(list);
486 397 3 if (!commit) {
487 73 4 git_error_clear();
488 73 5 return GIT_ITEROVER;
489 - }
490 -
491 - /*
492 - * If we did not run limit_list and we must add parents to the
493 - * list ourselves.
494 - */
495 324 6 if (!walk->limited) {
496 81 7,8 if ((error = add_parents_to_list(walk, commit, list)) < 0)
497 ##### 9 return error;
498 - }
499 -
500 324 10 *out = commit;
501 324 10 return 0;
502 - }
503 -
504 6 2 static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, git_commit_list *list)
505 - {
506 6 2 git_commit_list *ll = NULL, *newlist, **pptr;
507 - git_commit_list_node *next;
508 - git_pqueue queue;
509 6 2 git_vector_cmp queue_cmp = NULL;
510 - unsigned short i;
511 - int error;
512 -
513 6 2 if (walk->sorting & GIT_SORT_TIME)
514 ##### 3 queue_cmp = git_commit_list_time_cmp;
515 -
516 6 4,5 if ((error = git_pqueue_init(&queue, 0, 8, queue_cmp)))
517 ##### 6 return error;
518 -
519 - /*
520 - * Start by resetting the in-degree to 1 for the commits in
521 - * our list. We want to go through this list again, so we
522 - * store it in the commit list as we extract it from the lower
523 - * machinery.
524 - */
525 30 7-9 for (ll = list; ll; ll = ll->next) {
526 24 8 ll->item->in_degree = 1;
527 - }
528 -
529 - /*
530 - * Count up how many children each commit has. We limit
531 - * ourselves to those commits in the original list (in-degree
532 - * of 1) avoiding setting it for any parent that was hidden.
533 - */
534 30 10,16,17 for(ll = list; ll; ll = ll->next) {
535 50 11,14,15 for (i = 0; i < ll->item->out_degree; ++i) {
536 26 12 git_commit_list_node *parent = ll->item->parents[i];
537 26 12 if (parent->in_degree)
538 21 13 parent->in_degree++;
539 - }
540 - }
541 -
542 - /*
543 - * Now we find the tips i.e. those not reachable from any other node
544 - * i.e. those which still have an in-degree of 1.
545 - */
546 30 18,23,24 for(ll = list; ll; ll = ll->next) {
547 24 19 if (ll->item->in_degree == 1) {
548 5 20,21 if ((error = git_pqueue_insert(&queue, ll->item)))
549 ##### 22 goto cleanup;
550 - }
551 - }
552 -
553 - /*
554 - * We need to output the tips in the order that they came out of the
555 - * traversal, so if we're not doing time-sorting, we need to reverse the
556 - * pqueue in order to get them to come out as we inserted them.
557 - */
558 6 25 if ((walk->sorting & GIT_SORT_TIME) == 0)
559 6 26 git_pqueue_reverse(&queue);
560 -
561 -
562 6 27 pptr = &newlist;
563 6 27 newlist = NULL;
564 30 27,39,40 while ((next = git_pqueue_pop(&queue)) != NULL) {
565 50 28,35,36 for (i = 0; i < next->out_degree; ++i) {
566 26 29 git_commit_list_node *parent = next->parents[i];
567 26 29 if (parent->in_degree == 0)
568 5 30 continue;
569 -
570 21 31 if (--parent->in_degree == 1) {
571 19 32,33 if ((error = git_pqueue_insert(&queue, parent)))
572 ##### 34 goto cleanup;
573 - }
574 - }
575 -
576 - /* All the children of 'item' have been emitted (since we got to it via the priority queue) */
577 24 37 next->in_degree = 0;
578 -
579 24 37,38 pptr = &git_commit_list_insert(next, pptr)->next;
580 - }
581 -
582 6 41 *out = newlist;
583 6 41 error = 0;
584 -
585 - cleanup:
586 6 42 git_pqueue_free(&queue);
587 6 43 return error;
588 - }
589 -
590 183 2 static int prepare_walk(git_revwalk *walk)
591 - {
592 183 2 int error = 0;
593 183 2 git_commit_list *list, *commits = NULL;
594 - git_commit_list_node *next;
595 -
596 - /* If there were no pushes, we know that the walk is already over */
597 183 2 if (!walk->did_push) {
598 40 3 git_error_clear();
599 40 4 return GIT_ITEROVER;
600 - }
601 -
602 1150 5,13,14 for (list = walk->user_input; list; list = list->next) {
603 1007 6 git_commit_list_node *commit = list->item;
604 1007 6,7 if ((error = git_commit_list_parse(walk, commit)) < 0)
605 ##### 8 return error;
606 -
607 1007 9 if (commit->uninteresting)
608 62 10 mark_parents_uninteresting(commit);
609 -
610 1007 11 if (!commit->seen) {
611 594 12 commit->seen = 1;
612 594 12 git_commit_list_insert(commit, &commits);
613 - }
614 - }
615 -
616 143 15-17 if (walk->limited && (error = limit_list(&commits, walk, commits)) < 0)
617 ##### 18 return error;
618 -
619 143 19 if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
620 6 20 error = sort_in_topological_order(&walk->iterator_topo, walk, commits);
621 6 21 git_commit_list_free(&commits);
622 -
623 6 22 if (error < 0)
624 ##### 23 return error;
625 -
626 6 24 walk->get_next = &revwalk_next_toposort;
627 137 25 } else if (walk->sorting & GIT_SORT_TIME) {
628 856 26,28-30 for (list = commits; list && !error; list = list->next)
629 788 27 error = walk->enqueue(walk, list->item);
630 -
631 68 31 git_commit_list_free(&commits);
632 -
633 68 32 if (error < 0)
634 ##### 33 return error;
635 - } else {
636 69 34 walk->iterator_rand = commits;
637 69 34 walk->get_next = revwalk_next_unsorted;
638 - }
639 -
640 143 35 if (walk->sorting & GIT_SORT_REVERSE) {
641 -
642 241 36,40,41 while ((error = walk->get_next(&next, walk)) == 0)
643 191 37,38 if (git_commit_list_insert(next, &walk->iterator_reverse) == NULL)
644 ##### 39 return -1;
645 -
646 50 42 if (error != GIT_ITEROVER)
647 ##### 43 return error;
648 -
649 50 44 walk->get_next = &revwalk_next_reverse;
650 - }
651 -
652 143 45 walk->walking = 1;
653 143 45 return 0;
654 - }
655 -
656 -
657 479 2 int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
658 - {
659 479 2 git_revwalk *walk = git__calloc(1, sizeof(git_revwalk));
660 479 3,4 GIT_ERROR_CHECK_ALLOC(walk);
661 -
662 479 5,6,8 if (git_oidmap_new(&walk->commits) < 0 ||
663 479 7,10 git_pqueue_init(&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 ||
664 479 9 git_pool_init(&walk->commit_pool, COMMIT_ALLOC) < 0)
665 ##### 11 return -1;
666 -
667 479 12 walk->get_next = &revwalk_next_unsorted;
668 479 12 walk->enqueue = &revwalk_enqueue_unsorted;
669 -
670 479 12 walk->repo = repo;
671 -
672 479 12,13 if (git_repository_odb(&walk->odb, repo) < 0) {
673 ##### 14 git_revwalk_free(walk);
674 ##### 15 return -1;
675 - }
676 -
677 479 16 *revwalk_out = walk;
678 479 16 return 0;
679 - }
680 -
681 487 2 void git_revwalk_free(git_revwalk *walk)
682 - {
683 487 2 if (walk == NULL)
684 487 3,10 return;
685 -
686 479 4 git_revwalk_reset(walk);
687 479 5 git_odb_free(walk->odb);
688 -
689 479 6 git_oidmap_free(walk->commits);
690 479 7 git_pool_clear(&walk->commit_pool);
691 479 8 git_pqueue_free(&walk->iterator_time);
692 479 9 git__free(walk);
693 - }
694 -
695 70 2 git_repository *git_revwalk_repository(git_revwalk *walk)
696 - {
697 70 2,3 assert(walk);
698 70 4 return walk->repo;
699 - }
700 -
701 129 2 int git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
702 - {
703 129 2,3 assert(walk);
704 -
705 129 4 if (walk->walking)
706 ##### 5 git_revwalk_reset(walk);
707 -
708 129 6 walk->sorting = sort_mode;
709 -
710 129 6 if (walk->sorting & GIT_SORT_TIME) {
711 70 7 walk->get_next = &revwalk_next_timesort;
712 70 7 walk->enqueue = &revwalk_enqueue_timesort;
713 - } else {
714 59 8 walk->get_next = &revwalk_next_unsorted;
715 59 8 walk->enqueue = &revwalk_enqueue_unsorted;
716 - }
717 -
718 129 9 if (walk->sorting != GIT_SORT_NONE)
719 124 10 walk->limited = 1;
720 -
721 129 11 return 0;
722 - }
723 -
724 1 2 int git_revwalk_simplify_first_parent(git_revwalk *walk)
725 - {
726 1 2 walk->first_parent = 1;
727 1 2 return 0;
728 - }
729 -
730 1251 2 int git_revwalk_next(git_oid *oid, git_revwalk *walk)
731 - {
732 - int error;
733 - git_commit_list_node *next;
734 -
735 1251 2-4 assert(walk && oid);
736 -
737 1251 5 if (!walk->walking) {
738 183 6,7 if ((error = prepare_walk(walk)) < 0)
739 40 8 return error;
740 - }
741 -
742 1211 9 error = walk->get_next(&next, walk);
743 -
744 1211 10 if (error == GIT_ITEROVER) {
745 134 11 git_revwalk_reset(walk);
746 134 12 git_error_clear();
747 134 13 return GIT_ITEROVER;
748 - }
749 -
750 1077 14 if (!error)
751 1077 15 git_oid_cpy(oid, &next->oid);
752 -
753 1077 16 return error;
754 - }
755 -
756 620 2 int git_revwalk_reset(git_revwalk *walk)
757 - {
758 - git_commit_list_node *commit;
759 -
760 620 2,3 assert(walk);
761 -
762 5773 4-7 git_oidmap_foreach_value(walk->commits, commit, {
763 - commit->seen = 0;
764 - commit->in_degree = 0;
765 - commit->topo_delay = 0;
766 - commit->uninteresting = 0;
767 - commit->added = 0;
768 - commit->flags = 0;
769 - });
770 -
771 620 8 git_pqueue_clear(&walk->iterator_time);
772 620 9 git_commit_list_free(&walk->iterator_topo);
773 620 10 git_commit_list_free(&walk->iterator_rand);
774 620 11 git_commit_list_free(&walk->iterator_reverse);
775 620 12 git_commit_list_free(&walk->user_input);
776 620 13 walk->first_parent = 0;
777 620 13 walk->walking = 0;
778 620 13 walk->limited = 0;
779 620 13 walk->did_push = walk->did_hide = 0;
780 620 13 walk->sorting = GIT_SORT_NONE;
781 -
782 620 13 return 0;
783 - }
784 -
785 9 2 int git_revwalk_add_hide_cb(
786 - git_revwalk *walk,
787 - git_revwalk_hide_cb hide_cb,
788 - void *payload)
789 - {
790 9 2,3 assert(walk);
791 -
792 9 4 if (walk->walking)
793 1 5 git_revwalk_reset(walk);
794 -
795 9 6 walk->hide_cb = hide_cb;
796 9 6 walk->hide_cb_payload = payload;
797 -
798 9 6 if (hide_cb)
799 8 7 walk->limited = 1;
800 -
801 9 8 return 0;
802 - }
803 -