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`.
/*
* 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
* builtin/unpack-objects.c: 2021
* pack-bitmap.h: 2122
*/
-#define FLAG_BITS 28
+#define FLAG_BITS 29
#define TYPE_BITS 3
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)
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)
} 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")) {
!!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)
{
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) {
#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
left_right:1,
left_only:1,
right_only:1,
+ maximal_only:1,
rewrite_parents:1,
print_parents:1,
show_decorations:1,
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
--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