diff --git a/src/commit.c b/src/commit.c index fa33b5202..8654e891d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -35,16 +35,15 @@ const git_oid *git_commit_id(git_commit *c) return &c->id; } -void git_commit_mark_uninteresting(git_commit *commit) +void git_commit__mark_uninteresting(git_commit *commit) { + if (commit == NULL) + return; + git_commit_list *parents = commit->parents; commit->flags |= GIT_COMMIT_HIDE; - /* - * FIXME: mark recursively the parents' parents? - * They are most likely not parsed yet... - */ while (parents) { parents->commit->flags |= GIT_COMMIT_HIDE; parents = parents->next; @@ -113,8 +112,6 @@ git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id) git_oid_cpy(&commit->id, id); commit->pool = pool; - git_commit_list_insert(&pool->commits, commit); - return commit; } @@ -187,6 +184,10 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len) if ((parent = git_commit_lookup(commit->pool, &oid)) == NULL) return -1; + // Inherit uninteresting flag + if (commit->flags & GIT_COMMIT_HIDE) + parent->flags |= GIT_COMMIT_HIDE; + git_commit_list_insert(&commit->parents, parent); } diff --git a/src/commit.h b/src/commit.h index 3a6b70664..a0c0512a8 100644 --- a/src/commit.h +++ b/src/commit.h @@ -29,6 +29,7 @@ struct git_commit { int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); int git_commit__parse_buffer(git_commit *commit, void *data, size_t len); int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end); +void git_commit__mark_uninteresting(git_commit *commit); int git_commit_parse_existing(git_commit *commit); diff --git a/src/git/commit.h b/src/git/commit.h index 1a57ba732..279d8e376 100644 --- a/src/git/commit.h +++ b/src/git/commit.h @@ -44,6 +44,14 @@ GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id); */ GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit); + +/** + * Mark a commit and all its parents as uninteresting. + * @param commit The commit to mark + */ +GIT_EXTERN(void) git_commit_mark_uninteresting(git_commit *commit); + + /** @} */ GIT_END_DECL #endif diff --git a/src/revwalk.c b/src/revwalk.c index fe6f9f293..001d938db 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -43,10 +43,12 @@ void gitrp_free(git_revpool *walk) { git_commit_list *list; - list = walk->commits; + list = walk->roots; while (list) { free(list->commit); + free(list); + list = list->next; } @@ -67,16 +69,35 @@ void gitrp_push(git_revpool *pool, git_commit *commit) return; } + // Sanity check: make sure that if the commit + // has been manually marked as uninteresting, + // all the parent commits are too. + if ((commit->flags & GIT_COMMIT_HIDE) != 0) + git_commit__mark_uninteresting(commit); + commit->flags |= GIT_COMMIT_SEEN; git_commit_list_insert(&pool->roots, commit); + git_commit_list_insert(&pool->iterator, commit); +} + +void gitrp_hide(git_revpool *pool, git_commit *commit) +{ + git_commit_mark_uninteresting(commit); + gitrp_push(pool, commit); } void gitrp_prepare_walk(git_revpool *pool) { - // TODO: sort commit list based on walk ordering + git_commit_list *list; + + list = pool->roots; + while (list) + { + git_commit_list_insert(&pool->iterator, list->commit); + list = list->next; + } - pool->iterator = pool->roots; pool->walking = 1; } @@ -87,17 +108,36 @@ git_commit *gitrp_next(git_revpool *pool) if (!pool->walking) gitrp_prepare_walk(pool); - // Iteration finished - if (pool->iterator == NULL) + while (pool->iterator != NULL) { - gitrp_reset(pool); - return NULL; + git_commit_list *list; + + next = pool->iterator->commit; + free(pool->iterator); + pool->iterator = pool->iterator->next; + + list = next->parents; + while (list) + { + git_commit *parent = list->commit; + list = list->next; + + if ((parent->flags & GIT_COMMIT_SEEN) != 0) + continue; + + if (parent->parsed == 0) + git_commit_parse_existing(parent); + + git_commit_list_insert(&pool->iterator, list->commit); + } + + if ((next->flags & GIT_COMMIT_HIDE) != 0) + return next; } - next = pool->iterator->commit; - pool->iterator = pool->iterator->next; - - return next; + // No commits left to iterate + gitrp_reset(pool); + return NULL; } void gitrp_reset(git_revpool *pool) diff --git a/src/revwalk.h b/src/revwalk.h index 34ff3378e..be01c4799 100644 --- a/src/revwalk.h +++ b/src/revwalk.h @@ -7,7 +7,6 @@ struct git_revpool { git_odb *db; git_commit_list *iterator; - git_commit_list *commits; git_commit_list *roots; unsigned walking:1,