File Coverage

deps/libgit2/src/libgit2/revwalk.c
Criterion Covered Total %
statement 346 404 85.6
branch 179 266 67.2
condition n/a
subroutine n/a
pod n/a
total 525 670 78.3


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