File Coverage

deps/libgit2/src/revwalk.c
Criterion Covered Total %
statement 338 397 85.1
branch 180 268 67.1
condition n/a
subroutine n/a
pod n/a
total 518 665 77.8


line stmt bran cond sub pod time code
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 272           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 272 100         if ((commit = git_oidmap_get(walk->commits, oid)) != NULL)
27 92           return commit;
28              
29 180           commit = git_commit_list_alloc_node(walk);
30 180 50         if (commit == NULL)
31 0           return NULL;
32              
33 180           git_oid_cpy(&commit->oid, oid);
34              
35 180 50         if ((git_oidmap_set(walk->commits, &commit->oid, commit)) < 0)
36 0           return NULL;
37              
38 180           return commit;
39             }
40              
41 37           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 37 50         if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJECT_ANY)) < 0)
50 0           return error;
51              
52 37           error = git_object_peel(&obj, oobj, GIT_OBJECT_COMMIT);
53 37           git_object_free(oobj);
54              
55 37 50         if (error == GIT_ENOTFOUND || error == GIT_EINVALIDSPEC || error == GIT_EPEEL) {
    50          
    50          
56             /* If this comes from e.g. push_glob("tags"), ignore this */
57 0 0         if (opts->from_glob)
58 0           return 0;
59              
60 0           git_error_set(GIT_ERROR_INVALID, "object is not a committish");
61 0           return error;
62             }
63 37 50         if (error < 0)
64 0           return error;
65              
66 37           git_oid_cpy(&commit_id, git_object_id(obj));
67 37           git_object_free(obj);
68              
69 37           commit = git_revwalk__commit_lookup(walk, &commit_id);
70 37 50         if (commit == NULL)
71 0           return -1; /* error already reported by failed lookup */
72              
73             /* A previous hide already told us we don't want this commit */
74 37 50         if (commit->uninteresting)
75 0           return 0;
76              
77 37 100         if (opts->uninteresting) {
78 10           walk->limited = 1;
79 10           walk->did_hide = 1;
80             } else {
81 27           walk->did_push = 1;
82             }
83              
84 37           commit->uninteresting = opts->uninteresting;
85 37           list = walk->user_input;
86 37           if ((opts->insert_by_date &&
87 37 50         git_commit_list_insert_by_date(commit, &list) == NULL) ||
88 37           git_commit_list_insert(commit, &list) == NULL) {
89 0           git_error_set_oom();
90 0           return -1;
91             }
92              
93 37           walk->user_input = list;
94              
95 37           return 0;
96             }
97              
98 15           int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
99             {
100 15           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
101              
102 15 50         assert(walk && oid);
    50          
103              
104 15           return git_revwalk__push_commit(walk, oid, &opts);
105             }
106              
107              
108 4           int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
109             {
110 4           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
111 4 50         assert(walk && oid);
    50          
112              
113 4           opts.uninteresting = 1;
114 4           return git_revwalk__push_commit(walk, oid, &opts);
115             }
116              
117 12           int git_revwalk__push_ref(git_revwalk *walk, const char *refname, const git_revwalk__push_options *opts)
118             {
119             git_oid oid;
120              
121 12 50         if (git_reference_name_to_id(&oid, walk->repo, refname) < 0)
122 0           return -1;
123              
124 12           return git_revwalk__push_commit(walk, &oid, opts);
125             }
126              
127 2           int git_revwalk__push_glob(git_revwalk *walk, const char *glob, const git_revwalk__push_options *given_opts)
128             {
129 2           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
130 2           int error = 0;
131 2           git_buf buf = GIT_BUF_INIT;
132             git_reference *ref;
133             git_reference_iterator *iter;
134             size_t wildcard;
135              
136 2 50         assert(walk && glob);
    50          
137              
138 2 50         if (given_opts)
139 2           memcpy(&opts, given_opts, sizeof(opts));
140              
141             /* refs/ is implied if not given in the glob */
142 2 100         if (git__prefixcmp(glob, GIT_REFS_DIR) != 0)
143 1           git_buf_joinpath(&buf, GIT_REFS_DIR, glob);
144             else
145 1           git_buf_puts(&buf, glob);
146 2 50         GIT_ERROR_CHECK_ALLOC_BUF(&buf);
147              
148             /* If no '?', '*' or '[' exist, we append '/ *' to the glob */
149 2           wildcard = strcspn(glob, "?*[");
150 2 100         if (!glob[wildcard])
151 1           git_buf_put(&buf, "/*", 2);
152              
153 2 50         if ((error = git_reference_iterator_glob_new(&iter, walk->repo, buf.ptr)) < 0)
154 0           goto out;
155              
156 2           opts.from_glob = true;
157 3 100         while ((error = git_reference_next(&ref, iter)) == 0) {
158 1           error = git_revwalk__push_ref(walk, git_reference_name(ref), &opts);
159 1           git_reference_free(ref);
160 1 50         if (error < 0)
161 0           break;
162             }
163 2           git_reference_iterator_free(iter);
164              
165 2 50         if (error == GIT_ITEROVER)
166 2           error = 0;
167             out:
168 2           git_buf_dispose(&buf);
169 2           return error;
170             }
171              
172 1           int git_revwalk_push_glob(git_revwalk *walk, const char *glob)
173             {
174 1           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
175 1 50         assert(walk && glob);
    50          
176              
177 1           return git_revwalk__push_glob(walk, glob, &opts);
178             }
179              
180 1           int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
181             {
182 1           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
183 1 50         assert(walk && glob);
    50          
184              
185 1           opts.uninteresting = 1;
186 1           return git_revwalk__push_glob(walk, glob, &opts);
187             }
188              
189 7           int git_revwalk_push_head(git_revwalk *walk)
190             {
191 7           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
192 7 50         assert(walk);
193              
194 7           return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
195             }
196              
197 1           int git_revwalk_hide_head(git_revwalk *walk)
198             {
199 1           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
200 1 50         assert(walk);
201              
202 1           opts.uninteresting = 1;
203 1           return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
204             }
205              
206 1           int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
207             {
208 1           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
209 1 50         assert(walk && refname);
    50          
210              
211 1           return git_revwalk__push_ref(walk, refname, &opts);
212             }
213              
214 5           int git_revwalk_push_range(git_revwalk *walk, const char *range)
215             {
216 5           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
217             git_revspec revspec;
218 5           int error = 0;
219              
220 5 100         if ((error = git_revparse(&revspec, walk->repo, range)))
221 1           return error;
222              
223 4 50         if (!revspec.to) {
224 0           git_error_set(GIT_ERROR_INVALID, "invalid revspec: range not provided");
225 0           error = GIT_EINVALIDSPEC;
226 0           goto out;
227             }
228              
229 4 100         if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
230             /* TODO: support "..." */
231 1           git_error_set(GIT_ERROR_INVALID, "symmetric differences not implemented in revwalk");
232 1           error = GIT_EINVALIDSPEC;
233 1           goto out;
234             }
235              
236 3           opts.uninteresting = 1;
237 3 50         if ((error = git_revwalk__push_commit(walk, git_object_id(revspec.from), &opts)))
238 0           goto out;
239              
240 3           opts.uninteresting = 0;
241 3           error = git_revwalk__push_commit(walk, git_object_id(revspec.to), &opts);
242              
243             out:
244 4           git_object_free(revspec.from);
245 4           git_object_free(revspec.to);
246 5           return error;
247             }
248              
249 2           int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
250             {
251 2           git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
252 2 50         assert(walk && refname);
    50          
253 2           opts.uninteresting = 1;
254 2           return git_revwalk__push_ref(walk, refname, &opts);
255             }
256              
257 11           static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit)
258             {
259 11           return git_pqueue_insert(&walk->iterator_time, commit);
260             }
261              
262 0           static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *commit)
263             {
264 0 0         return git_commit_list_insert(commit, &walk->iterator_rand) ? 0 : -1;
265             }
266              
267 14           static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk)
268             {
269             git_commit_list_node *next;
270              
271 14 100         while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {
272             /* Some commits might become uninteresting after being added to the list */
273 11 50         if (!next->uninteresting) {
274 11           *object_out = next;
275 11           return 0;
276             }
277             }
278              
279 3           git_error_clear();
280 3           return GIT_ITEROVER;
281             }
282              
283 47           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 47 100         while (!(error = get_revision(&next, walk, &walk->iterator_rand))) {
289             /* Some commits might become uninteresting after being added to the list */
290 31 50         if (!next->uninteresting) {
291 31           *object_out = next;
292 31           return 0;
293             }
294             }
295              
296 47           return error;
297             }
298              
299 12           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 12 100         while (!(error = get_revision(&next, walk, &walk->iterator_topo))) {
305             /* Some commits might become uninteresting after being added to the list */
306 11 50         if (!next->uninteresting) {
307 11           *object_out = next;
308 11           return 0;
309             }
310             }
311              
312 12           return error;
313             }
314              
315 13           static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
316             {
317 13           *object_out = git_commit_list_pop(&walk->iterator_reverse);
318 13 100         return *object_out ? 0 : GIT_ITEROVER;
319             }
320              
321 38           static void mark_parents_uninteresting(git_commit_list_node *commit)
322             {
323             unsigned short i;
324 38           git_commit_list *parents = NULL;
325              
326 55 100         for (i = 0; i < commit->out_degree; i++)
327 17           git_commit_list_insert(commit->parents[i], &parents);
328              
329              
330 58 100         while (parents) {
331 20           commit = git_commit_list_pop(&parents);
332              
333 27 100         while (commit) {
334 23 100         if (commit->uninteresting)
335 16           break;
336              
337 7           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 7 50         if (!commit->parents)
344 0           break;
345              
346 10 100         for (i = 0; i < commit->out_degree; i++)
347 3           git_commit_list_insert(commit->parents[i], &parents);
348 7           commit = commit->parents[0];
349             }
350             }
351 38           }
352              
353 78           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 78 50         if (commit->added)
359 0           return 0;
360              
361 78           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 78 100         if (commit->uninteresting) {
372 24 100         for (i = 0; i < commit->out_degree; i++) {
373 7           git_commit_list_node *p = commit->parents[i];
374 7           p->uninteresting = 1;
375              
376             /* git does it gently here, but we don't like missing objects */
377 7 50         if ((error = git_commit_list_parse(walk, p)) < 0)
378 0           return error;
379              
380 7 50         if (p->parents)
381 7           mark_parents_uninteresting(p);
382              
383 7           p->seen = 1;
384 7           git_commit_list_insert_by_date(p, list);
385             }
386              
387 17           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 112 100         for (i = 0; i < commit->out_degree; i++) {
396 51           git_commit_list_node *p = commit->parents[i];
397              
398 51 50         if ((error = git_commit_list_parse(walk, p)) < 0)
399 0           return error;
400              
401 51 50         if (walk->hide_cb && walk->hide_cb(&p->oid, walk->hide_cb_payload))
    0          
402 0           continue;
403              
404 51 100         if (!p->seen) {
405 41           p->seen = 1;
406 41           git_commit_list_insert_by_date(p, list);
407             }
408              
409 51 50         if (walk->first_parent)
410 0           break;
411             }
412 61           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 17           static int still_interesting(git_commit_list *list, int64_t time, int slop)
419             {
420             /* The empty list is pretty boring */
421 17 100         if (!list)
422 5           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 12 100         if (time <= list->item->time)
429 2           return SLOP;
430              
431 17 100         for (; list; list = list->next) {
432             /*
433             * If the destination list still contains interesting commits we
434             * want to continue looking.
435             */
436 10 100         if (!list->item->uninteresting || list->item->time > time)
    50          
437 3           return SLOP;
438             }
439              
440             /* Everything's uninteresting, reduce the count */
441 7           return slop - 1;
442             }
443              
444 18           static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits)
445             {
446 18           int error, slop = SLOP;
447 18           int64_t time = INT64_MAX;
448 18           git_commit_list *list = commits;
449 18           git_commit_list *newlist = NULL;
450 18           git_commit_list **p = &newlist;
451              
452 73 100         while (list) {
453 60           git_commit_list_node *commit = git_commit_list_pop(&list);
454              
455 60 50         if ((error = add_parents_to_list(walk, commit, &list)) < 0)
456 0           return error;
457              
458 60 100         if (commit->uninteresting) {
459 17           mark_parents_uninteresting(commit);
460              
461 17           slop = still_interesting(list, time, slop);
462 17 100         if (slop)
463 12           continue;
464              
465 5           break;
466             }
467              
468 43 50         if (walk->hide_cb && walk->hide_cb(&commit->oid, walk->hide_cb_payload))
    0          
469 0           continue;
470              
471 43           time = commit->time;
472 43           p = &git_commit_list_insert(commit, p)->next;
473             }
474              
475 18           git_commit_list_free(&list);
476 18           *out = newlist;
477 18           return 0;
478             }
479              
480 59           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 59           commit = git_commit_list_pop(list);
486 59 100         if (!commit) {
487 17           git_error_clear();
488 17           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 42 100         if (!walk->limited) {
496 18 50         if ((error = add_parents_to_list(walk, commit, list)) < 0)
497 0           return error;
498             }
499              
500 42           *out = commit;
501 42           return 0;
502             }
503              
504 5           static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, git_commit_list *list)
505             {
506 5           git_commit_list *ll = NULL, *newlist, **pptr;
507             git_commit_list_node *next;
508             git_pqueue queue;
509 5           git_vector_cmp queue_cmp = NULL;
510             unsigned short i;
511             int error;
512              
513 5 50         if (walk->sorting & GIT_SORT_TIME)
514 0           queue_cmp = git_commit_list_time_cmp;
515              
516 5 50         if ((error = git_pqueue_init(&queue, 0, 8, queue_cmp)))
517 0           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 24 100         for (ll = list; ll; ll = ll->next) {
526 19           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 24 100         for(ll = list; ll; ll = ll->next) {
535 37 100         for (i = 0; i < ll->item->out_degree; ++i) {
536 18           git_commit_list_node *parent = ll->item->parents[i];
537 18 50         if (parent->in_degree)
538 18           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 24 100         for(ll = list; ll; ll = ll->next) {
547 19 100         if (ll->item->in_degree == 1) {
548 5 50         if ((error = git_pqueue_insert(&queue, ll->item)))
549 0           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 5 50         if ((walk->sorting & GIT_SORT_TIME) == 0)
559 5           git_pqueue_reverse(&queue);
560              
561              
562 5           pptr = &newlist;
563 5           newlist = NULL;
564 24 100         while ((next = git_pqueue_pop(&queue)) != NULL) {
565 37 100         for (i = 0; i < next->out_degree; ++i) {
566 18           git_commit_list_node *parent = next->parents[i];
567 18 50         if (parent->in_degree == 0)
568 0           continue;
569              
570 18 100         if (--parent->in_degree == 1) {
571 14 50         if ((error = git_pqueue_insert(&queue, parent)))
572 0           goto cleanup;
573             }
574             }
575              
576             /* All the children of 'item' have been emitted (since we got to it via the priority queue) */
577 19           next->in_degree = 0;
578              
579 19           pptr = &git_commit_list_insert(next, pptr)->next;
580             }
581              
582 5           *out = newlist;
583 5           error = 0;
584              
585             cleanup:
586 5           git_pqueue_free(&queue);
587 5           return error;
588             }
589              
590 27           static int prepare_walk(git_revwalk *walk)
591             {
592 27           int error = 0;
593 27           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 27 100         if (!walk->did_push) {
598 1           git_error_clear();
599 1           return GIT_ITEROVER;
600             }
601              
602 63 100         for (list = walk->user_input; list; list = list->next) {
603 37           git_commit_list_node *commit = list->item;
604 37 50         if ((error = git_commit_list_parse(walk, commit)) < 0)
605 0           return error;
606              
607 37 100         if (commit->uninteresting)
608 14           mark_parents_uninteresting(commit);
609              
610 37 100         if (!commit->seen) {
611 32           commit->seen = 1;
612 32           git_commit_list_insert(commit, &commits);
613             }
614             }
615              
616 26 100         if (walk->limited && (error = limit_list(&commits, walk, commits)) < 0)
    50          
617 0           return error;
618              
619 26 100         if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
620 5           error = sort_in_topological_order(&walk->iterator_topo, walk, commits);
621 5           git_commit_list_free(&commits);
622              
623 5 50         if (error < 0)
624 0           return error;
625              
626 5           walk->get_next = &revwalk_next_toposort;
627 21 100         } else if (walk->sorting & GIT_SORT_TIME) {
628 14 100         for (list = commits; list && !error; list = list->next)
    50          
629 11           error = walk->enqueue(walk, list->item);
630              
631 3           git_commit_list_free(&commits);
632              
633 3 50         if (error < 0)
634 0           return error;
635             } else {
636 18           walk->iterator_rand = commits;
637 18           walk->get_next = revwalk_next_unsorted;
638             }
639              
640 26 100         if (walk->sorting & GIT_SORT_REVERSE) {
641              
642 13 100         while ((error = walk->get_next(&next, walk)) == 0)
643 9 50         if (git_commit_list_insert(next, &walk->iterator_reverse) == NULL)
644 0           return -1;
645              
646 4 50         if (error != GIT_ITEROVER)
647 0           return error;
648              
649 4           walk->get_next = &revwalk_next_reverse;
650             }
651              
652 26           walk->walking = 1;
653 27           return 0;
654             }
655              
656              
657 56           int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
658             {
659 56           git_revwalk *walk = git__calloc(1, sizeof(git_revwalk));
660 56 50         GIT_ERROR_CHECK_ALLOC(walk);
661              
662 56 50         if (git_oidmap_new(&walk->commits) < 0)
663 0           return -1;
664              
665 56 50         if (git_pqueue_init(&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0)
666 0           return -1;
667              
668 56           git_pool_init(&walk->commit_pool, COMMIT_ALLOC);
669 56           walk->get_next = &revwalk_next_unsorted;
670 56           walk->enqueue = &revwalk_enqueue_unsorted;
671              
672 56           walk->repo = repo;
673              
674 56 50         if (git_repository_odb(&walk->odb, repo) < 0) {
675 0           git_revwalk_free(walk);
676 0           return -1;
677             }
678              
679 56           *revwalk_out = walk;
680 56           return 0;
681             }
682              
683 56           void git_revwalk_free(git_revwalk *walk)
684             {
685 56 50         if (walk == NULL)
686 0           return;
687              
688 56           git_revwalk_reset(walk);
689 56           git_odb_free(walk->odb);
690              
691 56           git_oidmap_free(walk->commits);
692 56           git_pool_clear(&walk->commit_pool);
693 56           git_pqueue_free(&walk->iterator_time);
694 56           git__free(walk);
695             }
696              
697 35           git_repository *git_revwalk_repository(git_revwalk *walk)
698             {
699 35 50         assert(walk);
700 35           return walk->repo;
701             }
702              
703 12           int git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
704             {
705 12 50         assert(walk);
706              
707 12 50         if (walk->walking)
708 0           git_revwalk_reset(walk);
709              
710 12           walk->sorting = sort_mode;
711              
712 12 100         if (walk->sorting & GIT_SORT_TIME) {
713 3           walk->get_next = &revwalk_next_timesort;
714 3           walk->enqueue = &revwalk_enqueue_timesort;
715             } else {
716 9           walk->get_next = &revwalk_next_unsorted;
717 9           walk->enqueue = &revwalk_enqueue_unsorted;
718             }
719              
720 12 100         if (walk->sorting != GIT_SORT_NONE)
721 11           walk->limited = 1;
722              
723 12           return 0;
724             }
725              
726 0           int git_revwalk_simplify_first_parent(git_revwalk *walk)
727             {
728 0           walk->first_parent = 1;
729 0           return 0;
730             }
731              
732 74           int git_revwalk_next(git_oid *oid, git_revwalk *walk)
733             {
734             int error;
735             git_commit_list_node *next;
736              
737 74 50         assert(walk && oid);
    50          
738              
739 74 100         if (!walk->walking) {
740 27 100         if ((error = prepare_walk(walk)) < 0)
741 1           return error;
742             }
743              
744 73           error = walk->get_next(&next, walk);
745              
746 73 100         if (error == GIT_ITEROVER) {
747 20           git_revwalk_reset(walk);
748 20           git_error_clear();
749 20           return GIT_ITEROVER;
750             }
751              
752 53 50         if (!error)
753 53           git_oid_cpy(oid, &next->oid);
754              
755 74           return error;
756             }
757              
758 87           int git_revwalk_reset(git_revwalk *walk)
759             {
760             git_commit_list_node *commit;
761              
762 87 50         assert(walk);
763              
764 354 100         git_oidmap_foreach_value(walk->commits, commit, {
765             commit->seen = 0;
766             commit->in_degree = 0;
767             commit->topo_delay = 0;
768             commit->uninteresting = 0;
769             commit->added = 0;
770             commit->flags = 0;
771             });
772              
773 87           git_pqueue_clear(&walk->iterator_time);
774 87           git_commit_list_free(&walk->iterator_topo);
775 87           git_commit_list_free(&walk->iterator_rand);
776 87           git_commit_list_free(&walk->iterator_reverse);
777 87           git_commit_list_free(&walk->user_input);
778 87           walk->first_parent = 0;
779 87           walk->walking = 0;
780 87           walk->limited = 0;
781 87           walk->did_push = walk->did_hide = 0;
782 87           walk->sorting = GIT_SORT_NONE;
783              
784 87           return 0;
785             }
786              
787 0           int git_revwalk_add_hide_cb(
788             git_revwalk *walk,
789             git_revwalk_hide_cb hide_cb,
790             void *payload)
791             {
792 0 0         assert(walk);
793              
794 0 0         if (walk->walking)
795 0           git_revwalk_reset(walk);
796              
797 0           walk->hide_cb = hide_cb;
798 0           walk->hide_cb_payload = payload;
799              
800 0 0         if (hide_cb)
801 0           walk->limited = 1;
802              
803 0           return 0;
804             }
805