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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.