Commit 45dc219f by Edward Thomson Committed by GitHub

Merge pull request #3921 from libgit2/cmn/walk-limit-enough

Improve revision walk preparation logic
parents d11fcf86 fedc05c8
...@@ -15,6 +15,8 @@ v0.24 + 1 ...@@ -15,6 +15,8 @@ v0.24 + 1
* Support for reading and writing git index v4 files * Support for reading and writing git index v4 files
* Improve the performance of the revwalk and bring us closer to git's code.
### API additions ### API additions
* You can now get the user-agent used by libgit2 using the * You can now get the user-agent used by libgit2 using the
......
...@@ -25,17 +25,15 @@ GIT_BEGIN_DECL ...@@ -25,17 +25,15 @@ GIT_BEGIN_DECL
*/ */
typedef enum { typedef enum {
/** /**
* Sort the repository contents in no particular ordering; * Sort the output with the same default time-order method from git.
* this sorting is arbitrary, implementation-specific
* and subject to change at any time.
* This is the default sorting for new walkers. * This is the default sorting for new walkers.
*/ */
GIT_SORT_NONE = 0, GIT_SORT_NONE = 0,
/** /**
* Sort the repository contents in topological order * Sort the repository contents in topological order (parents before
* (parents before children); this sorting mode * children); this sorting mode can be combined with time sorting to
* can be combined with time sorting. * produce git's "time-order".
*/ */
GIT_SORT_TOPOLOGICAL = 1 << 0, GIT_SORT_TOPOLOGICAL = 1 << 0,
......
...@@ -13,10 +13,15 @@ ...@@ -13,10 +13,15 @@
int git_commit_list_time_cmp(const void *a, const void *b) int git_commit_list_time_cmp(const void *a, const void *b)
{ {
const git_commit_list_node *commit_a = a; int64_t time_a = ((git_commit_list_node *) a)->time;
const git_commit_list_node *commit_b = b; int64_t time_b = ((git_commit_list_node *) b)->time;
return (commit_a->time < commit_b->time); if (time_a < time_b)
return 1;
if (time_a > time_b)
return -1;
return 0;
} }
git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p)
......
...@@ -28,6 +28,7 @@ typedef struct git_commit_list_node { ...@@ -28,6 +28,7 @@ typedef struct git_commit_list_node {
uninteresting:1, uninteresting:1,
topo_delay:1, topo_delay:1,
parsed:1, parsed:1,
added:1,
flags : FLAG_BITS; flags : FLAG_BITS;
unsigned short in_degree; unsigned short in_degree;
......
...@@ -93,7 +93,7 @@ int git_pqueue_insert(git_pqueue *pq, void *item) ...@@ -93,7 +93,7 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
(void)git_pqueue_pop(pq); (void)git_pqueue_pop(pq);
} }
if (!(error = git_vector_insert(pq, item))) if (!(error = git_vector_insert(pq, item)) && pq->_cmp)
pqueue_up(pq, pq->length - 1); pqueue_up(pq, pq->length - 1);
return error; return error;
...@@ -101,9 +101,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item) ...@@ -101,9 +101,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
void *git_pqueue_pop(git_pqueue *pq) void *git_pqueue_pop(git_pqueue *pq)
{ {
void *rval = git_pqueue_get(pq, 0); void *rval;
if (git_pqueue_size(pq) > 1) { if (!pq->_cmp) {
rval = git_vector_last(pq);
} else {
rval = git_pqueue_get(pq, 0);
}
if (git_pqueue_size(pq) > 1 && pq->_cmp) {
/* move last item to top of heap, shrink, and push item down */ /* move last item to top of heap, shrink, and push item down */
pq->contents[0] = git_vector_last(pq); pq->contents[0] = git_vector_last(pq);
git_vector_pop(pq); git_vector_pop(pq);
......
...@@ -35,6 +35,7 @@ extern int git_pqueue_init( ...@@ -35,6 +35,7 @@ extern int git_pqueue_init(
#define git_pqueue_clear git_vector_clear #define git_pqueue_clear git_vector_clear
#define git_pqueue_size git_vector_length #define git_pqueue_size git_vector_length
#define git_pqueue_get git_vector_get #define git_pqueue_get git_vector_get
#define git_pqueue_reverse git_vector_reverse
/** /**
* Insert a new item into the queue * Insert a new item into the queue
......
...@@ -586,7 +586,7 @@ static int rebase_init_operations( ...@@ -586,7 +586,7 @@ static int rebase_init_operations(
(error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0) (error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0)
goto done; goto done;
git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME); git_revwalk_sorting(revwalk, GIT_SORT_REVERSE);
while ((error = git_revwalk_next(&id, revwalk)) == 0) { while ((error = git_revwalk_next(&id, revwalk)) == 0) {
if ((error = git_commit_lookup(&commit, repo, &id)) < 0) if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "revwalk.h" #include "revwalk.h"
#include "git2/revparse.h" #include "git2/revparse.h"
#include "merge.h" #include "merge.h"
#include "vector.h"
GIT__USE_OIDMAP GIT__USE_OIDMAP
...@@ -41,97 +42,6 @@ git_commit_list_node *git_revwalk__commit_lookup( ...@@ -41,97 +42,6 @@ git_commit_list_node *git_revwalk__commit_lookup(
return commit; return commit;
} }
typedef git_array_t(git_commit_list_node*) commit_list_node_array;
static bool interesting_arr(commit_list_node_array arr)
{
git_commit_list_node **n;
size_t i = 0, size;
size = git_array_size(arr);
for (i = 0; i < size; i++) {
n = git_array_get(arr, i);
if (!*n)
break;
if (!(*n)->uninteresting)
return true;
}
return false;
}
static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit)
{
int error;
unsigned short i;
commit_list_node_array pending = GIT_ARRAY_INIT;
git_commit_list_node **tmp;
assert(commit);
do {
commit->uninteresting = 1;
if ((error = git_commit_list_parse(walk, commit)) < 0)
return error;
for (i = 0; i < commit->out_degree; ++i)
if (!commit->parents[i]->uninteresting) {
git_commit_list_node **node = git_array_alloc(pending);
GITERR_CHECK_ALLOC(node);
*node = commit->parents[i];
}
tmp = git_array_pop(pending);
commit = tmp ? *tmp : NULL;
} while (commit != NULL && !interesting_arr(pending));
git_array_clear(pending);
return 0;
}
static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide)
{
int error;
if (!hide && walk->hide_cb)
hide = walk->hide_cb(&commit->oid, walk->hide_cb_payload);
if (hide && mark_uninteresting(walk, commit) < 0)
return -1;
if (commit->seen)
return 0;
commit->seen = 1;
if ((error = git_commit_list_parse(walk, commit)) < 0)
return error;
if (!hide)
return walk->enqueue(walk, commit);
return 0;
}
static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commit)
{
unsigned short i, max;
int error = 0;
max = commit->out_degree;
if (walk->first_parent && commit->out_degree)
max = 1;
for (i = 0; i < max && !error; ++i)
error = process_commit(walk, commit->parents[i], commit->uninteresting);
return error;
}
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob) static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
{ {
git_oid commit_id; git_oid commit_id;
...@@ -321,17 +231,12 @@ static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *com ...@@ -321,17 +231,12 @@ static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *com
static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk) static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk)
{ {
int error;
git_commit_list_node *next; git_commit_list_node *next;
while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) if ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {
if (!next->uninteresting) { *object_out = next;
if ((error = process_commit_parents(walk, next)) < 0) return 0;
return error; }
*object_out = next;
return 0;
}
giterr_clear(); giterr_clear();
return GIT_ITEROVER; return GIT_ITEROVER;
...@@ -339,17 +244,15 @@ static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk ...@@ -339,17 +244,15 @@ static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk
static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk *walk) static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk *walk)
{ {
int error;
git_commit_list_node *next; git_commit_list_node *next;
while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) {
/* Some commits might become uninteresting after being added to the list */
if (!next->uninteresting) { if (!next->uninteresting) {
if ((error = process_commit_parents(walk, next)) < 0)
return error;
*object_out = next; *object_out = next;
return 0; return 0;
} }
}
giterr_clear(); giterr_clear();
return GIT_ITEROVER; return GIT_ITEROVER;
...@@ -358,121 +261,283 @@ static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk ...@@ -358,121 +261,283 @@ static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk
static int revwalk_next_toposort(git_commit_list_node **object_out, git_revwalk *walk) static int revwalk_next_toposort(git_commit_list_node **object_out, git_revwalk *walk)
{ {
git_commit_list_node *next; git_commit_list_node *next;
unsigned short i, max;
for (;;) { while ((next = git_commit_list_pop(&walk->iterator_topo)) != NULL) {
next = git_commit_list_pop(&walk->iterator_topo); /* Some commits might become uninteresting after being added to the list */
if (next == NULL) { if (!next->uninteresting) {
giterr_clear(); *object_out = next;
return GIT_ITEROVER; return 0;
} }
}
if (next->in_degree > 0) { giterr_clear();
next->topo_delay = 1; return GIT_ITEROVER;
continue; }
static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk)
{
*object_out = git_commit_list_pop(&walk->iterator_reverse);
return *object_out ? 0 : GIT_ITEROVER;
}
static void mark_parents_uninteresting(git_commit_list_node *commit)
{
unsigned short i;
git_commit_list *parents = NULL;
for (i = 0; i < commit->out_degree; i++)
git_commit_list_insert(commit->parents[i], &parents);
while (parents) {
git_commit_list_node *commit = git_commit_list_pop(&parents);
while (commit) {
if (commit->uninteresting)
break;
commit->uninteresting = 1;
/*
* If we've reached this commit some other way
* already, we need to mark its parents uninteresting
* as well.
*/
if (!commit->parents)
break;
for (i = 0; i < commit->out_degree; i++)
git_commit_list_insert(commit->parents[i], &parents);
commit = commit->parents[0];
} }
}
}
static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, git_commit_list **list)
{
unsigned short i;
int error;
max = next->out_degree; if (commit->added)
if (walk->first_parent && next->out_degree) return 0;
max = 1;
for (i = 0; i < max; ++i) { commit->added = 1;
git_commit_list_node *parent = next->parents[i];
/*
* Go full on in the uninteresting case as we want to include
* as many of these as we can.
*
* Usually we haven't parsed the parent of a parent, but if we
* have it we reached it via other means so we want to mark
* its parents recursively too.
*/
if (commit->uninteresting) {
for (i = 0; i < commit->out_degree; i++) {
git_commit_list_node *p = commit->parents[i];
p->uninteresting = 1;
if (--parent->in_degree == 0 && parent->topo_delay) { /* git does it gently here, but we don't like missing objects */
parent->topo_delay = 0; if ((error = git_commit_list_parse(walk, p)) < 0)
if (git_commit_list_insert(parent, &walk->iterator_topo) == NULL) return error;
return -1;
} if (p->parents)
mark_parents_uninteresting(p);
p->seen = 1;
git_commit_list_insert_by_date(p, list);
} }
*object_out = next;
return 0; return 0;
} }
/*
* Now on to what we do if the commit is indeed
* interesting. Here we do want things like first-parent take
* effect as this is what we'll be showing.
*/
for (i = 0; i < commit->out_degree; i++) {
git_commit_list_node *p = commit->parents[i];
if ((error = git_commit_list_parse(walk, p)) < 0)
return error;
if (walk->hide_cb && walk->hide_cb(&p->oid, walk->hide_cb_payload))
continue;
if (!p->seen) {
p->seen = 1;
git_commit_list_insert_by_date(p, list);
}
if (walk->first_parent)
break;
}
return 0;
} }
static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk) static int everybody_uninteresting(git_commit_list *orig)
{ {
*object_out = git_commit_list_pop(&walk->iterator_reverse); git_commit_list *list = orig;
return *object_out ? 0 : GIT_ITEROVER;
while (list) {
git_commit_list_node *commit = list->item;
list = list->next;
if (!commit->uninteresting)
return 0;
}
return 1;
} }
/* How many unintersting commits we want to look at after we run out of interesting ones */
#define SLOP 5
static int interesting(git_pqueue *list) static int still_interesting(git_commit_list *list, int64_t time, int slop)
{ {
size_t i; /* The empty list is pretty boring */
if (!list)
return 0;
for (i = 0; i < git_pqueue_size(list); i++) { /*
git_commit_list_node *commit = git_pqueue_get(list, i); * If the destination list has commits with an earlier date
if (!commit->uninteresting) * than our source we want to continue looking.
return 1; */
} if (time <= list->item->time)
return SLOP;
return 0; /* If we find interesting commits, we reset the slop count */
if (!everybody_uninteresting(list))
return SLOP;
/* Everything's uninteresting, reduce the count */
return slop - 1;
} }
static int contains(git_pqueue *list, git_commit_list_node *node) static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits)
{ {
size_t i; int error, slop = SLOP;
int64_t time = ~0ll;
git_commit_list *list = commits;
git_commit_list *newlist = NULL;
git_commit_list **p = &newlist;
while (list) {
git_commit_list_node *commit = git_commit_list_pop(&list);
if ((error = add_parents_to_list(walk, commit, &list)) < 0)
return error;
if (commit->uninteresting) {
mark_parents_uninteresting(commit);
slop = still_interesting(list, time, slop);
if (slop)
continue;
break;
}
if (!commit->uninteresting && walk->hide_cb && walk->hide_cb(&commit->oid, walk->hide_cb_payload))
continue;
for (i = 0; i < git_pqueue_size(list); i++) { time = commit->time;
git_commit_list_node *commit = git_pqueue_get(list, i); p = &git_commit_list_insert(commit, p)->next;
if (commit == node)
return 1;
} }
git_commit_list_free(&list);
*out = newlist;
return 0; return 0;
} }
static int premark_uninteresting(git_revwalk *walk) static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, git_commit_list *list)
{ {
int error = 0; git_commit_list *ll = NULL, *newlist, **pptr;
git_commit_list_node *next;
git_pqueue queue;
git_vector_cmp queue_cmp = NULL;
unsigned short i; unsigned short i;
git_pqueue q; int error;
git_commit_list *list;
git_commit_list_node *commit, *parent;
if ((error = git_pqueue_init(&q, 0, 8, git_commit_list_time_cmp)) < 0) if (walk->sorting & GIT_SORT_TIME)
return error; queue_cmp = git_commit_list_time_cmp;
for (list = walk->user_input; list; list = list->next) { if ((error = git_pqueue_init(&queue, 0, 8, queue_cmp)))
if ((error = git_commit_list_parse(walk, list->item)) < 0) return error;
goto cleanup;
if ((error = git_pqueue_insert(&q, list->item)) < 0) /*
goto cleanup; * Start by resetting the in-degree to 1 for the commits in
* our list. We want to go through this list again, so we
* store it in the commit list as we extract it from the lower
* machinery.
*/
for (ll = list; ll; ll = ll->next) {
ll->item->in_degree = 1;
} }
while (interesting(&q)) { /*
commit = git_pqueue_pop(&q); * Count up how many children each commit has. We limit
* ourselves to those commits in the original list (in-degree
for (i = 0; i < commit->out_degree; i++) { * of 1) avoiding setting it for any parent that was hidden.
parent = commit->parents[i]; */
for(ll = list; ll; ll = ll->next) {
for (i = 0; i < ll->item->out_degree; ++i) {
git_commit_list_node *parent = ll->item->parents[i];
if (parent->in_degree)
parent->in_degree++;
}
}
if ((error = git_commit_list_parse(walk, parent)) < 0) /*
* Now we find the tips i.e. those not reachable from any other node
* i.e. those which still have an in-degree of 1.
*/
for(ll = list; ll; ll = ll->next) {
if (ll->item->in_degree == 1) {
if ((error = git_pqueue_insert(&queue, ll->item)))
goto cleanup; goto cleanup;
}
}
/*
* We need to output the tips in the order that they came out of the
* traversal, so if we're not doing time-sorting, we need to reverse the
* pqueue in order to get them to come out as we inserted them.
*/
if ((walk->sorting & GIT_SORT_TIME) == 0)
git_pqueue_reverse(&queue);
if (commit->uninteresting)
parent->uninteresting = 1;
if (contains(&q, parent)) pptr = &newlist;
newlist = NULL;
while ((next = git_pqueue_pop(&queue)) != NULL) {
for (i = 0; i < next->out_degree; ++i) {
git_commit_list_node *parent = next->parents[i];
if (parent->in_degree == 0)
continue; continue;
if ((error = git_pqueue_insert(&q, parent)) < 0) if (--parent->in_degree == 1) {
goto cleanup; if ((error = git_pqueue_insert(&queue, parent)))
goto cleanup;
}
} }
/* All the children of 'item' have been emitted (since we got to it via the priority queue) */
next->in_degree = 0;
pptr = &git_commit_list_insert(next, pptr)->next;
} }
*out = newlist;
error = 0;
cleanup: cleanup:
git_pqueue_free(&q); git_pqueue_free(&queue);
return error; return error;
} }
static int prepare_walk(git_revwalk *walk) static int prepare_walk(git_revwalk *walk)
{ {
int error; int error;
git_commit_list *list; git_commit_list *list, *commits = NULL;
git_commit_list_node *next; git_commit_list_node *next;
/* If there were no pushes, we know that the walk is already over */ /* If there were no pushes, we know that the walk is already over */
...@@ -481,32 +546,42 @@ static int prepare_walk(git_revwalk *walk) ...@@ -481,32 +546,42 @@ static int prepare_walk(git_revwalk *walk)
return GIT_ITEROVER; return GIT_ITEROVER;
} }
if (walk->did_hide && (error = premark_uninteresting(walk)) < 0)
return error;
for (list = walk->user_input; list; list = list->next) { for (list = walk->user_input; list; list = list->next) {
if (process_commit(walk, list->item, list->item->uninteresting) < 0) git_commit_list_node *commit = list->item;
return -1; if ((error = git_commit_list_parse(walk, commit)) < 0)
} return error;
if (commit->uninteresting)
mark_parents_uninteresting(commit);
if (walk->sorting & GIT_SORT_TOPOLOGICAL) { if (!commit->seen) {
unsigned short i; commit->seen = 1;
git_commit_list_insert(commit, &commits);
}
}
while ((error = walk->get_next(&next, walk)) == 0) { if ((error = limit_list(&commits, walk, commits)) < 0)
for (i = 0; i < next->out_degree; ++i) { return error;
git_commit_list_node *parent = next->parents[i];
parent->in_degree++;
}
if (git_commit_list_insert(next, &walk->iterator_topo) == NULL) if (walk->sorting & GIT_SORT_TOPOLOGICAL) {
return -1; error = sort_in_topological_order(&walk->iterator_topo, walk, commits);
} git_commit_list_free(&commits);
if (error != GIT_ITEROVER) if (error < 0)
return error; return error;
walk->get_next = &revwalk_next_toposort; walk->get_next = &revwalk_next_toposort;
} else if (walk->sorting & GIT_SORT_TIME) {
for (list = commits; list && !error; list = list->next)
error = walk->enqueue(walk, list->item);
git_commit_list_free(&commits);
if (error < 0)
return error;
} else {
walk->iterator_rand = commits;
walk->get_next = revwalk_next_unsorted;
} }
if (walk->sorting & GIT_SORT_REVERSE) { if (walk->sorting & GIT_SORT_REVERSE) {
...@@ -632,6 +707,7 @@ void git_revwalk_reset(git_revwalk *walk) ...@@ -632,6 +707,7 @@ 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->added = 0;
commit->flags = 0; commit->flags = 0;
}); });
......
...@@ -401,3 +401,19 @@ int git_vector_verify_sorted(const git_vector *v) ...@@ -401,3 +401,19 @@ int git_vector_verify_sorted(const git_vector *v)
return 0; return 0;
} }
void git_vector_reverse(git_vector *v)
{
size_t a, b;
a = 0;
b = v->length - 1;
while (a < b) {
void *tmp = v->contents[a];
v->contents[a] = v->contents[b];
v->contents[b] = tmp;
a++;
b--;
}
}
...@@ -118,4 +118,9 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp) ...@@ -118,4 +118,9 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
/* Just use this in tests, not for realz. returns -1 if not sorted */ /* Just use this in tests, not for realz. returns -1 if not sorted */
int git_vector_verify_sorted(const git_vector *v); int git_vector_verify_sorted(const git_vector *v);
/**
* Reverse the vector in-place.
*/
void git_vector_reverse(git_vector *v);
#endif #endif
...@@ -376,3 +376,32 @@ void test_core_vector__grow_and_shrink(void) ...@@ -376,3 +376,32 @@ void test_core_vector__grow_and_shrink(void)
git_vector_free(&x); git_vector_free(&x);
} }
void test_core_vector__reverse(void)
{
git_vector v = GIT_VECTOR_INIT;
size_t i;
void *in1[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3};
void *out1[] = {(void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0};
void *in2[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3, (void *) 0x4};
void *out2[] = {(void *) 0x4, (void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0};
for (i = 0; i < 4; i++)
cl_git_pass(git_vector_insert(&v, in1[i]));
git_vector_reverse(&v);
for (i = 0; i < 4; i++)
cl_assert_equal_p(out1[i], git_vector_get(&v, i));
git_vector_clear(&v);
for (i = 0; i < 5; i++)
cl_git_pass(git_vector_insert(&v, in2[i]));
git_vector_reverse(&v);
for (i = 0; i < 5; i++)
cl_assert_equal_p(out2[i], git_vector_get(&v, i));
}
...@@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data) ...@@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data)
/* /*
* $ git --git-dir tests/resources/testrepo.git count-objects --verbose * $ git --git-dir tests/resources/testrepo.git count-objects --verbose
* count: 47 * count: 60
* size: 4 * size: 240
* in-pack: 1640 * in-pack: 1640
* packs: 3 * packs: 3
* size-pack: 425 * size-pack: 425
...@@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void) ...@@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void)
git_repository_odb(&_odb, _repo); git_repository_odb(&_odb, _repo);
cl_git_pass(git_odb_foreach(_odb, foreach_cb, &nobj)); cl_git_pass(git_odb_foreach(_odb, foreach_cb, &nobj));
cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */
} }
void test_odb_foreach__one_pack(void) void test_odb_foreach__one_pack(void)
...@@ -118,7 +118,7 @@ void test_odb_foreach__files_in_objects_dir(void) ...@@ -118,7 +118,7 @@ void test_odb_foreach__files_in_objects_dir(void)
cl_git_pass(git_repository_odb(&odb, repo)); cl_git_pass(git_repository_odb(&odb, repo));
cl_git_pass(git_odb_foreach(odb, foreach_cb, &nobj)); cl_git_pass(git_odb_foreach(odb, foreach_cb, &nobj));
cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */
git_odb_free(odb); git_odb_free(odb);
git_repository_free(repo); git_repository_free(repo);
......
...@@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = { ...@@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = {
{4, 5, 2, 1, 3, 0} {4, 5, 2, 1, 3, 0}
}; };
/* This is specified unsorted, so both combinations are possible */
static const int commit_sorting_segment[][6] = { static const int commit_sorting_segment[][6] = {
{1, 2, -1, -1, -1, -1} {1, 2, -1, -1, -1, -1}, {2, 1, -1, -1, -1, -1}
}; };
#define commit_count 6 #define commit_count 6
...@@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void) ...@@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void)
cl_git_pass(git_revwalk_push_glob(_walk, "heads")); cl_git_pass(git_revwalk_push_glob(_walk, "heads"));
while (git_revwalk_next(&oid, _walk) == 0) { while (git_revwalk_next(&oid, _walk) == 0)
i++; i++;
}
/* git log --branches --oneline | wc -l => 14 */ /* git log --branches --oneline | wc -l => 14 */
cl_assert_equal_i(i, 14); cl_assert_equal_i(i, 14);
...@@ -338,7 +338,7 @@ void test_revwalk_basic__push_range(void) ...@@ -338,7 +338,7 @@ void test_revwalk_basic__push_range(void)
git_revwalk_reset(_walk); git_revwalk_reset(_walk);
git_revwalk_sorting(_walk, 0); git_revwalk_sorting(_walk, 0);
cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e"));
cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 2));
} }
void test_revwalk_basic__push_mixed(void) void test_revwalk_basic__push_mixed(void)
...@@ -473,3 +473,51 @@ void test_revwalk_basic__big_timestamp(void) ...@@ -473,3 +473,51 @@ void test_revwalk_basic__big_timestamp(void)
git_signature_free(sig); git_signature_free(sig);
} }
/* Ensure that we correctly hide a commit that is (timewise) older
* than the commits that we are showing.
*
* % git rev-list 8e73b76..bd75801
* bd758010071961f28336333bc41e9c64c9a64866
*/
void test_revwalk_basic__old_hidden_commit_one(void)
{
git_oid new_id, old_id, oid;
revwalk_basic_setup_walk("testrepo.git");
cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_pass(git_revwalk_push(_walk, &new_id));
cl_git_pass(git_oid_fromstr(&old_id, "8e73b769e97678d684b809b163bebdae2911720f"));
cl_git_pass(git_revwalk_hide(_walk, &old_id));
cl_git_pass(git_revwalk_next(&oid, _walk));
cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk));
}
/* Ensure that we correctly hide a commit that is (timewise) older
* than the commits that we are showing.
*
* % git rev-list bd75801 ^b91e763
* bd758010071961f28336333bc41e9c64c9a64866
*/
void test_revwalk_basic__old_hidden_commit_two(void)
{
git_oid new_id, old_id, oid;
revwalk_basic_setup_walk("testrepo.git");
cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_pass(git_revwalk_push(_walk, &new_id));
cl_git_pass(git_oid_fromstr(&old_id, "b91e763008b10db366442469339f90a2b8400d0a"));
cl_git_pass(git_revwalk_hide(_walk, &old_id));
cl_git_pass(git_revwalk_next(&oid, _walk));
cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk));
}
...@@ -158,6 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void) ...@@ -158,6 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void)
cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id)); cl_git_pass(git_revwalk_push(walk, &_head_id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback */ /* Add hide callback */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL)); cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL));
...@@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void) ...@@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void)
cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id)); cl_git_pass(git_revwalk_push(walk, &_head_id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback, pass id of parent of initial commit as payload data */ /* Add hide callback, pass id of parent of initial commit as payload data */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_use_payload_cb, &commit_ids[5])); cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_use_payload_cb, &commit_ids[5]));
......
...@@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void) ...@@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void)
git_oid_fromstr(&id, commit_head); git_oid_fromstr(&id, commit_head);
cl_git_pass(git_revwalk_push(walk, &id)); cl_git_pass(git_revwalk_push(walk, &id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
git_revwalk_simplify_first_parent(walk); git_revwalk_simplify_first_parent(walk);
i = 0; i = 0;
......
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