From: Junio C Hamano <gitster@pobox.com>
To: "Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com>
Cc: git@vger.kernel.org, "SZEDER Gábor" <szeder.dev@gmail.com>,
"Michael Montalbo" <mmontalbo@gmail.com>
Subject: Re: [PATCH] revision: make get_commit_action() a pure predicate
Date: Mon, 27 Jul 2026 06:45:41 -0700 [thread overview]
Message-ID: <xmqq8q6wpmuy.fsf@gitster.g> (raw)
In-Reply-To: <pull.2169.git.1784143793613.gitgitgadget@gmail.com> (Michael Montalbo via GitGitGadget's message of "Wed, 15 Jul 2026 19:29:52 +0000")
"Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com> writes:
> commit_early_ignore() runs twice on the -L path, once for that gate and
> once inside get_commit_action(), but it reads only object flags and pack
> membership, disjoint from the TREESAME flag the fold sets, so the repeat
> is harmless.
This one confused me a bit, so I'll think aloud below to see if you
can spot where I am misunderstanding your code.
> +/*
> + * Whether the commit is ignored by the cheap checks that read only its
> + * traversal flags and pack membership (e.g. already shown, or marked
> + * uninteresting), before any check that examines the commit's date,
> + * parents, message, or diff.
> + */
> +static int commit_early_ignore(struct rev_info *revs, struct commit *commit)
> {
> if (commit->object.flags & SHOWN)
> - return commit_ignore;
> + return 1;
> if (revs->maximal_only && (commit->object.flags & CHILD_VISITED))
> - return commit_ignore;
> + return 1;
> if (revs->unpacked && has_object_pack(revs->repo, &commit->object.oid))
> - return commit_ignore;
> - if (revs->no_kept_objects) {
> - if (has_object_kept_pack(revs->repo, &commit->object.oid,
> - revs->keep_pack_cache_flags))
> - return commit_ignore;
> - }
> + return 1;
> + if (revs->no_kept_objects &&
> + has_object_kept_pack(revs->repo, &commit->object.oid,
> + revs->keep_pack_cache_flags))
> + return 1;
> if (commit->object.flags & UNINTERESTING)
> + return 1;
> + return 0;
> +}
This mirrors what the original get_commit_action() did to return
early with 'commit_ignore'. Collapsing the nested 'if' for the
kept-objects case is a nice touch that makes the result easier to
follow.
> +/*
> + * Decide whether this commit is shown or ignored. Keep it a pure
> + * predicate: callers such as the commit graph depend on it having no
> + * side effects, so per-commit mutations (such as -L range tracking)
> + * belong in the caller, simplify_commit(), not here.
> + */
> +enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit)
> +{
> + if (commit_early_ignore(revs, commit))
> return commit_ignore;
> - if (revs->line_level_traverse && !want_ancestry(revs)) {
> - /*
> - * In case of line-level log with parent rewriting
> - * prepare_revision_walk() already took care of all line-level
> - * log filtering, and there is nothing left to do here.
> - *
> - * If parent rewriting was not requested, then this is the
> - * place to perform the line-level log filtering. Notably,
> - * this check, though expensive, must come before the other,
> - * cheaper filtering conditions, because the tracked line
> - * ranges must be adjusted even when the commit will end up
> - * being ignored based on other conditions.
> - */
> - if (!line_log_process_ranges_arbitrary_commit(revs, commit))
> - return commit_ignore;
> - }
> if (revs->min_age != -1 &&
> comparison_date(revs, commit) > revs->min_age)
> return commit_ignore;
> @@ -4314,7 +4316,23 @@ struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit
>
> enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
> {
> - enum commit_action action = get_commit_action(revs, commit);
> + enum commit_action action;
> +
> + /*
> + * For a line-level log without parent rewriting, fold each commit's
> + * ranges as the walk reaches it (parent rewriting does this eagerly in
> + * prepare_revision_walk()). Fold before get_commit_action() so the
> + * ranges carry across a commit that a later, cheaper check ignores;
> + * the commit_early_ignore() guard skips a commit get_commit_action()
> + * would ignore outright.
> + */
> + if (revs->line_level_traverse && !want_ancestry(revs) &&
> + !commit_early_ignore(revs, commit)) {
> + if (!line_log_process_ranges_arbitrary_commit(revs, commit))
> + return commit_ignore;
> + }
> +
> + action = get_commit_action(revs, commit);
The primary change in the patch is to lift the "line-level" code out
of get_commit_action() and move it to one of its callers (namely
simplify_commit()). The other caller is known not to trigger the
affected parts of the function, which was discussed previously at
https://lore.kernel.org/git/xmqqtsqxfdl4.fsf@gitster.g/ and started
this leftover bit.
We used to call get_commit_action() to decide the fate of the
commit. If get_commit_action() returned anything other than
'commit_show', simplify_commit() simply returned that action without
doing anything further.
The original get_commit_action(), when on the code path that calls
line_log_process_ranges_arbitrary_commit() to check if we want to
ignore this commit, did what the commit_early_ignore() helper does
in this version before reaching that point. So this updated caller
in simplify_commit() recreates the exact same logic.
We do end up executing the commit_early_ignore() logic twice if
line_log_process_ranges_arbitrary_commit() does not tell us to ignore
this commit. With only two callers of get_commit_action(), we could
easily reuse the result of commit_early_ignore() if we wanted to, but
it is probably not worth it.
So the patch looks good. Will queue. Thanks.
prev parent reply other threads:[~2026-07-27 13:45 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 19:29 [PATCH] revision: make get_commit_action() a pure predicate Michael Montalbo via GitGitGadget
2026-07-24 21:37 ` Junio C Hamano
2026-07-25 19:25 ` Michael Montalbo
2026-07-27 13:25 ` Junio C Hamano
2026-07-27 13:45 ` Junio C Hamano [this message]
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=xmqq8q6wpmuy.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
--cc=gitgitgadget@gmail.com \
--cc=mmontalbo@gmail.com \
--cc=szeder.dev@gmail.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