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