Commit f339f441 by Edward Thomson

Merge pull request #2603 from libgit2/cmn/revwalk-merge-base

Walk only as far as the common ancestors of uninteresting commits
parents bd62dc6f d6afda62
...@@ -116,6 +116,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, ...@@ -116,6 +116,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting,
int error; int error;
git_object *obj, *oobj; git_object *obj, *oobj;
git_commit_list_node *commit; git_commit_list_node *commit;
git_commit_list *list;
if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJ_ANY)) < 0) if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJ_ANY)) < 0)
return error; return error;
...@@ -141,14 +142,20 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, ...@@ -141,14 +142,20 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting,
if (commit == NULL) if (commit == NULL)
return -1; /* error already reported by failed lookup */ return -1; /* error already reported by failed lookup */
if (uninteresting)
walk->did_hide = 1;
else
walk->did_push = 1;
commit->uninteresting = uninteresting; commit->uninteresting = uninteresting;
if (walk->one == NULL && !uninteresting) { list = walk->user_input;
walk->one = commit; if (git_commit_list_insert(commit, &list) == NULL) {
} else { giterr_set_oom();
if (git_vector_insert(&walk->twos, commit) < 0) return -1;
return -1;
} }
walk->user_input = list;
return 0; return 0;
} }
...@@ -367,29 +374,97 @@ static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk * ...@@ -367,29 +374,97 @@ static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *
} }
static int interesting(git_pqueue *list)
{
size_t i;
for (i = 0; i < git_pqueue_size(list); i++) {
git_commit_list_node *commit = git_pqueue_get(list, i);
if (!commit->uninteresting)
return 1;
}
return 0;
}
static int contains(git_pqueue *list, git_commit_list_node *node)
{
size_t i;
for (i = 0; i < git_pqueue_size(list); i++) {
git_commit_list_node *commit = git_pqueue_get(list, i);
if (commit == node)
return 1;
}
return 0;
}
static int premark_uninteresting(git_revwalk *walk)
{
int error = 0;
unsigned short i;
git_pqueue q;
git_commit_list *list;
git_commit_list_node *commit, *parent;
if ((error = git_pqueue_init(&q, 0, 8, git_commit_list_time_cmp)) < 0)
return error;
for (list = walk->user_input; list; list = list->next) {
if ((error = git_commit_list_parse(walk, list->item)) < 0)
goto cleanup;
if ((error = git_pqueue_insert(&q, list->item)) < 0)
goto cleanup;
}
while (interesting(&q)) {
commit = git_pqueue_pop(&q);
for (i = 0; i < commit->out_degree; i++) {
parent = commit->parents[i];
if ((error = git_commit_list_parse(walk, parent)) < 0)
goto cleanup;
if (commit->uninteresting)
parent->uninteresting = 1;
if (contains(&q, parent))
continue;
if ((error = git_pqueue_insert(&q, parent)) < 0)
goto cleanup;
}
}
cleanup:
git_pqueue_free(&q);
return error;
}
static int prepare_walk(git_revwalk *walk) static int prepare_walk(git_revwalk *walk)
{ {
int error; int error;
unsigned int i; git_commit_list *list;
git_commit_list_node *next, *two; git_commit_list_node *next;
/* /* If there were no pushes, we know that the walk is already over */
* If walk->one is NULL, there were no positive references, if (!walk->did_push) {
* so we know that the walk is already over.
*/
if (walk->one == NULL) {
giterr_clear(); giterr_clear();
return GIT_ITEROVER; return GIT_ITEROVER;
} }
if (process_commit(walk, walk->one, walk->one->uninteresting) < 0) if (walk->did_hide && (error = premark_uninteresting(walk)) < 0)
return -1; return error;
git_vector_foreach(&walk->twos, i, two) { for (list = walk->user_input; list; list = list->next) {
if (process_commit(walk, two, two->uninteresting) < 0) if (process_commit(walk, list->item, list->item->uninteresting) < 0)
return -1; return -1;
} }
if (walk->sorting & GIT_SORT_TOPOLOGICAL) { if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
unsigned short i; unsigned short i;
...@@ -440,7 +515,6 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) ...@@ -440,7 +515,6 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
if (git_pqueue_init( if (git_pqueue_init(
&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 || &walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 ||
git_vector_init(&walk->twos, 4, NULL) < 0 ||
git_pool_init(&walk->commit_pool, 1, git_pool_init(&walk->commit_pool, 1,
git_pool__suggest_items_per_page(COMMIT_ALLOC) * COMMIT_ALLOC) < 0) git_pool__suggest_items_per_page(COMMIT_ALLOC) * COMMIT_ALLOC) < 0)
return -1; return -1;
...@@ -470,7 +544,6 @@ void git_revwalk_free(git_revwalk *walk) ...@@ -470,7 +544,6 @@ void git_revwalk_free(git_revwalk *walk)
git_oidmap_free(walk->commits); git_oidmap_free(walk->commits);
git_pool_clear(&walk->commit_pool); git_pool_clear(&walk->commit_pool);
git_pqueue_free(&walk->iterator_time); git_pqueue_free(&walk->iterator_time);
git_vector_free(&walk->twos);
git__free(walk); git__free(walk);
} }
...@@ -540,16 +613,17 @@ void git_revwalk_reset(git_revwalk *walk) ...@@ -540,16 +613,17 @@ void git_revwalk_reset(git_revwalk *walk)
commit->in_degree = 0; commit->in_degree = 0;
commit->topo_delay = 0; commit->topo_delay = 0;
commit->uninteresting = 0; commit->uninteresting = 0;
commit->flags = 0;
}); });
git_pqueue_clear(&walk->iterator_time); git_pqueue_clear(&walk->iterator_time);
git_commit_list_free(&walk->iterator_topo); git_commit_list_free(&walk->iterator_topo);
git_commit_list_free(&walk->iterator_rand); git_commit_list_free(&walk->iterator_rand);
git_commit_list_free(&walk->iterator_reverse); git_commit_list_free(&walk->iterator_reverse);
git_commit_list_free(&walk->user_input);
walk->first_parent = 0;
walk->walking = 0; walk->walking = 0;
walk->did_push = walk->did_hide = 0;
walk->one = NULL;
git_vector_clear(&walk->twos);
} }
int git_revwalk_add_hide_cb( int git_revwalk_add_hide_cb(
......
...@@ -32,12 +32,13 @@ struct git_revwalk { ...@@ -32,12 +32,13 @@ struct git_revwalk {
int (*enqueue)(git_revwalk *, git_commit_list_node *); int (*enqueue)(git_revwalk *, git_commit_list_node *);
unsigned walking:1, unsigned walking:1,
first_parent: 1; first_parent: 1,
did_hide: 1,
did_push: 1;
unsigned int sorting; unsigned int sorting;
/* merge base calculation */ /* the pushes and hides */
git_commit_list_node *one; git_commit_list *user_input;
git_vector twos;
/* hide callback */ /* hide callback */
git_revwalk_hide_cb hide_cb; git_revwalk_hide_cb hide_cb;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment