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
4 changes: 4 additions & 0 deletions Documentation/rev-list-options.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ endif::git-log[]
from the point where it diverged from the remote branch, given
that arbitrary merges can be valid topic branch changes.

`--maximal-only`::
Restrict the output commits to be those that are not reachable
from any other commits in the revision range.

`--not`::
Reverses the meaning of the '{caret}' prefix (or lack thereof)
for all following revision specifiers, up to the next `--not`.
Expand Down
4 changes: 2 additions & 2 deletions object.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void object_array_init(struct object_array *array);

/*
* object flag allocation:
* revision.h: 0---------10 15 23------27
* revision.h: 0---------10 15 23--------28
* fetch-pack.c: 01 67
* negotiator/default.c: 2--5
* walker.c: 0-2
Expand All @@ -86,7 +86,7 @@ void object_array_init(struct object_array *array);
* builtin/unpack-objects.c: 2021
* pack-bitmap.h: 2122
*/
#define FLAG_BITS 28
#define FLAG_BITS 29

#define TYPE_BITS 3

Expand Down
12 changes: 10 additions & 2 deletions revision.c
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,8 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
struct commit *p = parent->item;
parent = parent->next;
if (p)
p->object.flags |= UNINTERESTING;
p->object.flags |= UNINTERESTING |
CHILD_VISITED;
if (repo_parse_commit_gently(revs->repo, p, 1) < 0)
continue;
if (p->parents)
Expand Down Expand Up @@ -1204,7 +1205,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
if (!*slot)
*slot = *revision_sources_at(revs->sources, commit);
}
p->object.flags |= pass_flags;
p->object.flags |= pass_flags | CHILD_VISITED;
if (!(p->object.flags & SEEN)) {
p->object.flags |= (SEEN | NOT_USER_GIVEN);
if (list)
Expand Down Expand Up @@ -2377,6 +2378,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if ((argcount = parse_long_opt("until", argv, &optarg))) {
revs->min_age = approxidate(optarg);
return argcount;
} else if (!strcmp(arg, "--maximal-only")) {
revs->maximal_only = 1;
} else if (!strcmp(arg, "--first-parent")) {
revs->first_parent_only = 1;
} else if (!strcmp(arg, "--exclude-first-parent-only")) {
Expand Down Expand Up @@ -3147,6 +3150,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
!!revs->reverse, "--reverse",
!!revs->reflog_info, "--walk-reflogs");

die_for_incompatible_opt2(!!revs->boundary, "--boundary",
!!revs->maximal_only, "--maximal-only");

if (revs->no_walk && revs->graph)
die(_("options '%s' and '%s' cannot be used together"), "--no-walk", "--graph");
if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
Expand Down Expand Up @@ -4125,6 +4131,8 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
{
if (commit->object.flags & SHOWN)
return commit_ignore;
if (revs->maximal_only && (commit->object.flags & CHILD_VISITED))
return commit_ignore;
if (revs->unpacked && has_object_pack(revs->repo, &commit->object.oid))
return commit_ignore;
if (revs->no_kept_objects) {
Expand Down
5 changes: 4 additions & 1 deletion revision.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
#define NOT_USER_GIVEN (1u<<25)
#define TRACK_LINEAR (1u<<26)
#define ANCESTRY_PATH (1u<<27)
#define ALL_REV_FLAGS (((1u<<11)-1) | NOT_USER_GIVEN | TRACK_LINEAR | PULL_MERGE)
#define CHILD_VISITED (1u<<28)
#define ALL_REV_FLAGS (((1u<<11)-1) | NOT_USER_GIVEN | TRACK_LINEAR \
| PULL_MERGE | CHILD_VISITED)

#define DECORATE_SHORT_REFS 1
#define DECORATE_FULL_REFS 2
Expand Down Expand Up @@ -189,6 +191,7 @@ struct rev_info {
left_right:1,
left_only:1,
right_only:1,
maximal_only:1,
rewrite_parents:1,
print_parents:1,
show_decorations:1,
Expand Down
15 changes: 15 additions & 0 deletions t/t6000-rev-list-misc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,19 @@ test_expect_success 'rev-list -z --boundary' '
test_cmp expect actual
'

test_expect_success 'rev-list --boundary incompatible with --maximal-only' '
test_when_finished rm -rf repo &&
git init repo &&
test_commit -C repo 1 &&
test_commit -C repo 2 &&
oid1=$(git -C repo rev-parse HEAD~) &&
oid2=$(git -C repo rev-parse HEAD) &&
test_must_fail git -C repo rev-list --boundary --maximal-only \
HEAD~1..HEAD 2>err &&
test_grep "cannot be used together" err
'

test_done
75 changes: 75 additions & 0 deletions t/t6600-test-reach.sh
Original file line number Diff line number Diff line change
Expand Up @@ -762,4 +762,79 @@ test_expect_success 'for-each-ref is-base: --sort' '
--sort=refname --sort=-is-base:commit-2-3
'

test_expect_success 'rev-list --maximal-only (all positive)' '
# Only one maximal.
cat >input <<-\EOF &&
refs/heads/commit-1-1
refs/heads/commit-4-2
refs/heads/commit-4-4
refs/heads/commit-8-4
EOF
cat >expect <<-EOF &&
$(git rev-parse refs/heads/commit-8-4)
EOF
run_all_modes git rev-list --maximal-only --stdin &&
# All maximal.
cat >input <<-\EOF &&
refs/heads/commit-5-2
refs/heads/commit-4-3
refs/heads/commit-3-4
refs/heads/commit-2-5
EOF
cat >expect <<-EOF &&
$(git rev-parse refs/heads/commit-5-2)
$(git rev-parse refs/heads/commit-4-3)
$(git rev-parse refs/heads/commit-3-4)
$(git rev-parse refs/heads/commit-2-5)
EOF
run_all_modes git rev-list --maximal-only --stdin &&
# Mix of both.
cat >input <<-\EOF &&
refs/heads/commit-5-2
refs/heads/commit-3-2
refs/heads/commit-2-5
EOF
cat >expect <<-EOF &&
$(git rev-parse refs/heads/commit-5-2)
$(git rev-parse refs/heads/commit-2-5)
EOF
run_all_modes git rev-list --maximal-only --stdin
'

test_expect_success 'rev-list --maximal-only (range)' '
cat >input <<-\EOF &&
refs/heads/commit-1-1
refs/heads/commit-2-5
refs/heads/commit-6-4
^refs/heads/commit-4-5
EOF
cat >expect <<-EOF &&
$(git rev-parse refs/heads/commit-6-4)
EOF
run_all_modes git rev-list --maximal-only --stdin &&
# first-parent changes reachability: the first parent
# reduces the second coordinate to 1 before reducing the
# first coordinate.
cat >input <<-\EOF &&
refs/heads/commit-1-1
refs/heads/commit-2-5
refs/heads/commit-6-4
^refs/heads/commit-4-5
EOF
cat >expect <<-EOF &&
$(git rev-parse refs/heads/commit-6-4)
$(git rev-parse refs/heads/commit-2-5)
EOF
run_all_modes git rev-list --maximal-only --stdin \
--first-parent --exclude-first-parent-only
'

test_done
Loading