]>
Commit | Line | Data |
---|---|---|
06160502 | 1 | /* |
bb742ede | 2 | * Copyright (C) 2009-2011 the libgit2 contributors |
06160502 | 3 | * |
bb742ede VM |
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. | |
06160502 SP |
6 | */ |
7 | ||
64a47c01 | 8 | #include "common.h" |
08d5d000 | 9 | #include "commit.h" |
72a3fe42 | 10 | #include "odb.h" |
3315782c | 11 | #include "hashtable.h" |
71db842f | 12 | #include "pqueue.h" |
06160502 | 13 | |
b5c5f0f8 VM |
14 | #include "git2/revwalk.h" |
15 | ||
71db842f VM |
16 | typedef struct commit_object { |
17 | git_oid oid; | |
18 | uint32_t time; | |
19 | unsigned int seen:1, | |
20 | uninteresting:1, | |
21 | topo_delay:1, | |
22 | parsed:1; | |
23 | ||
24 | unsigned short in_degree; | |
25 | unsigned short out_degree; | |
26 | ||
27 | struct commit_object **parents; | |
28 | } commit_object; | |
29 | ||
30 | typedef struct commit_list { | |
31 | commit_object *item; | |
32 | struct commit_list *next; | |
33 | } commit_list; | |
34 | ||
35 | struct git_revwalk { | |
36 | git_repository *repo; | |
9462c471 | 37 | git_odb *odb; |
71db842f VM |
38 | |
39 | git_hashtable *commits; | |
71db842f VM |
40 | |
41 | commit_list *iterator_topo; | |
42 | commit_list *iterator_rand; | |
43 | commit_list *iterator_reverse; | |
44 | git_pqueue iterator_time; | |
45 | ||
46 | int (*get_next)(commit_object **, git_revwalk *); | |
47 | int (*enqueue)(git_revwalk *, commit_object *); | |
48 | ||
49 | git_vector memory_alloc; | |
50 | size_t chunk_size; | |
51 | ||
52 | unsigned walking:1; | |
53 | unsigned int sorting; | |
54 | }; | |
55 | ||
d568d585 | 56 | static commit_list *commit_list_insert(commit_object *item, commit_list **list_p) |
71db842f VM |
57 | { |
58 | commit_list *new_list = git__malloc(sizeof(commit_list)); | |
59 | new_list->item = item; | |
60 | new_list->next = *list_p; | |
61 | *list_p = new_list; | |
62 | return new_list; | |
63 | } | |
64 | ||
d568d585 | 65 | static void commit_list_free(commit_list **list_p) |
71db842f | 66 | { |
36b31329 VM |
67 | commit_list *list = *list_p; |
68 | ||
71db842f VM |
69 | while (list) { |
70 | commit_list *temp = list; | |
71 | list = temp->next; | |
3286c408 | 72 | git__free(temp); |
71db842f | 73 | } |
36b31329 VM |
74 | |
75 | *list_p = NULL; | |
71db842f VM |
76 | } |
77 | ||
d568d585 | 78 | static commit_object *commit_list_pop(commit_list **stack) |
71db842f VM |
79 | { |
80 | commit_list *top = *stack; | |
81 | commit_object *item = top ? top->item : NULL; | |
82 | ||
83 | if (top) { | |
84 | *stack = top->next; | |
3286c408 | 85 | git__free(top); |
71db842f VM |
86 | } |
87 | return item; | |
88 | } | |
89 | ||
90 | static int commit_time_cmp(void *a, void *b) | |
91 | { | |
92 | commit_object *commit_a = (commit_object *)a; | |
93 | commit_object *commit_b = (commit_object *)b; | |
94 | ||
95 | return (commit_a->time < commit_b->time); | |
96 | } | |
97 | ||
98 | static uint32_t object_table_hash(const void *key, int hash_id) | |
3315782c VM |
99 | { |
100 | uint32_t r; | |
803ca5cb | 101 | const git_oid *id = key; |
5e15176d | 102 | |
71db842f | 103 | memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r)); |
3315782c VM |
104 | return r; |
105 | } | |
106 | ||
71db842f VM |
107 | #define COMMITS_PER_CHUNK 128 |
108 | #define CHUNK_STEP 64 | |
109 | #define PARENTS_PER_COMMIT ((CHUNK_STEP - sizeof(commit_object)) / sizeof(commit_object *)) | |
110 | ||
111 | static int alloc_chunk(git_revwalk *walk) | |
06160502 | 112 | { |
71db842f VM |
113 | void *chunk; |
114 | ||
115 | chunk = git__calloc(COMMITS_PER_CHUNK, CHUNK_STEP); | |
116 | if (chunk == NULL) | |
117 | return GIT_ENOMEM; | |
118 | ||
119 | walk->chunk_size = 0; | |
120 | return git_vector_insert(&walk->memory_alloc, chunk); | |
121 | } | |
122 | ||
123 | static commit_object *alloc_commit(git_revwalk *walk) | |
124 | { | |
125 | unsigned char *chunk; | |
126 | ||
127 | if (walk->chunk_size == COMMITS_PER_CHUNK) | |
128 | alloc_chunk(walk); | |
129 | ||
130 | chunk = git_vector_get(&walk->memory_alloc, walk->memory_alloc.length - 1); | |
131 | chunk += (walk->chunk_size * CHUNK_STEP); | |
132 | walk->chunk_size++; | |
133 | ||
134 | return (commit_object *)chunk; | |
135 | } | |
136 | ||
137 | static commit_object **alloc_parents(commit_object *commit, size_t n_parents) | |
138 | { | |
139 | if (n_parents <= PARENTS_PER_COMMIT) | |
140 | return (commit_object **)((unsigned char *)commit + sizeof(commit_object)); | |
141 | ||
142 | return git__malloc(n_parents * sizeof(commit_object *)); | |
3315782c VM |
143 | } |
144 | ||
40721f6b | 145 | |
71db842f | 146 | static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid) |
3315782c | 147 | { |
71db842f | 148 | commit_object *commit; |
58b0cbea | 149 | |
71db842f | 150 | if ((commit = git_hashtable_lookup(walk->commits, oid)) != NULL) |
3315782c | 151 | return commit; |
40721f6b | 152 | |
71db842f | 153 | commit = alloc_commit(walk); |
3315782c VM |
154 | if (commit == NULL) |
155 | return NULL; | |
5e15176d | 156 | |
71db842f | 157 | git_oid_cpy(&commit->oid, oid); |
3315782c | 158 | |
71db842f | 159 | if (git_hashtable_insert(walk->commits, &commit->oid, commit) < GIT_SUCCESS) { |
3286c408 | 160 | git__free(commit); |
71db842f VM |
161 | return NULL; |
162 | } | |
3315782c VM |
163 | |
164 | return commit; | |
06160502 | 165 | } |
08d5d000 | 166 | |
71db842f | 167 | static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawobj *raw) |
e5d1faef | 168 | { |
932669b8 | 169 | const int parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; |
3315782c | 170 | |
71db842f VM |
171 | unsigned char *buffer = raw->data; |
172 | unsigned char *buffer_end = buffer + raw->len; | |
173 | unsigned char *parents_start; | |
3315782c | 174 | |
71db842f | 175 | int i, parents = 0; |
ad196c6a | 176 | int commit_time; |
3315782c | 177 | |
932669b8 | 178 | buffer += strlen("tree ") + GIT_OID_HEXSZ + 1; |
e5d1faef | 179 | |
71db842f | 180 | parents_start = buffer; |
932669b8 | 181 | while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", strlen("parent ")) == 0) { |
71db842f VM |
182 | parents++; |
183 | buffer += parent_len; | |
184 | } | |
3315782c | 185 | |
71db842f VM |
186 | commit->parents = alloc_parents(commit, parents); |
187 | if (commit->parents == NULL) | |
188 | return GIT_ENOMEM; | |
3315782c | 189 | |
71db842f VM |
190 | buffer = parents_start; |
191 | for (i = 0; i < parents; ++i) { | |
192 | git_oid oid; | |
3315782c | 193 | |
932669b8 | 194 | if (git_oid_fromstr(&oid, (char *)buffer + strlen("parent ")) < GIT_SUCCESS) |
b51c9269 | 195 | return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Parent object is corrupted"); |
eec95235 | 196 | |
71db842f VM |
197 | commit->parents[i] = commit_lookup(walk, &oid); |
198 | if (commit->parents[i] == NULL) | |
199 | return GIT_ENOMEM; | |
3315782c | 200 | |
71db842f VM |
201 | buffer += parent_len; |
202 | } | |
3315782c | 203 | |
71db842f | 204 | commit->out_degree = (unsigned short)parents; |
3315782c | 205 | |
71db842f | 206 | if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) |
b51c9269 | 207 | return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Object is corrupted"); |
3315782c | 208 | |
71db842f VM |
209 | buffer = memchr(buffer, '>', buffer_end - buffer); |
210 | if (buffer == NULL) | |
b51c9269 | 211 | return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't find author"); |
3315782c | 212 | |
c6e65aca | 213 | if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS) |
b51c9269 | 214 | return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't parse commit time"); |
e5d1faef | 215 | |
c6e65aca | 216 | commit->time = (time_t)commit_time; |
71db842f VM |
217 | commit->parsed = 1; |
218 | return GIT_SUCCESS; | |
3315782c | 219 | } |
8add0153 | 220 | |
71db842f | 221 | static int commit_parse(git_revwalk *walk, commit_object *commit) |
3315782c | 222 | { |
72a3fe42 | 223 | git_odb_object *obj; |
71db842f | 224 | int error; |
3315782c | 225 | |
71db842f VM |
226 | if (commit->parsed) |
227 | return GIT_SUCCESS; | |
08d5d000 | 228 | |
9462c471 | 229 | if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < GIT_SUCCESS) |
b51c9269 | 230 | return git__rethrow(error, "Failed to parse commit. Can't read object"); |
52f2390b | 231 | |
72a3fe42 VM |
232 | if (obj->raw.type != GIT_OBJ_COMMIT) { |
233 | git_odb_object_close(obj); | |
b51c9269 | 234 | return git__throw(GIT_EOBJTYPE, "Failed to parse commit. Object is no commit object"); |
9b3577ed | 235 | } |
71db842f | 236 | |
72a3fe42 VM |
237 | error = commit_quick_parse(walk, commit, &obj->raw); |
238 | git_odb_object_close(obj); | |
c0cd9d50 | 239 | return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse commit"); |
3315782c VM |
240 | } |
241 | ||
71db842f | 242 | static void mark_uninteresting(commit_object *commit) |
3315782c | 243 | { |
71db842f VM |
244 | unsigned short i; |
245 | assert(commit); | |
1f080e2d | 246 | |
71db842f | 247 | commit->uninteresting = 1; |
08d5d000 | 248 | |
71db842f VM |
249 | for (i = 0; i < commit->out_degree; ++i) |
250 | if (!commit->parents[i]->uninteresting) | |
251 | mark_uninteresting(commit->parents[i]); | |
3315782c | 252 | } |
1a895dd7 | 253 | |
c68dee2a | 254 | static int process_commit(git_revwalk *walk, commit_object *commit, int hide) |
3315782c | 255 | { |
71db842f | 256 | int error; |
3315782c | 257 | |
c68dee2a VM |
258 | if (hide) |
259 | mark_uninteresting(commit); | |
260 | ||
71db842f VM |
261 | if (commit->seen) |
262 | return GIT_SUCCESS; | |
3315782c | 263 | |
71db842f | 264 | commit->seen = 1; |
1a895dd7 | 265 | |
71db842f | 266 | if ((error = commit_parse(walk, commit)) < GIT_SUCCESS) |
c0cd9d50 | 267 | return git__rethrow(error, "Failed to process commit"); |
e5d1faef | 268 | |
71db842f VM |
269 | return walk->enqueue(walk, commit); |
270 | } | |
3315782c | 271 | |
71db842f VM |
272 | static int process_commit_parents(git_revwalk *walk, commit_object *commit) |
273 | { | |
274 | unsigned short i; | |
275 | int error = GIT_SUCCESS; | |
c836c332 | 276 | |
71db842f | 277 | for (i = 0; i < commit->out_degree && error == GIT_SUCCESS; ++i) { |
c68dee2a | 278 | error = process_commit(walk, commit->parents[i], commit->uninteresting); |
3315782c VM |
279 | } |
280 | ||
c0cd9d50 | 281 | return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to process commit parents"); |
08d5d000 VM |
282 | } |
283 | ||
71db842f | 284 | static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting) |
08d5d000 | 285 | { |
71db842f | 286 | commit_object *commit; |
1a895dd7 | 287 | |
71db842f VM |
288 | commit = commit_lookup(walk, oid); |
289 | if (commit == NULL) | |
b51c9269 | 290 | return git__throw(GIT_ENOTFOUND, "Failed to push commit. Object not found"); |
1f080e2d | 291 | |
c68dee2a | 292 | return process_commit(walk, commit, uninteresting); |
3315782c VM |
293 | } |
294 | ||
71db842f VM |
295 | int git_revwalk_push(git_revwalk *walk, const git_oid *oid) |
296 | { | |
297 | assert(walk && oid); | |
298 | return push_commit(walk, oid, 0); | |
299 | } | |
3315782c | 300 | |
71db842f VM |
301 | int git_revwalk_hide(git_revwalk *walk, const git_oid *oid) |
302 | { | |
303 | assert(walk && oid); | |
304 | return push_commit(walk, oid, 1); | |
305 | } | |
3315782c | 306 | |
71db842f | 307 | static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit) |
3315782c | 308 | { |
71db842f VM |
309 | return git_pqueue_insert(&walk->iterator_time, commit); |
310 | } | |
3315782c | 311 | |
71db842f VM |
312 | static int revwalk_enqueue_unsorted(git_revwalk *walk, commit_object *commit) |
313 | { | |
314 | return commit_list_insert(commit, &walk->iterator_rand) ? GIT_SUCCESS : GIT_ENOMEM; | |
315 | } | |
3315782c | 316 | |
71db842f VM |
317 | static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk) |
318 | { | |
319 | int error; | |
320 | commit_object *next; | |
5e15176d | 321 | |
71db842f VM |
322 | while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) { |
323 | if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS) | |
c0cd9d50 | 324 | return git__rethrow(error, "Failed to load next revision"); |
6bb7aa13 | 325 | |
71db842f VM |
326 | if (!next->uninteresting) { |
327 | *object_out = next; | |
328 | return GIT_SUCCESS; | |
329 | } | |
9b3577ed | 330 | } |
08d5d000 | 331 | |
c0cd9d50 | 332 | return git__throw(GIT_EREVWALKOVER, "Failed to load next revision"); |
3315782c VM |
333 | } |
334 | ||
71db842f | 335 | static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk) |
3315782c | 336 | { |
71db842f VM |
337 | int error; |
338 | commit_object *next; | |
3315782c | 339 | |
71db842f VM |
340 | while ((next = commit_list_pop(&walk->iterator_rand)) != NULL) { |
341 | if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS) | |
c0cd9d50 | 342 | return git__rethrow(error, "Failed to load next revision"); |
6bb7aa13 | 343 | |
71db842f VM |
344 | if (!next->uninteresting) { |
345 | *object_out = next; | |
346 | return GIT_SUCCESS; | |
347 | } | |
3315782c VM |
348 | } |
349 | ||
c0cd9d50 | 350 | return git__throw(GIT_EREVWALKOVER, "Failed to load next revision"); |
a7c182c5 | 351 | } |
1a895dd7 | 352 | |
71db842f | 353 | static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) |
a7c182c5 | 354 | { |
71db842f VM |
355 | commit_object *next; |
356 | unsigned short i; | |
1a895dd7 | 357 | |
71db842f VM |
358 | for (;;) { |
359 | next = commit_list_pop(&walk->iterator_topo); | |
360 | if (next == NULL) | |
c0cd9d50 | 361 | return git__throw(GIT_EREVWALKOVER, "Failed to load next revision"); |
5e15176d | 362 | |
71db842f VM |
363 | if (next->in_degree > 0) { |
364 | next->topo_delay = 1; | |
365 | continue; | |
366 | } | |
655d381a | 367 | |
71db842f VM |
368 | for (i = 0; i < next->out_degree; ++i) { |
369 | commit_object *parent = next->parents[i]; | |
5e15176d | 370 | |
71db842f VM |
371 | if (--parent->in_degree == 0 && parent->topo_delay) { |
372 | parent->topo_delay = 0; | |
373 | commit_list_insert(parent, &walk->iterator_topo); | |
374 | } | |
375 | } | |
5e15176d | 376 | |
71db842f VM |
377 | *object_out = next; |
378 | return GIT_SUCCESS; | |
379 | } | |
5e15176d VM |
380 | } |
381 | ||
71db842f | 382 | static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk) |
5e15176d | 383 | { |
71db842f VM |
384 | *object_out = commit_list_pop(&walk->iterator_reverse); |
385 | return *object_out ? GIT_SUCCESS : GIT_EREVWALKOVER; | |
386 | } | |
5e15176d | 387 | |
3315782c | 388 | |
71db842f VM |
389 | static int prepare_walk(git_revwalk *walk) |
390 | { | |
71db842f | 391 | int error; |
36aaf1ff | 392 | commit_object *next; |
08d5d000 | 393 | |
71db842f | 394 | if (walk->sorting & GIT_SORT_TOPOLOGICAL) { |
71db842f | 395 | unsigned short i; |
08d5d000 | 396 | |
71db842f VM |
397 | while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS) { |
398 | for (i = 0; i < next->out_degree; ++i) { | |
399 | commit_object *parent = next->parents[i]; | |
400 | parent->in_degree++; | |
401 | } | |
3315782c | 402 | |
71db842f VM |
403 | commit_list_insert(next, &walk->iterator_topo); |
404 | } | |
3315782c | 405 | |
71db842f | 406 | if (error != GIT_EREVWALKOVER) |
c0cd9d50 | 407 | return git__rethrow(error, "Failed to prepare revision walk"); |
3315782c | 408 | |
71db842f VM |
409 | walk->get_next = &revwalk_next_toposort; |
410 | } | |
3315782c | 411 | |
71db842f | 412 | if (walk->sorting & GIT_SORT_REVERSE) { |
3315782c | 413 | |
71db842f VM |
414 | while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS) |
415 | commit_list_insert(next, &walk->iterator_reverse); | |
3315782c | 416 | |
71db842f | 417 | if (error != GIT_EREVWALKOVER) |
c0cd9d50 | 418 | return git__rethrow(error, "Failed to prepare revision walk"); |
9bdb7594 | 419 | |
71db842f VM |
420 | walk->get_next = &revwalk_next_reverse; |
421 | } | |
40721f6b | 422 | |
71db842f VM |
423 | walk->walking = 1; |
424 | return GIT_SUCCESS; | |
425 | } | |
3315782c | 426 | |
3315782c | 427 | |
36aaf1ff VM |
428 | |
429 | ||
430 | ||
431 | int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) | |
432 | { | |
9462c471 | 433 | int error; |
36aaf1ff VM |
434 | git_revwalk *walk; |
435 | ||
436 | walk = git__malloc(sizeof(git_revwalk)); | |
437 | if (walk == NULL) | |
438 | return GIT_ENOMEM; | |
439 | ||
440 | memset(walk, 0x0, sizeof(git_revwalk)); | |
441 | ||
442 | walk->commits = git_hashtable_alloc(64, | |
443 | object_table_hash, | |
444 | (git_hash_keyeq_ptr)git_oid_cmp); | |
445 | ||
446 | if (walk->commits == NULL) { | |
3286c408 | 447 | git__free(walk); |
36aaf1ff VM |
448 | return GIT_ENOMEM; |
449 | } | |
450 | ||
451 | git_pqueue_init(&walk->iterator_time, 8, commit_time_cmp); | |
452 | git_vector_init(&walk->memory_alloc, 8, NULL); | |
453 | alloc_chunk(walk); | |
454 | ||
455 | walk->get_next = &revwalk_next_unsorted; | |
456 | walk->enqueue = &revwalk_enqueue_unsorted; | |
457 | ||
458 | walk->repo = repo; | |
459 | ||
9462c471 VM |
460 | error = git_repository_odb(&walk->odb, repo); |
461 | if (error < GIT_SUCCESS) { | |
462 | git_revwalk_free(walk); | |
463 | return error; | |
464 | } | |
465 | ||
36aaf1ff VM |
466 | *revwalk_out = walk; |
467 | return GIT_SUCCESS; | |
468 | } | |
469 | ||
470 | void git_revwalk_free(git_revwalk *walk) | |
471 | { | |
472 | unsigned int i; | |
402a47a7 | 473 | const void *GIT_UNUSED(_unused); |
21d73e71 | 474 | commit_object *commit; |
36aaf1ff VM |
475 | |
476 | if (walk == NULL) | |
477 | return; | |
478 | ||
479 | git_revwalk_reset(walk); | |
9462c471 | 480 | git_odb_free(walk->odb); |
21d73e71 VM |
481 | |
482 | /* if the parent has more than PARENTS_PER_COMMIT parents, | |
483 | * we had to allocate a separate array for those parents. | |
484 | * make sure it's being free'd */ | |
485 | GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, { | |
486 | if (commit->out_degree > PARENTS_PER_COMMIT) | |
3286c408 | 487 | git__free(commit->parents); |
21d73e71 VM |
488 | }); |
489 | ||
36aaf1ff VM |
490 | git_hashtable_free(walk->commits); |
491 | git_pqueue_free(&walk->iterator_time); | |
492 | ||
493 | for (i = 0; i < walk->memory_alloc.length; ++i) | |
3286c408 | 494 | git__free(git_vector_get(&walk->memory_alloc, i)); |
36aaf1ff VM |
495 | |
496 | git_vector_free(&walk->memory_alloc); | |
3286c408 | 497 | git__free(walk); |
36aaf1ff VM |
498 | } |
499 | ||
500 | git_repository *git_revwalk_repository(git_revwalk *walk) | |
501 | { | |
502 | assert(walk); | |
503 | return walk->repo; | |
504 | } | |
505 | ||
506 | void git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode) | |
507 | { | |
508 | assert(walk); | |
509 | ||
510 | if (walk->walking) | |
511 | git_revwalk_reset(walk); | |
512 | ||
513 | walk->sorting = sort_mode; | |
514 | ||
515 | if (walk->sorting & GIT_SORT_TIME) { | |
516 | walk->get_next = &revwalk_next_timesort; | |
517 | walk->enqueue = &revwalk_enqueue_timesort; | |
518 | } else { | |
519 | walk->get_next = &revwalk_next_unsorted; | |
520 | walk->enqueue = &revwalk_enqueue_unsorted; | |
521 | } | |
522 | } | |
523 | ||
71db842f VM |
524 | int git_revwalk_next(git_oid *oid, git_revwalk *walk) |
525 | { | |
526 | int error; | |
527 | commit_object *next; | |
3315782c | 528 | |
71db842f | 529 | assert(walk && oid); |
3315782c | 530 | |
71db842f VM |
531 | if (!walk->walking) { |
532 | if ((error = prepare_walk(walk)) < GIT_SUCCESS) | |
c0cd9d50 | 533 | return git__rethrow(error, "Failed to load next revision"); |
71db842f | 534 | } |
3315782c | 535 | |
71db842f | 536 | error = walk->get_next(&next, walk); |
ce90d81f VM |
537 | |
538 | if (error == GIT_EREVWALKOVER) { | |
539 | git_revwalk_reset(walk); | |
540 | return GIT_EREVWALKOVER; | |
36aaf1ff | 541 | } |
3315782c | 542 | |
ce90d81f VM |
543 | if (error < GIT_SUCCESS) |
544 | return git__rethrow(error, "Failed to load next revision"); | |
545 | ||
71db842f VM |
546 | git_oid_cpy(oid, &next->oid); |
547 | return GIT_SUCCESS; | |
3315782c VM |
548 | } |
549 | ||
71db842f | 550 | void git_revwalk_reset(git_revwalk *walk) |
3315782c | 551 | { |
402a47a7 | 552 | const void *GIT_UNUSED(_unused); |
71db842f | 553 | commit_object *commit; |
3315782c | 554 | |
71db842f | 555 | assert(walk); |
9bdb7594 | 556 | |
71db842f VM |
557 | GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, |
558 | commit->seen = 0; | |
559 | commit->in_degree = 0; | |
560 | commit->topo_delay = 0; | |
561 | ); | |
9bdb7594 | 562 | |
36aaf1ff | 563 | git_pqueue_clear(&walk->iterator_time); |
36b31329 VM |
564 | commit_list_free(&walk->iterator_topo); |
565 | commit_list_free(&walk->iterator_rand); | |
566 | commit_list_free(&walk->iterator_reverse); | |
71db842f | 567 | walk->walking = 0; |
08d5d000 | 568 | } |
36b7cdb6 | 569 |