Re: Bug report - git rev-list --exclude-first-parent-only [SEC=UNOFFICIAL]

Jerry Zhang <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <CAMKO5Cu0i3UKT61th3ZUiiQTkPa+YtxGQAQSXJjNWGWaTs8OGg@mail.gmail.com>
On Fri, Jul 3, 2026 at 1:28 PM Junio C Hamano <[email protected]> wrote:
>
> Michael Hore <[email protected]> writes:
>
> > I believe I have found a bug -
> >
> > My repo has a commit structure like
> >
> > R2
> > |\
> > | F
> > |/
> > R1
> >
> > i.e.
> >  - there is a merge commit R2 with parents R1 and F
> >  - the parent of F is R1
>
> IOW, R2 is a useless merge that could have been a simple
> fast-forward directly to F.
>
> > I ran "git rev-list --exclude-first-parent-only F ^R2"
> >
> > it gave the expected result: "F"
> >
> > I ran "git rev-list --exclude-first-parent-only F R1 ^R2"
> >
> > I expected the same result, but I got an unexpected result - nothing at all
>
> This seems to have come from 9d505b7b49 (git-rev-list: add
> --exclude-first-parent-only flag, 2022-01-11).  I do not know if the
> original author is still around, but it would have been nicer to ask
> for input from them (cc'ed).
>
> A fix could be something along this line, but I've never used this
> feature even once (I instead use Michael Haggerty's exellent "git
> when-merged" thing), so I may very well be breaking _other_ use
> cases this feature was originally intended for without knowing.
fwiw when-merged seems to be asking the question "when was X branch
merged into the
baseline", while exclude-first-parent-only is asking "when did X
branch first split off from
the baseline". of course that property may not be interesting to you
if you're looking for the
former.
>
> The patched part is inside a huge "while (parent)" loop.  The idea
> is to break out before the loop goes on to smudge later parents when
> we are in the "smudge only first parent as uninteresting, without
> contaminating the history leading to other parents" mode.
>
>  revision.c                   | 10 ++++++++--
>  t/t6012-rev-list-simplify.sh | 18 ++++++++++++++++++
>  2 files changed, 26 insertions(+), 2 deletions(-)
>
> diff --git c/revision.c w/revision.c
> index e91d7e1f11..1f50d42a7a 100644
> --- c/revision.c
> +++ w/revision.c
> @@ -1151,12 +1151,18 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
>                         if (p)
>                                 p->object.flags |= UNINTERESTING |
>                                                    CHILD_VISITED;
> -                       if (repo_parse_commit_gently(revs->repo, p, 1) < 0)
> +                       if (repo_parse_commit_gently(revs->repo, p, 1) < 0) {
> +                               if (revs->exclude_first_parent_only)
> +                                       break;
>                                 continue;
> +                       }
>                         if (p->parents)
>                                 mark_parents_uninteresting(revs, p);
> -                       if (p->object.flags & SEEN)
> +                       if (p->object.flags & SEEN) {
> +                               if (revs->exclude_first_parent_only)
> +                                       break;
>                                 continue;
> +                       }
>                         p->object.flags |= (SEEN | NOT_USER_GIVEN);
>                         if (queue)
>                                 prio_queue_put(queue, p);
> diff --git c/t/t6012-rev-list-simplify.sh w/t/t6012-rev-list-simplify.sh
> index 4cecb6224c..2284bbba12 100755
> --- c/t/t6012-rev-list-simplify.sh
> +++ w/t/t6012-rev-list-simplify.sh
> @@ -285,4 +285,22 @@ test_expect_success 'log --graph --simplify-merges --show-pulls' '
>         test_cmp expect actual
>  '
>
> +test_expect_success 'exclude-first-parent-only with parent already seen' '
> +       git checkout --orphan test-seen &&
> +       git rm -rf . &&
> +       test_commit r1 &&
> +       git checkout -b branch-f &&
> +       test_commit f &&
> +       git checkout test-seen &&
> +       git merge --no-ff --no-edit -m r2 branch-f &&
> +       git tag r2 &&
> +
> +       git rev-list --exclude-first-parent-only f ^r2 >actual &&
> +       git rev-parse f >expect &&
> +       test_cmp expect actual &&
> +
> +       git rev-list --exclude-first-parent-only f r1 ^r2 >actual2 &&
> +       test_cmp expect actual2
> +'
> +
>  test_done
>
Its been a while since i've looked at the code, but the rationale and
test case make sense to me. thanks

Reviewed-by: Jerry Zhang <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.