From: Jeff King <peff@peff.net>
To: Tamir Duberstein <tamird@gmail.com>
Cc: git@vger.kernel.org, Karthik Nayak <karthik.188@gmail.com>,
Junio C Hamano <gitster@pobox.com>,
Victoria Dye <vdye@github.com>, Derrick Stolee <stolee@gmail.com>,
Elijah Newren <newren@gmail.com>,
Kristofer Karlsson <krka@spotify.com>
Subject: Re: [PATCH v4 1/3] commit-reach: reject cycles in contains walk
Date: Thu, 16 Jul 2026 05:05:25 -0400 [thread overview]
Message-ID: <20260716090525.GA1196203@coredump.intra.peff.net> (raw)
In-Reply-To: <20260612-ref-filter-memoized-contains-v4-1-5ed39fd001dd@gmail.com>
On Fri, Jun 12, 2026 at 05:49:12PM -0400, Tamir Duberstein wrote:
> @@ -708,7 +708,8 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
>
> /*
> * Test whether the candidate is contained in the list.
> - * Do not recurse to find out, though, but return -1 if inconclusive.
> + * Do not recurse to find out, though, but return CONTAINS_UNKNOWN if
> + * inconclusive.
> */
> static enum contains_result contains_test(struct commit *candidate,
> const struct commit_list *want,
This hunk is a good cleanup, but unrelated to the patch at hand.
We used to return a bare -1, then that became CONTAINS_UNKNOWN in
a0262c51d0 (ref-filter: use contains_result enum consistently,
2017-03-09). And then that value changed to 0 in a91aca44bf (ref-filter:
use separate cache for contains_tag_algo, 2017-03-09) when we started
using a slab.
So the code is correct and the comment is wrong, and it is worth
updating. I was just surprised to find it here.
> @@ -765,6 +766,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
> if (result != CONTAINS_UNKNOWN)
> return result;
>
> + *contains_cache_at(cache, candidate) = CONTAINS_IN_PROGRESS;
> push_to_contains_stack(candidate, &contains_stack);
> while (contains_stack.nr) {
> struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
> @@ -776,8 +778,8 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
> contains_stack.nr--;
> }
> /*
> - * If we just popped the stack, parents->item has been marked,
> - * therefore contains_test will return a meaningful yes/no.
> + * A parent may have just been popped and marked, or may still
> + * be active when replacement refs create a cycle.
> */
> else switch (contains_test(parents->item, want, cache, cutoff)) {
> case CONTAINS_YES:
> @@ -787,7 +789,11 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
> case CONTAINS_NO:
> entry->parents = parents->next;
> break;
> + case CONTAINS_IN_PROGRESS:
> + die(_("commit ancestry contains a cycle"));
> case CONTAINS_UNKNOWN:
> + *contains_cache_at(cache, parents->item) =
> + CONTAINS_IN_PROGRESS;
> push_to_contains_stack(parents->item, &contains_stack);
> break;
> }
Nice, this looks cleanly done.
> +test_expect_success 'tag --contains rejects cyclic replacement histories' '
> + first=$(git rev-parse HEAD~2) &&
> + second=$(git rev-parse HEAD~) &&
> + third=$(git rev-parse HEAD) &&
> + test_when_finished "
> + git replace -d $first &&
> + git replace -d $third &&
> + git tag -d cycle-a cycle-b
> + " &&
> + git tag cycle-a "$first" &&
> + git tag cycle-b "$third" &&
> + git replace --graft "$first" "$third" "$second" &&
> + git replace --graft "$third" "$first" &&
> + test_must_fail git tag --contains="$second" --list "cycle-*" \
> + >/dev/null 2>err &&
> + test_grep "fatal: commit ancestry contains a cycle" err
> +'
Likewise the test looks good.
-Peff
next prev parent reply other threads:[~2026-07-16 9:05 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-09 2:36 [PATCH v2 0/2] Reuse --contains traversal results Tamir Duberstein
2026-06-09 2:36 ` [PATCH v2 1/2] commit-reach: handle cycles in contains walk Tamir Duberstein
2026-06-11 7:29 ` Jeff King
2026-06-12 2:40 ` Tamir Duberstein
2026-06-09 2:36 ` [PATCH v2 2/2] ref-filter: memoize --contains with generations Tamir Duberstein
2026-06-10 11:47 ` Karthik Nayak
2026-06-10 12:20 ` Tamir Duberstein
2026-06-11 8:16 ` Karthik Nayak
2026-06-11 20:10 ` Tamir Duberstein
2026-06-11 8:22 ` Jeff King
2026-06-12 2:40 ` Tamir Duberstein
2026-06-12 3:00 ` [PATCH v3 0/3] Reuse --contains traversal results Tamir Duberstein
2026-06-12 3:00 ` [PATCH v3 1/3] commit-reach: handle cycles in contains walk Tamir Duberstein
2026-06-12 6:53 ` Kristofer Karlsson
2026-06-12 21:26 ` Tamir Duberstein
2026-06-12 3:00 ` [PATCH v3 2/3] ref-filter: memoize --contains with generations Tamir Duberstein
2026-06-12 3:00 ` [PATCH v3 3/3] commit-reach: die on contains walk errors Tamir Duberstein
2026-06-12 21:49 ` [PATCH v4 0/3] Reuse --contains traversal results Tamir Duberstein
2026-06-12 21:49 ` [PATCH v4 1/3] commit-reach: reject cycles in contains walk Tamir Duberstein
2026-07-16 9:05 ` Jeff King [this message]
2026-06-12 21:49 ` [PATCH v4 2/3] ref-filter: memoize --contains with generations Tamir Duberstein
2026-06-12 21:49 ` [PATCH v4 3/3] commit-reach: die on contains walk errors Tamir Duberstein
2026-07-16 9:18 ` Jeff King
2026-06-29 20:40 ` [PATCH v4 0/3] Reuse --contains traversal results Junio C Hamano
2026-07-16 9:19 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260716090525.GA1196203@coredump.intra.peff.net \
--to=peff@peff.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=karthik.188@gmail.com \
--cc=krka@spotify.com \
--cc=newren@gmail.com \
--cc=stolee@gmail.com \
--cc=tamird@gmail.com \
--cc=vdye@github.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox