Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions builtin/rev-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "oidset.h"
#include "oidmap.h"
#include "packfile.h"
#include "commit-reach.h"
#include "quote.h"
#include "strbuf.h"

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down
29 changes: 29 additions & 0 deletions t/perf/p6011-rev-list-maximal.sh
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions t/t6000-rev-list-misc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
45 changes: 45 additions & 0 deletions t/t6600-test-reach.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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