From 565fb8dcd41eefb373ec6dc71dc2f19884d29cdc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 25 Jun 2016 20:02:45 -0400 Subject: [PATCH 01/13] revwalk: introduce tests that hide old commits Introduce some tests that show some commits, while hiding some commits that have a timestamp older than the common ancestors of these two commits. --- tests/odb/foreach.c | 8 +-- .../43/da5ec3274dd061df152ff5e69853d562b01842 | Bin 0 -> 193 bytes .../43/e968a905a821532069bb413801d35b200631cf | Bin 0 -> 158 bytes .../5d/0f8f7891e872d284beef38254882dc879b2602 | Bin 0 -> 149 bytes .../5f/34cd6e3285089647165983482cf90873d50940 | Bin 0 -> 37 bytes .../8e/73b769e97678d684b809b163bebdae2911720f | Bin 0 -> 209 bytes .../b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b | Bin 0 -> 184 bytes .../b2/35959d89084af8d3544fbdf675e47944f86524 | Bin 0 -> 77 bytes .../b9/1e763008b10db366442469339f90a2b8400d0a | Bin 0 -> 206 bytes .../bd/758010071961f28336333bc41e9c64c9a64866 | Bin 0 -> 162 bytes .../db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 | Bin 0 -> 192 bytes .../db/793a00a5615eca1aac97e42b3a68b1acfa8bfd | Bin 0 -> 193 bytes .../db/c0be625bed24b5d8f5d9a927484f2065d321af | Bin 0 -> 175 bytes .../f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace | Bin 0 -> 38 bytes tests/revwalk/basic.c | 48 ++++++++++++++++++ 15 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 create mode 100644 tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf create mode 100644 tests/resources/testrepo.git/objects/5d/0f8f7891e872d284beef38254882dc879b2602 create mode 100644 tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 create mode 100644 tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f create mode 100644 tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b create mode 100644 tests/resources/testrepo.git/objects/b2/35959d89084af8d3544fbdf675e47944f86524 create mode 100644 tests/resources/testrepo.git/objects/b9/1e763008b10db366442469339f90a2b8400d0a create mode 100644 tests/resources/testrepo.git/objects/bd/758010071961f28336333bc41e9c64c9a64866 create mode 100644 tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 create mode 100644 tests/resources/testrepo.git/objects/db/793a00a5615eca1aac97e42b3a68b1acfa8bfd create mode 100644 tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af create mode 100644 tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace diff --git a/tests/odb/foreach.c b/tests/odb/foreach.c index 12b81b4f1..42d706467 100644 --- a/tests/odb/foreach.c +++ b/tests/odb/foreach.c @@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data) /* * $ git --git-dir tests/resources/testrepo.git count-objects --verbose - * count: 47 - * size: 4 + * count: 60 + * size: 240 * in-pack: 1640 * packs: 3 * size-pack: 425 @@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void) git_repository_odb(&_odb, _repo); 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) @@ -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_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_repository_free(repo); diff --git a/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 b/tests/resources/testrepo.git/objects/43/da5ec3274dd061df152ff5e69853d562b01842 new file mode 100644 index 0000000000000000000000000000000000000000..298feece49d7e4f368998e5147893df4f2c34a12 GIT binary patch literal 193 zcmV;y06zbC0WFSQYC|CqM*Hk4W&Ib~s=oik{7WdC*>g^Sj_7;`FVBsXalwz&x;p72t v`8$pbAGNpJ!{$|d(D}O0dQbnpbq;;d+ArTOU!)Nas_@r=ez5of)#OSW3n64z literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf b/tests/resources/testrepo.git/objects/43/e968a905a821532069bb413801d35b200631cf new file mode 100644 index 0000000000000000000000000000000000000000..ec04abf681024c5e3b293261ef7d871c5da8b66c GIT binary patch literal 158 zcmV;P0Ac@l0iBLZ3IZ_@1zqP9eE}t(PA35oH{QSt7X?pdSiy9jSV&wAEd`P`C=^Ml*&ZTGP*E^C#zAsV&koY$3W7ltP)c87L!rRTaLjw zG>Iwt0izRf?{jT%E1%d3+~>N!>jq~Y_D9#p(&s&$a$PT=v@@D0D1xJOQi@^6%g+Dy MqCSiG07F=Q|_FfcPQQ3!H%bn$g%5N`dHvVMD1*wTH+ot*d0HmhE8 zio?VJ2ow^N7(P11yjPSt(6h?$`BvBen~c_Mm~j}YJ*g-$FF7MVEi)%oucV@c!F6Zz zKC|sM>>YRJ?Ae~PyWvmuhH$9Tywq~Ak`Id(GC7}0`DuFl@txD1Z@NEb-#P~X4@N+M D#z04o literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 b/tests/resources/testrepo.git/objects/5f/34cd6e3285089647165983482cf90873d50940 new file mode 100644 index 0000000000000000000000000000000000000000..b1df3bdd5cf408c6a576fa3041938b194b268734 GIT binary patch literal 37 vcmV+=0NVd}0ZYosPf{>4W(dj1ELH%b#5{%koD_wmqQt!93`H&goVE$TEmshD literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f b/tests/resources/testrepo.git/objects/8e/73b769e97678d684b809b163bebdae2911720f new file mode 100644 index 0000000000000000000000000000000000000000..d75977a25d492bdfcfafc9ea58982cfd5beada91 GIT binary patch literal 209 zcmV;?051P{0iBS&YQ!)Qgj4$|w!11}^}7~?J|@&YUE`fNB`L6*tu$JgWm(hVOo z12d(r>(arYdFf3RBp1vYZOAIt=OE)0ByqCjM?YDNL7X)_4d2{!>)@THIC8?kqcy>u zj+C=EZbTz4WQ!P`DSv*7PRKCJgo!By6H+XRd@N|al4?;ZboTSn=i1;yez*yI&2`=D z2Jd>(r@GyjJ|Fq5)b$F+lCxyI5AceFIGprc)%Cym;ZxgPAvfO2443`L&vW(*EL*Qo LA2R#`W_Mo1f`V*1 literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b b/tests/resources/testrepo.git/objects/b2/04707bbc546a1a770ef6ced37c7089cc3bfe6b new file mode 100644 index 0000000000000000000000000000000000000000..f9ec61c1e2c805779a27b5ec0170af4d2c3b389e GIT binary patch literal 184 zcmV;p07w6L0WHp5io-Ar1mJznDRhA@{!tVQN+~RRg7yNAEjNL>UR;M>f1T2|LCiNO zl$_TFM$=cTBEX12B@&FuqaJw_lGz545NC~PR7tecWQIRq<6WiT`_Ff%bx2y%6F@pWYoZvB+9etT5d(tXFBocGN(t6p-7 j1F9lFCxs#2r13djB-Bl`UFwXBD&G1 znbAz`>$(iE);)|}6{J)w8pszFa>Yw*UQ$lPF1kh-yjU{1O&@vJZ2$)=Y;u-{DRc71 zr%)5SP?4OnYE`cM>vvXDh&iFpk&L%TV=BcN8_|gMg%E=^wN3dx=Dx$LeCA!?eeUb6 zZ}6-K{Z=oRWz6^TRQq}cLu`qSa~>X%5vPM5uZI3NKfURGQTVBW(_crQVA)28eifR& I02(=EX>-VC7sl_|4+y#`=hEw^H@Na)e{`Q;W7(!l>h%W7dQZVQqu?y9l;W_*<=}sN Q(Rhcn#5S||0*`k|){{(4dH?_b literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 b/tests/resources/testrepo.git/objects/db/4df74a2fc340a0d0cb0cafc0db471fdfff1048 new file mode 100644 index 0000000000000000000000000000000000000000..5f3d50efa28b5b1c8ec01cf0b9a23deae7384cd9 GIT binary patch literal 192 zcmV;x06+hD0WHo^N(3mvq6uhFO z)w&OGo*qV51*h>A)+ zAuENm7fzN{$i&+yt;4&tG2pdCX$L%Cr!a3a7 zYTXAIYo12W8G@z|Rz@EpT3wvZ2?NVgI5^9hSF6bqCH2KU-v$sHG-An#U=d8>b162K zlEp@k!Xn8aEsBq^wGQvGjRBX9W4po2J^sS^T6zC`j;+3eHlDoE%d)}=J))ZHd^mE4 vxAe_D!N=C>{bA=>e9-y2kL{3upPUOmtiey8rmq-EJNnq*ucUqeBnL|0%C}%Q literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af b/tests/resources/testrepo.git/objects/db/c0be625bed24b5d8f5d9a927484f2065d321af new file mode 100644 index 0000000000000000000000000000000000000000..b966b0b2fda7c481c94a110b27d32c6f7484aa4c GIT binary patch literal 175 zcmV;g08syU0V^p=O;s>7H)1d}FfcPQQ3!H%bn$g%5N`dHvVMD1*wTH+ot*d0HmhE8 zio?VJ2ow^N7(P11yjPSt(6h?$`BvBen~c_Mm~j}YJ*g-$FF7MVEi)%oucV@c!F6Zz zKC|sM>>YRJ?Ae~PyWvmuhH$9Tywq~Al3$)1%BL$&TpPh$5b$Yve97ZJ d@g`^Uj9NLSxr;?Md+7Y+D89<+008njM;gt0RR;h7 literal 0 HcmV?d00001 diff --git a/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace b/tests/resources/testrepo.git/objects/f0/a2a10243ca64f935dbe3dccb89ec8bf16bdace new file mode 100644 index 0000000000000000000000000000000000000000..1b299dc257b712a486bb7ec5bd07720d88001374 GIT binary patch literal 38 ucmbxW_q Date: Thu, 21 Jul 2016 01:24:12 -0600 Subject: [PATCH 02/13] revwalk: get closer to git We had some home-grown logic to figure out which objects to show during the revision walk, but it was rather inefficient, looking over the same list multiple times to figure out when we had run out of interesting commits. We now use the lists in a smarter way. We also introduce the slop mechanism to determine when to stpo looking. When we run out of interesting objects, we continue preparing the walk for another 5 rounds in order to make it less likely that we miss objects in situations with complex graphs. --- src/commit_list.h | 1 + src/revwalk.c | 231 ++++++++++++++++++++++++++++++--------- tests/revwalk/basic.c | 8 +- tests/revwalk/hidecb.c | 2 + tests/revwalk/simplify.c | 1 + 5 files changed, 189 insertions(+), 54 deletions(-) diff --git a/src/commit_list.h b/src/commit_list.h index a6967bcef..9746c2801 100644 --- a/src/commit_list.h +++ b/src/commit_list.h @@ -28,6 +28,7 @@ typedef struct git_commit_list_node { uninteresting:1, topo_delay:1, parsed:1, + added:1, flags : FLAG_BITS; unsigned short in_degree; diff --git a/src/revwalk.c b/src/revwalk.c index 4815a1089..cc585ff4f 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -86,7 +86,7 @@ static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit) tmp = git_array_pop(pending); commit = tmp ? *tmp : NULL; - } while (commit != NULL && !interesting_arr(pending)); + } while (commit != NULL && interesting_arr(pending)); git_array_clear(pending); @@ -398,20 +398,6 @@ static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk * return *object_out ? 0 : GIT_ITEROVER; } - -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; @@ -425,54 +411,181 @@ static int contains(git_pqueue *list, git_commit_list_node *node) return 0; } -static int premark_uninteresting(git_revwalk *walk) +static void mark_parents_uninteresting(git_commit_list_node *commit) { - int error = 0; unsigned short i; - git_pqueue q; - git_commit_list *list; - git_commit_list_node *commit, *parent; + git_commit_list *parents = NULL; - if ((error = git_pqueue_init(&q, 0, 8, git_commit_list_time_cmp)) < 0) - return error; + for (i = 0; i < commit->out_degree; i++) + git_commit_list_insert(commit->parents[i], &parents); - 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; + while (parents) { + git_commit_list_node *commit = git_commit_list_pop(&parents); + while (commit) { if (commit->uninteresting) - parent->uninteresting = 1; + break; - if (contains(&q, parent)) - continue; + 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; - if ((error = git_pqueue_insert(&q, parent)) < 0) - goto cleanup; + for (i = 0; i < commit->out_degree; i++) + git_commit_list_insert(commit->parents[i], &parents); + commit = commit->parents[0]; } } +} -cleanup: - git_pqueue_free(&q); - return error; +static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, git_commit_list **list) +{ + unsigned short i; + int error; + + if (commit->added) + return 0; + + commit->added = 1; + + /* TODO: add the insertion callback here as well */ + + /* + * 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; + + /* git does it gently here, but we don't like missing objects */ + if ((error = git_commit_list_parse(walk, p)) < 0) + return error; + + if (p->parents) + mark_parents_uninteresting(p); + + p->seen = 1; + git_commit_list_insert_by_date(p, list); + } + + 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 everybody_uninteresting(git_commit_list *orig) +{ + git_commit_list *list = orig; + + while (list) { + git_commit_list_node *commit = list->item; + list = list->next; + if (commit->uninteresting) + continue; + + 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 still_interesting(git_commit_list *list, int64_t time, int slop) +{ + /* The empty list is pretty boring */ + if (!list) + return 0; + + /* + * If the destination list has commits with an earlier date + * than our source we want to continue looking. + */ + if (time <= list->item->time) + return SLOP; + + /* 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 limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits) +{ + 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; + + time = commit->time; + p = &git_commit_list_insert(commit, p)->next; + } + + *out = newlist; + return 0; } static int prepare_walk(git_revwalk *walk) { int error; - git_commit_list *list; + git_commit_list *list, *commits = NULL; git_commit_list_node *next; /* If there were no pushes, we know that the walk is already over */ @@ -481,12 +594,29 @@ static int prepare_walk(git_revwalk *walk) return GIT_ITEROVER; } - if (walk->did_hide && (error = premark_uninteresting(walk)) < 0) + for (list = walk->user_input; list; list = list->next) { + git_commit_list_node *commit = list->item; + if ((error = git_commit_list_parse(walk, commit)) < 0) + return error; + + if (commit->uninteresting) + mark_parents_uninteresting(commit); + + if (!commit->seen) { + commit->seen = 1; + git_commit_list_insert(commit, &commits); + } + } + + if ((error = limit_list(&commits, walk, commits)) < 0) return error; - for (list = walk->user_input; list; list = list->next) { - if (process_commit(walk, list->item, list->item->uninteresting) < 0) - return -1; + for (list = commits; list; list = list->next) { + if (list->item->uninteresting) + continue; + + if ((error = walk->enqueue(walk, list->item)) < 0) + return error; } @@ -632,6 +762,7 @@ void git_revwalk_reset(git_revwalk *walk) commit->in_degree = 0; commit->topo_delay = 0; commit->uninteresting = 0; + commit->added = 0; commit->flags = 0; }); diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c index 7559f72e9..89140bc54 100644 --- a/tests/revwalk/basic.c +++ b/tests/revwalk/basic.c @@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = { {4, 5, 2, 1, 3, 0} }; +/* This is specified unsorted, so both combinations are possible */ 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 @@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void) cl_git_pass(git_revwalk_push_glob(_walk, "heads")); - while (git_revwalk_next(&oid, _walk) == 0) { + while (git_revwalk_next(&oid, _walk) == 0) i++; - } /* git log --branches --oneline | wc -l => 14 */ cl_assert_equal_i(i, 14); @@ -338,7 +338,7 @@ void test_revwalk_basic__push_range(void) git_revwalk_reset(_walk); git_revwalk_sorting(_walk, 0); 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) diff --git a/tests/revwalk/hidecb.c b/tests/revwalk/hidecb.c index 14cf39afd..ab53ee780 100644 --- a/tests/revwalk/hidecb.c +++ b/tests/revwalk/hidecb.c @@ -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_push(walk, &_head_id)); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); /* Add hide callback */ cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL)); @@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void) cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_push(walk, &_head_id)); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); /* 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])); diff --git a/tests/revwalk/simplify.c b/tests/revwalk/simplify.c index f65ce6c59..6dd068a42 100644 --- a/tests/revwalk/simplify.c +++ b/tests/revwalk/simplify.c @@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void) git_oid_fromstr(&id, commit_head); cl_git_pass(git_revwalk_push(walk, &id)); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); git_revwalk_simplify_first_parent(walk); i = 0; From 0bd43371c27b5fee23768c1b369bf2c62601578f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 23 Sep 2016 12:42:33 +0200 Subject: [PATCH 03/13] vector, pqueue: add git_vector_reverse and git_pqueue_reverse This is a convenience function to reverse the contents of a vector and a pqueue in-place. The pqueue function is useful in the case where we're treating it as a LIFO queue. --- src/pqueue.h | 1 + src/vector.c | 16 ++++++++++++++++ src/vector.h | 5 +++++ tests/core/vector.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/src/pqueue.h b/src/pqueue.h index da7b74edf..76b14919e 100644 --- a/src/pqueue.h +++ b/src/pqueue.h @@ -35,6 +35,7 @@ extern int git_pqueue_init( #define git_pqueue_clear git_vector_clear #define git_pqueue_size git_vector_length #define git_pqueue_get git_vector_get +#define git_pqueue_reverse git_vector_reverse /** * Insert a new item into the queue diff --git a/src/vector.c b/src/vector.c index db1dcf89a..baec8036f 100644 --- a/src/vector.c +++ b/src/vector.c @@ -401,3 +401,19 @@ int git_vector_verify_sorted(const git_vector *v) 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--; + } +} diff --git a/src/vector.h b/src/vector.h index 96d149e16..cc4c314d5 100644 --- a/src/vector.h +++ b/src/vector.h @@ -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 */ int git_vector_verify_sorted(const git_vector *v); +/** + * Reverse the vector in-place. + */ +void git_vector_reverse(git_vector *v); + #endif diff --git a/tests/core/vector.c b/tests/core/vector.c index c351655a7..336254cce 100644 --- a/tests/core/vector.c +++ b/tests/core/vector.c @@ -376,3 +376,32 @@ void test_core_vector__grow_and_shrink(void) 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)); +} From 938f8e32ec3fa467454ac44c01b916d17e5731af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 23 Sep 2016 13:25:35 +0200 Subject: [PATCH 04/13] pqueue: support not having a comparison function In this case, we simply behave like a vector. --- src/pqueue.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pqueue.c b/src/pqueue.c index 54a60ca04..8cfc4390f 100644 --- a/src/pqueue.c +++ b/src/pqueue.c @@ -93,7 +93,7 @@ int git_pqueue_insert(git_pqueue *pq, void *item) (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); return error; @@ -101,9 +101,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item) 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 */ pq->contents[0] = git_vector_last(pq); git_vector_pop(pq); From 48c64362e43f5a11aeca6a6dd2950107d6c8adce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 27 Sep 2016 11:59:24 +0200 Subject: [PATCH 05/13] revwalk: port over the topological sorting After porting over the commit hiding and selection we were still left with mistmaching output due to the topologial sort. This ports the topological sorting code to make us match with our equivalent of `--date-order` and `--topo-order` against the output from `rev-list`. --- src/revwalk.c | 154 ++++++++++++++++++++++++++++------------- tests/revwalk/hidecb.c | 4 +- 2 files changed, 109 insertions(+), 49 deletions(-) diff --git a/src/revwalk.c b/src/revwalk.c index cc585ff4f..244061a42 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -357,39 +357,16 @@ 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) { - git_commit_list_node *next; - unsigned short i, max; + git_commit_list_node *node; - for (;;) { - next = git_commit_list_pop(&walk->iterator_topo); - if (next == NULL) { - giterr_clear(); - return GIT_ITEROVER; - } - - if (next->in_degree > 0) { - next->topo_delay = 1; - continue; - } - - - max = next->out_degree; - if (walk->first_parent && next->out_degree) - max = 1; - - for (i = 0; i < max; ++i) { - git_commit_list_node *parent = next->parents[i]; - - if (--parent->in_degree == 0 && parent->topo_delay) { - parent->topo_delay = 0; - if (git_commit_list_insert(parent, &walk->iterator_topo) == NULL) - return -1; - } - } - - *object_out = next; + node = git_commit_list_pop(&walk->iterator_topo); + if (node) { + *object_out = node; return 0; } + + giterr_clear(); + return GIT_ITEROVER; } static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk) @@ -453,8 +430,6 @@ static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, commit->added = 1; - /* TODO: add the insertion callback here as well */ - /* * Go full on in the uninteresting case as we want to include * as many of these as we can. @@ -494,7 +469,7 @@ static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, return error; if (walk->hide_cb && walk->hide_cb(&p->oid, walk->hide_cb_payload)) - continue; + continue; if (!p->seen) { p->seen = 1; @@ -578,10 +553,104 @@ static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list p = &git_commit_list_insert(commit, p)->next; } + git_commit_list_free(&list); *out = newlist; return 0; } +static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk) +{ + git_commit_list *list = NULL, *ll = NULL, *newlist, **pptr; + git_commit_list_node *next; + git_pqueue queue; + git_vector_cmp queue_cmp = NULL; + unsigned short i; + int error; + + if (walk->sorting & GIT_SORT_TIME) + queue_cmp = git_commit_list_time_cmp; + + if ((error = git_pqueue_init(&queue, 0, 8, queue_cmp))) + return error; + + /* + * 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. + */ + while ((error = walk->get_next(&next, walk)) == 0) { + next->in_degree = 1; + git_commit_list_insert(next, &list); + } + + if (error != GIT_ITEROVER) + goto cleanup; + + error = 0; + + /* + * Count up how many children each commit has. We limit + * ourselves to those commits in the original list (in-degree + * of 1) avoiding setting it for any parent that was hidden. + */ + 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++; + } + } + + /* + * 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; + } + } + + /* + * 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); + + + 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; + + if (--parent->in_degree == 1) { + 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: + git_commit_list_free(&list); + git_pqueue_free(&queue); + return error; +} + static int prepare_walk(git_revwalk *walk) { int error; @@ -615,25 +684,16 @@ static int prepare_walk(git_revwalk *walk) if (list->item->uninteresting) continue; - if ((error = walk->enqueue(walk, list->item)) < 0) + if ((error = walk->enqueue(walk, list->item)) < 0) { + git_commit_list_free(&commits); return error; + } } + git_commit_list_free(&commits); if (walk->sorting & GIT_SORT_TOPOLOGICAL) { - unsigned short i; - - while ((error = walk->get_next(&next, walk)) == 0) { - for (i = 0; i < next->out_degree; ++i) { - git_commit_list_node *parent = next->parents[i]; - parent->in_degree++; - } - - if (git_commit_list_insert(next, &walk->iterator_topo) == NULL) - return -1; - } - - if (error != GIT_ITEROVER) + if ((error = sort_in_topological_order(&walk->iterator_topo, walk))) return error; walk->get_next = &revwalk_next_toposort; diff --git a/tests/revwalk/hidecb.c b/tests/revwalk/hidecb.c index ab53ee780..b274ed86a 100644 --- a/tests/revwalk/hidecb.c +++ b/tests/revwalk/hidecb.c @@ -158,7 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void) cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_push(walk, &_head_id)); - git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); /* Add hide callback */ cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL)); @@ -183,7 +183,7 @@ void test_revwalk_hidecb__test_payload(void) cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_push(walk, &_head_id)); - git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); + git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL); /* 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])); From 5e2a29a78c19b110dace4018f0c077d0fb476a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 27 Sep 2016 13:11:47 +0200 Subject: [PATCH 06/13] commit_list: fix the date comparison function This returns the integer-cast truth value comparing the dates. What we want instead of a (-1, 0, 1) output depending on how they compare. --- src/commit_list.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/commit_list.c b/src/commit_list.c index 28948c88b..a1681ffae 100644 --- a/src/commit_list.c +++ b/src/commit_list.c @@ -13,10 +13,15 @@ int git_commit_list_time_cmp(const void *a, const void *b) { - const git_commit_list_node *commit_a = a; - const git_commit_list_node *commit_b = b; + int64_t time_a = ((git_commit_list_node *) a)->time; + 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) From e93b7e327ab21f691ddd9358bca4a0e3da2d3fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 27 Sep 2016 13:35:48 +0200 Subject: [PATCH 07/13] revwalk: style change Change the condition for returning 0 more in line with that we write elsewhere in the library. --- src/revwalk.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/revwalk.c b/src/revwalk.c index 244061a42..ec9cc576a 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -489,10 +489,8 @@ static int everybody_uninteresting(git_commit_list *orig) while (list) { git_commit_list_node *commit = list->item; list = list->next; - if (commit->uninteresting) - continue; - - return 0; + if (!commit->uninteresting) + return 0; } return 1; From 9db367bf27ed7b984f282d9f86ea6bcefb31778d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 27 Sep 2016 16:14:42 +0200 Subject: [PATCH 08/13] revwalk: get rid of obsolete marking code We've now moved to code that's closer to git and produces the output during the preparation phase, so we no longer process the commits as part of generating the output. This makes a chunk of code redundant, as we're simply short-circuiting it by detecting we've processed the commits alrady. --- src/revwalk.c | 131 ++++---------------------------------------------- 1 file changed, 9 insertions(+), 122 deletions(-) diff --git a/src/revwalk.c b/src/revwalk.c index ec9cc576a..cea76309b 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -13,6 +13,7 @@ #include "revwalk.h" #include "git2/revparse.h" #include "merge.h" +#include "vector.h" GIT__USE_OIDMAP @@ -41,97 +42,6 @@ git_commit_list_node *git_revwalk__commit_lookup( 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) { git_oid commit_id; @@ -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) { - int error; git_commit_list_node *next; - while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) - if (!next->uninteresting) { - if ((error = process_commit_parents(walk, next)) < 0) - return error; - - *object_out = next; - return 0; - } + if ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) { + *object_out = next; + return 0; + } giterr_clear(); return GIT_ITEROVER; @@ -339,17 +244,12 @@ 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) { - int error; git_commit_list_node *next; - while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) - if (!next->uninteresting) { - if ((error = process_commit_parents(walk, next)) < 0) - return error; - - *object_out = next; - return 0; - } + if ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) { + *object_out = next; + return 0; + } giterr_clear(); return GIT_ITEROVER; @@ -375,19 +275,6 @@ static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk * return *object_out ? 0 : GIT_ITEROVER; } -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 void mark_parents_uninteresting(git_commit_list_node *commit) { unsigned short i; From 4aed1b9a69f66bd6ea365a49e1a637c51f8c3013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 29 Sep 2016 15:05:38 +0200 Subject: [PATCH 09/13] Add revwalk note to CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4fd68dfe..dae86de4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ v0.24 + 1 * 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 * You can now get the user-agent used by libgit2 using the From ea1ceb7f554da276ffb0fe18c6ca4a0233845d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 5 Oct 2016 12:23:26 +0200 Subject: [PATCH 10/13] revwalk: remove a useless enqueueing phase for topological and default sorting After `limit_list()` we already have the list in time-sorted order, which is what we want in the "default" case. Enqueueing into the "unsorted" list would just reverse it, and the topological sort will do its own sorting if it needs to. --- src/revwalk.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/revwalk.c b/src/revwalk.c index cea76309b..80f5bdfdf 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -443,9 +443,9 @@ static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list return 0; } -static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk) +static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk, git_commit_list *list) { - git_commit_list *list = NULL, *ll = NULL, *newlist, **pptr; + git_commit_list *ll = NULL, *newlist, **pptr; git_commit_list_node *next; git_pqueue queue; git_vector_cmp queue_cmp = NULL; @@ -464,16 +464,10 @@ static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk) * store it in the commit list as we extract it from the lower * machinery. */ - while ((error = walk->get_next(&next, walk)) == 0) { - next->in_degree = 1; - git_commit_list_insert(next, &list); + for (ll = list; ll; ll = ll->next) { + ll->item->in_degree = 1; } - if (error != GIT_ITEROVER) - goto cleanup; - - error = 0; - /* * Count up how many children each commit has. We limit * ourselves to those commits in the original list (in-degree @@ -531,7 +525,6 @@ static int sort_in_topological_order(git_commit_list **out, git_revwalk *walk) error = 0; cleanup: - git_commit_list_free(&list); git_pqueue_free(&queue); return error; } @@ -562,26 +555,32 @@ static int prepare_walk(git_revwalk *walk) } } + for (list = commits; list; list = list->next) { + printf("%s: commit %s\n", __func__, git_oid_tostr_s(&list->item->oid)); + } + if ((error = limit_list(&commits, walk, commits)) < 0) return error; - for (list = commits; list; list = list->next) { - if (list->item->uninteresting) - continue; - - if ((error = walk->enqueue(walk, list->item)) < 0) { - git_commit_list_free(&commits); - return error; - } - } - - git_commit_list_free(&commits); - if (walk->sorting & GIT_SORT_TOPOLOGICAL) { - if ((error = sort_in_topological_order(&walk->iterator_topo, walk))) + error = sort_in_topological_order(&walk->iterator_topo, walk, commits); + git_commit_list_free(&commits); + + if (error < 0) return error; 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) { From 82d4c0e6b841ae0e466bd97ab1faec0920a6b7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 5 Oct 2016 12:55:53 +0200 Subject: [PATCH 11/13] revwalk: update the description for the default sorting It changed from implementation-defined to git's default sorting, as there are systems (e.g. rebase) which depend on this order. Also specify more explicitly how you can get git's "date-order". --- include/git2/revwalk.h | 10 ++++------ src/revwalk.c | 4 ---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index 2cc00536e..d9376ceea 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -25,17 +25,15 @@ GIT_BEGIN_DECL */ typedef enum { /** - * Sort the repository contents in no particular ordering; - * this sorting is arbitrary, implementation-specific - * and subject to change at any time. + * Sort the output with the same default time-order method from git. * This is the default sorting for new walkers. */ GIT_SORT_NONE = 0, /** - * Sort the repository contents in topological order - * (parents before children); this sorting mode - * can be combined with time sorting. + * Sort the repository contents in topological order (parents before + * children); this sorting mode can be combined with time sorting to + * produce git's "time-order". */ GIT_SORT_TOPOLOGICAL = 1 << 0, diff --git a/src/revwalk.c b/src/revwalk.c index 80f5bdfdf..4753a3723 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -555,10 +555,6 @@ static int prepare_walk(git_revwalk *walk) } } - for (list = commits; list; list = list->next) { - printf("%s: commit %s\n", __func__, git_oid_tostr_s(&list->item->oid)); - } - if ((error = limit_list(&commits, walk, commits)) < 0) return error; From 3cc5ec94f8d4753d00e7c407d0033187fe79eb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 5 Oct 2016 12:57:53 +0200 Subject: [PATCH 12/13] rebase: don't ask for time sorting `git-rebase--merge` does not ask for time sorting, but uses the default. We now produce the same default time-ordered output as git, so make us of that since it's not always the same output as our time sorting. --- src/rebase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rebase.c b/src/rebase.c index 470e62a23..e86312e7e 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -586,7 +586,7 @@ static int rebase_init_operations( (error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0) 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) { if ((error = git_commit_lookup(&commit, repo, &id)) < 0) From fedc05c89ceb545f29c57bf35ffd066bd9e49386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 6 Oct 2016 18:13:34 +0200 Subject: [PATCH 13/13] revwalk: don't show commits that become uninteresting after being enqueued When we read from the list which `limit_list()` gives us, we need to check that the commit is still interesting, as it might have become uninteresting after it was added to the list. --- src/revwalk.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/revwalk.c b/src/revwalk.c index 4753a3723..0ada5870a 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -246,9 +246,12 @@ static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk { git_commit_list_node *next; - if ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) { - *object_out = next; - return 0; + while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) { + /* Some commits might become uninteresting after being added to the list */ + if (!next->uninteresting) { + *object_out = next; + return 0; + } } giterr_clear(); @@ -257,12 +260,14 @@ 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) { - git_commit_list_node *node; + git_commit_list_node *next; - node = git_commit_list_pop(&walk->iterator_topo); - if (node) { - *object_out = node; - return 0; + while ((next = git_commit_list_pop(&walk->iterator_topo)) != NULL) { + /* Some commits might become uninteresting after being added to the list */ + if (!next->uninteresting) { + *object_out = next; + return 0; + } } giterr_clear();