Commit 704b55cc by Carlos Martín Nieto

revwalk: don't try to find merge bases when there can be none

As a way to speed up the cases where we need to hide some commits, we
find out what the merge bases are so we know to stop marking commits as
uninteresting and avoid walking down a potentially very large amount of
commits which we will never see. There are however two oversights in
current code.

The merge-base finding algorithm fails to recognize that if it is only
given one commit, there can be no merge base. It instead walks down the
whole ancestor chain needlessly. Make it return an empty list
immediately in this situation.

The revwalk does not know whether the user has asked to hide any commits
at all. In situation where the user pushes multiple commits but doesn't
hide any, the above fix wouldn't do the trick. Keep track of whether the
user wants to hide any commits and only run the merge-base finding
algorithm when it's needed.
parent f29e4899
...@@ -205,6 +205,12 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l ...@@ -205,6 +205,12 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
git_commit_list *result = NULL, *tmp = NULL; git_commit_list *result = NULL, *tmp = NULL;
git_pqueue list; git_pqueue list;
/* If there's only the one commit, there can be no merge bases */
if (twos->length == 0) {
*out = NULL;
return 0;
}
/* if the commit is repeated, we have a our merge base already */ /* if the commit is repeated, we have a our merge base already */
git_vector_foreach(twos, i, two) { git_vector_foreach(twos, i, two) {
if (one == two) if (one == two)
......
...@@ -141,6 +141,9 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, ...@@ -141,6 +141,9 @@ 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;
commit->uninteresting = uninteresting; commit->uninteresting = uninteresting;
if (walk->one == NULL && !uninteresting) { if (walk->one == NULL && !uninteresting) {
walk->one = commit; walk->one = commit;
...@@ -390,11 +393,18 @@ static int prepare_walk(git_revwalk *walk) ...@@ -390,11 +393,18 @@ static int prepare_walk(git_revwalk *walk)
return GIT_ITEROVER; return GIT_ITEROVER;
} }
/* first figure out what the merge bases are */ /*
* If the user asked to hide commits, we need to figure out
* what the merge bases are so we can know when we can stop
* marking parents uninteresting.
*/
if (walk->did_hide) {
if (git_merge__bases_many(&bases, walk, walk->one, &walk->twos) < 0) if (git_merge__bases_many(&bases, walk, walk->one, &walk->twos) < 0)
return -1; return -1;
git_commit_list_free(&bases); git_commit_list_free(&bases);
}
if (process_commit(walk, walk->one, walk->one->uninteresting) < 0) if (process_commit(walk, walk->one, walk->one->uninteresting) < 0)
return -1; return -1;
......
...@@ -32,7 +32,8 @@ struct git_revwalk { ...@@ -32,7 +32,8 @@ 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;
unsigned int sorting; unsigned int sorting;
/* merge base calculation */ /* merge base calculation */
......
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