Merge branch 'ds/rev-list-maximal-only-optim' into next
"git rev-list --maximal-only" has been optimized by borrowing the logic used by "git show-branch --independent", which computes the same kind of information much more efficiently. * ds/rev-list-maximal-only-optim: rev-list: use reduce_heads() for --maximal-only p6011: add perf test for rev-list --maximal-only t6600: test --maximal-only and --independentnext
commit
7a70817efa
|
|
@ -25,6 +25,7 @@
|
|||
#include "oidset.h"
|
||||
#include "oidmap.h"
|
||||
#include "packfile.h"
|
||||
#include "commit-reach.h"
|
||||
#include "quote.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
|
|
@ -633,6 +634,61 @@ static int try_bitmap_disk_usage(struct rev_info *revs,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If revs->maximal_only is set and no other walk modifiers are provided,
|
||||
* run a faster computation to filter the independent commits and prepare
|
||||
* them for output. Set revs->no_walk to prevent later walking.
|
||||
*
|
||||
* If this algorithm doesn't apply, then no changes are made to revs.
|
||||
*/
|
||||
static void prepare_maximal_independent(struct rev_info *revs)
|
||||
{
|
||||
struct commit_list *c;
|
||||
|
||||
if (!revs->maximal_only)
|
||||
return;
|
||||
|
||||
for (c = revs->commits; c; c = c->next) {
|
||||
if (c->item->object.flags & UNINTERESTING)
|
||||
return;
|
||||
}
|
||||
|
||||
if (revs->limited ||
|
||||
revs->topo_order ||
|
||||
revs->first_parent_only ||
|
||||
revs->reverse ||
|
||||
revs->max_count >= 0 ||
|
||||
revs->skip_count >= 0 ||
|
||||
revs->min_age != (timestamp_t)-1 ||
|
||||
revs->max_age != (timestamp_t)-1 ||
|
||||
revs->min_parents > 0 ||
|
||||
revs->max_parents >= 0 ||
|
||||
revs->prune_data.nr ||
|
||||
revs->count ||
|
||||
revs->left_right ||
|
||||
revs->boundary ||
|
||||
revs->tag_objects ||
|
||||
revs->tree_objects ||
|
||||
revs->blob_objects ||
|
||||
revs->filter.choice ||
|
||||
revs->reflog_info ||
|
||||
revs->diff ||
|
||||
revs->grep_filter.pattern_list ||
|
||||
revs->grep_filter.header_list ||
|
||||
revs->verbose_header ||
|
||||
revs->print_parents ||
|
||||
revs->edge_hint ||
|
||||
revs->unpacked ||
|
||||
revs->no_kept_objects ||
|
||||
revs->line_level_traverse)
|
||||
return;
|
||||
|
||||
reduce_heads_replace(&revs->commits);
|
||||
|
||||
/* Modify 'revs' to only output this commit list. */
|
||||
revs->no_walk = 1;
|
||||
}
|
||||
|
||||
int cmd_rev_list(int argc,
|
||||
const char **argv,
|
||||
const char *prefix,
|
||||
|
|
@ -875,6 +931,9 @@ int cmd_rev_list(int argc,
|
|||
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
|
||||
prepare_maximal_independent(&revs);
|
||||
|
||||
if (revs.tree_objects)
|
||||
mark_edges_uninteresting(&revs, show_edge, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='Test --maximal-only and --independent options'
|
||||
|
||||
. ./perf-lib.sh
|
||||
|
||||
test_perf_default_repo
|
||||
|
||||
test_expect_success 'setup' '
|
||||
git for-each-ref --format="%(*objecttype) %(objecttype) %(objectname)" \
|
||||
"refs/heads/*" "refs/tags/*" |
|
||||
sed -n -e "s/^commit commit //p" -e "s/^ commit //p" |
|
||||
head -n 50 >commits &&
|
||||
git commit-graph write --reachable
|
||||
'
|
||||
|
||||
test_perf 'merge-base --independent' '
|
||||
git merge-base --independent $(cat commits) >/dev/null
|
||||
'
|
||||
|
||||
test_perf 'rev-list --maximal-only' '
|
||||
git rev-list --maximal-only $(cat commits) >/dev/null
|
||||
'
|
||||
|
||||
test_perf 'rev-list --maximal-only --since' '
|
||||
git rev-list --maximal-only --since=2000-01-01 $(cat commits) >/dev/null
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
@ -263,4 +263,35 @@ test_expect_success 'rev-list --boundary incompatible with --maximal-only' '
|
|||
test_grep "cannot be used together" err
|
||||
'
|
||||
|
||||
test_expect_success 'rev-list --maximal-only and --pretty' '
|
||||
test_when_finished rm -rf repo &&
|
||||
|
||||
git init repo &&
|
||||
test_commit -C repo 1 &&
|
||||
oid1=$(git -C repo rev-parse HEAD) &&
|
||||
test_commit -C repo 2 &&
|
||||
oid2=$(git -C repo rev-parse HEAD) &&
|
||||
git -C repo checkout --detach HEAD~1 &&
|
||||
test_commit -C repo 3 &&
|
||||
oid3=$(git -C repo rev-parse HEAD) &&
|
||||
|
||||
cat >expect <<-EOF &&
|
||||
commit $oid3
|
||||
$oid3
|
||||
commit $oid2
|
||||
$oid2
|
||||
EOF
|
||||
|
||||
git -C repo rev-list --pretty="%H" --maximal-only $oid1 $oid2 $oid3 >out &&
|
||||
test_cmp expect out &&
|
||||
|
||||
cat >expect <<-EOF &&
|
||||
$oid3
|
||||
$oid2
|
||||
EOF
|
||||
|
||||
git -C repo log --pretty="%H" --maximal-only $oid1 $oid2 $oid3 >out &&
|
||||
test_cmp expect out
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
|
|
@ -837,4 +837,49 @@ test_expect_success 'rev-list --maximal-only (range)' '
|
|||
--first-parent --exclude-first-parent-only
|
||||
'
|
||||
|
||||
test_expect_success 'rev-list --maximal-only matches merge-base --independent' '
|
||||
# Mix of independent and dependent
|
||||
git merge-base --independent \
|
||||
refs/heads/commit-5-2 \
|
||||
refs/heads/commit-3-2 \
|
||||
refs/heads/commit-2-5 >expect &&
|
||||
sort expect >expect.sorted &&
|
||||
git rev-list --maximal-only \
|
||||
refs/heads/commit-5-2 \
|
||||
refs/heads/commit-3-2 \
|
||||
refs/heads/commit-2-5 >actual &&
|
||||
sort actual >actual.sorted &&
|
||||
test_cmp expect.sorted actual.sorted &&
|
||||
|
||||
# All independent commits.
|
||||
git merge-base --independent \
|
||||
refs/heads/commit-5-2 \
|
||||
refs/heads/commit-4-3 \
|
||||
refs/heads/commit-3-4 \
|
||||
refs/heads/commit-2-5 >expect &&
|
||||
sort expect >expect.sorted &&
|
||||
git rev-list --maximal-only \
|
||||
refs/heads/commit-5-2 \
|
||||
refs/heads/commit-4-3 \
|
||||
refs/heads/commit-3-4 \
|
||||
refs/heads/commit-2-5 >actual &&
|
||||
sort actual >actual.sorted &&
|
||||
test_cmp expect.sorted actual.sorted &&
|
||||
|
||||
# Only one independent.
|
||||
git merge-base --independent \
|
||||
refs/heads/commit-1-1 \
|
||||
refs/heads/commit-4-2 \
|
||||
refs/heads/commit-4-4 \
|
||||
refs/heads/commit-8-4 >expect &&
|
||||
sort expect >expect.sorted &&
|
||||
git rev-list --maximal-only \
|
||||
refs/heads/commit-1-1 \
|
||||
refs/heads/commit-4-2 \
|
||||
refs/heads/commit-4-4 \
|
||||
refs/heads/commit-8-4 >actual &&
|
||||
sort actual >actual.sorted &&
|
||||
test_cmp expect.sorted actual.sorted
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
Loading…
Reference in New Issue