Subject: Re: [PATCH v2 3/3] diff-filter: be more careful when looking for negative bits

From: Junio C Hamano <[email-masked]>
Date: Thu, 27 Jan 2022 17:16:46 -0800

"Johannes Schindelin via GitGitGadget" <[email-masked]>
writes:

> diff --git a/diff.c b/diff.c
> index 5081052c431..4ab4299b817 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -4720,6 +4720,12 @@ void diff_setup_done(struct diff_options *options)
>  	if (!options->use_color || external_diff())
>  		options->color_moved = 0;
>  
> +	if (options->filter_not) {
> +		if (!options->filter)
> +			options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON];

Unlike the original, options->filter will have excess higher bit all
on, in addition to all the filter bits except for the all-or-none
bit.  I do not know offhand if that makes the difference, but I
trust that you have audited all uses of the options->filter flag
word and these high bits are truly unused and the difference does
not matter.

> +		options->filter &= ~options->filter_not;
> +	}

>  	for (i = 0; (optch = optarg[i]) != '\0'; i++) {
>  		unsigned int bit;
>  		int negate;
> @@ -4851,7 +4842,7 @@ static int diff_opt_diff_filter(const struct option *option,
>  			return error(_("unknown change class '%c' in --diff-filter=%s"),
>  				     optarg[i], optarg);
>  		if (negate)
> -			opt->filter &= ~bit;
> +			opt->filter_not |= bit;
>  		else
>  			opt->filter |= bit;
>  	}

And this ... 

> diff --git a/diff.h b/diff.h
> index 8ba85c5e605..a70e7c478c1 100644
> --- a/diff.h
> +++ b/diff.h
> @@ -283,7 +283,7 @@ struct diff_options {
>  	struct diff_flags flags;
>  
>  	/* diff-filter bits */
> -	unsigned int filter;
> +	unsigned int filter, filter_not;

... is exactly I wrote in the NEEDSWORK comment I gave you in my
earlier review.  Excellent.

> +test_expect_success 'multiple --diff-filter bits' '
> +
> +	git log -M --pretty="format:%s" --diff-filter=R HEAD >expect &&
> +	git log -M --pretty="format:%s" --diff-filter=Ra HEAD >actual &&
> +	test_cmp expect actual &&
> +	git log -M --pretty="format:%s" --diff-filter=aR HEAD >actual &&
> +	test_cmp expect actual &&
> +	git log -M --pretty="format:%s" \
> +		--diff-filter=a --diff-filter=R HEAD >actual &&
> +	test_cmp expect actual
> +
> +'

Good.

Thanks for noticing and fixing the long-standing issue.