Re: [PATCH] setup_revisions(): turn on diffs for all-negative diff filter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Jeff King <peff@xxxxxxxx> writes:

> On Thu, Jul 03, 2025 at 11:34:38AM -0400, Jeff King wrote:
>
>> On Wed, Jul 02, 2025 at 03:28:43PM -0500, Eric Salem wrote:
>>
>> > The git log --diff-filter documentation[1] for deleted files says:
>> >
>> > > Select only files that are Added (A), Copied (C), Deleted (D)...
>> >
>> > > Also, these upper-case letters can be downcased to exclude.
>> > > E.g. --diff-filter=ad excludes added and deleted paths.
>> >
>> > A simple test:
>> > [...]
>> > --diff-filter=D behaves as expected, but when using "d" instead, I don't
>> > get any output unless I add another option (such as --stat or
>> > --name-only).
>>
>> Looks like a bug. This used to produce the output I'd expect (i.e.,
>> commits "first" and "third", which do not have deletions), but that
>> changed in 75408ca949 (diff-filter: be more careful when looking for
>> negative bits, 2022-01-28).
>>
>> I don't have time to dig into it now, but I've cc'd the author (and left
>> your whole reproduction recipe quoted below).
>
> Argh, I forgot to add Johannes to the cc. Fortunately since then I had a
> moment to look at this, and the solution is pretty simple. So here it is
> as a patch with a test.
>
> -- >8 --
> Subject: setup_revisions(): turn on diffs for all-negative diff filter
>
> When the user gives us a diff filter like --diff-filter=D, we need to do
> a tree diff even if we're not planning to show the diff result itself,
> in order to decide whether to show the commit at all. So there's an
> explicit check of revs->diffopt.filter in setup_revisions(), and we set
> revs->diff if any bits are set.

So if `revs->diff` is set, then we compute the tree diff for the given
commit.

>
> Originally that "filter" field covered both positive capital-letter
> filters (like "D") and also negative lowercase filters (like "d"), so it
> was sufficient for both cases. But later, 75408ca949 (diff-filter: be
> more careful when looking for negative bits, 2022-01-28) split the
> negative bits out into a "filter_not" field.
>
> We eventually fold those into "filter", but not until diff_setup_done()
> is called, which happens after our explicit check. As a result, a purely
> negative filter like:
>
>   git log --diff-filter=d
>
> failed to turn on diffs at all. But rather than fail to filter by diff,
> because the filter variable is eventually set, we mistakenly show no
> commits at all, thinking that the empty diffs were cases where nothing
> passed through the filter.
>
> The smallest fix here is to just have our check look for any bits in
> either "filter" or "filter_not". I suspect it would also be OK to
> reorder the function a bit to call diff_setup_done() earlier, but that
> risks violating some other subtle ordering dependency. So I went with
> the simple and safe solution here.
>

The explanation here was really nice to read and explained the problem
well.

> Signed-off-by: Jeff King <peff@xxxxxxxx>
> ---
>  revision.c     | 2 +-
>  t/t4202-log.sh | 6 ++++++
>  2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/revision.c b/revision.c
> index afee111196..9892d08748 100644
> --- a/revision.c
> +++ b/revision.c
> @@ -3112,7 +3112,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
>
>  	/* Pickaxe, diff-filter and rename following need diffs */
>  	if ((revs->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
> -	    revs->diffopt.filter ||
> +	    revs->diffopt.filter || revs->diffopt.filter_not ||
>  	    revs->diffopt.flags.follow_renames)
>  		revs->diff = 1;
>

Makes sense.

> diff --git a/t/t4202-log.sh b/t/t4202-log.sh
> index 4a6c4dfbf4..05cee9e41b 100755
> --- a/t/t4202-log.sh
> +++ b/t/t4202-log.sh
> @@ -134,6 +134,12 @@ test_expect_success 'diff-filter=D' '
>
>  '
>
> +test_expect_success 'all-negative filter' '
> +	git log --no-renames --format=%s --diff-filter=d HEAD >actual &&
> +	printf "%s\n" fifth fourth third second initial >expect &&
> +	test_cmp expect actual
> +'
> +
>  test_expect_success 'diff-filter=R' '
>
>  	git log -M --pretty="format:%s" --diff-filter=R HEAD >actual &&
> --
> 2.50.0.438.g3b3bebd3e8

The fix looks great. Thanks!

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux