From: Junio C Hamano <gitster@pobox.com>
To: "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
Cc: git@vger.kernel.org, Johannes Schindelin <johannes.schindelin@gmx.de>
Subject: Re: [PATCH 2/2] diff-filter: be more careful when looking for negative bits
Date: Tue, 25 Jan 2022 23:23:28 -0800 [thread overview]
Message-ID: <xmqq1r0vt0y7.fsf@gitster.g> (raw)
In-Reply-To: e8006493a9ed4da9b9125865e004ba7ace20e7a4.1643149759.git.gitgitgadget@gmail.com
"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:
> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> The `--diff-filter=<bits>` option allows to filter the diff by certain
> criteria, for example `R` to only show renamed files. It also supports
> negating a filter via a down-cased letter, i.e. `r` to show _everything
> but_ renamed files.
[jc: Squashable fix-up attached at the end]
>
> However, the code is a bit overzealous when trying to figure out whether
> `git diff` should start with all diff-filters turned on because the user
> provided a lower-case letter: if the `--diff-filter` argument starts
> with an upper-case letter, we must not start with all bits turned on.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
> diff.c | 8 +++-----
> t/t4202-log.sh | 8 ++++++++
> 2 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/diff.c b/diff.c
> index c862771a589..fc1151b9c73 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -4821,17 +4821,15 @@ static int diff_opt_diff_filter(const struct option *option,
> prepare_filter_bits();
>
> /*
> - * If there is a negation e.g. 'd' in the input, and we haven't
> + * If the input starts with a negation e.g. 'd', and we haven't
> * initialized the filter field with another --diff-filter, start
> * from full set of bits, except for AON.
> */
> if (!opt->filter) {
> - for (i = 0; (optch = optarg[i]) != '\0'; i++) {
> - if (optch < 'a' || 'z' < optch)
> - continue;
> + optch = optarg[0];
> + if (optch >= 'a' && 'z' >= optch) {
Style. When both sides of && must be satisfied, list these three
things in the order that should appear. For example,
if ('z' >= optch && optch >= 'a')
is OK because it makes it clear that optch sits between 'z' and 'a'
for the expression to be true. The existing one is also OK for the
same reason. The condition holds when either optch is below
(i.e. comes before) 'a', or it is above (i.e. comes after) 'z', so
if (optch < 'a' || 'z' < optch)
orders them naturally. Also
if ('a' <= optch && optch <= 'z')
is good for the same reason as the first example, but probably is
better because the three things are ordered from smaller to larger,
which is usually how people count things.
I'd usually let this pass if it were new code, but because the patch
breaks the ordering the existing code has, it is a different story.
But more importantly, I do not know if the updated code is correct.
> opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
> opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
> - break;
> }
> }
While the finding in the cover letter (i.e. "--diff-filter=Dr does
not work as expected") is certainly good, I do not know about this
implementation. "--diff-filter=rD" and "--diff-filter=Dr" ought to
behave the same way, but if we base our logic on optarg[0], then the
first letter and only the first letter is made special, which does
not smell right.
> diff --git a/t/t4202-log.sh b/t/t4202-log.sh
> index 50495598619..28f727937dd 100755
> --- a/t/t4202-log.sh
> +++ b/t/t4202-log.sh
> @@ -142,6 +142,14 @@ test_expect_success 'diff-filter=R' '
>
> '
>
> +test_expect_success 'diff-filter=Ra' '
> +
> + 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
> +
In other words, this should work the same way, no?
> + git log -M --pretty="format:%s" --diff-filter=aR HEAD >actual &&
> +'
> +
> test_expect_success 'diff-filter=C' '
>
> git log -C -C --pretty="format:%s" --diff-filter=C HEAD >actual &&
------------------------------------------------------------
diff.c | 31 ++++++++++++++++++++++++++++---
t/t4202-log.sh | 4 +++-
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/diff.c b/diff.c
index fc1151b9c7..a57e458f63 100644
--- a/diff.c
+++ b/diff.c
@@ -4821,13 +4821,38 @@ static int diff_opt_diff_filter(const struct option *option,
prepare_filter_bits();
/*
- * If the input starts with a negation e.g. 'd', and we haven't
+ * If there is a negation e.g. 'd' in the input, and we haven't
* initialized the filter field with another --diff-filter, start
* from full set of bits, except for AON.
+ * However, the user can try to limit to selected positive bits,
+ * in which case we do not have to.
+ *
+ * NEEDSWORK: the "we haven't initialied" above is meant to
+ * address cases where multiple options, e.g. --diff-filter=d
+ * --diff-filter=a are given. But this implementation is
+ * insufficient when we refrain from starting from full set
+ * when any positive bit is given. Consider "--diff-filter=D
+ * --diff-filter=r", which ought to behave the same way as
+ * "--diff-filter=Dr" and "--diff-filter=rD". The right fix
+ * would probably involve two "opt->filter[NP]" fields,
+ * records positive and negative bits separately in them while
+ * parsing, and then after processing all options, compute
+ * opt->filter by subtracting opt->filterN from opt->filterP
+ * (and when we do so, fill opt->filterP to full bits if it is
+ * absolutely empty).
*/
if (!opt->filter) {
- optch = optarg[0];
- if (optch >= 'a' && 'z' >= optch) {
+ int has_positive = 0;
+ int has_negative = 0;
+
+ for (i = 0; (optch = optarg[i]) != '\0'; i++) {
+ if (optch < 'a' || 'z' < optch)
+ has_positive++;
+ else
+ has_negative++;
+ }
+
+ if (!has_positive && has_negative) {
opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
}
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 28f727937d..128183e66f 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -142,10 +142,12 @@ test_expect_success 'diff-filter=R' '
'
-test_expect_success 'diff-filter=Ra' '
+test_expect_success 'diff-filter=Ra and aR' '
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
'
--
2.35.0-155-g0eb5153edc
next prev parent reply other threads:[~2022-01-26 7:23 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-25 22:29 [PATCH 0/2] Fix two --diff-filter bugs Johannes Schindelin via GitGitGadget
2022-01-25 22:29 ` [PATCH 1/2] docs(diff): lose incorrect claim about `diff-files --diff-filter=A` Johannes Schindelin via GitGitGadget
2022-01-26 7:03 ` Junio C Hamano
2022-01-25 22:29 ` [PATCH 2/2] diff-filter: be more careful when looking for negative bits Johannes Schindelin via GitGitGadget
2022-01-25 23:21 ` Taylor Blau
2022-01-28 11:52 ` Johannes Schindelin
2022-01-26 7:23 ` Junio C Hamano [this message]
2022-01-26 22:55 ` Taylor Blau
2022-01-26 23:36 ` Junio C Hamano
2022-01-28 11:54 ` Johannes Schindelin
2022-01-26 17:57 ` Ævar Arnfjörð Bjarmason
2022-01-27 19:08 ` [PATCH v2 0/3] Fix two --diff-filter bugs Johannes Schindelin via GitGitGadget
2022-01-27 19:08 ` [PATCH v2 1/3] docs(diff): lose incorrect claim about `diff-files --diff-filter=A` Johannes Schindelin via GitGitGadget
2022-01-27 19:08 ` [PATCH v2 2/3] diff.c: move the diff filter bits definitions up a bit Johannes Schindelin via GitGitGadget
2022-01-27 19:08 ` [PATCH v2 3/3] diff-filter: be more careful when looking for negative bits Johannes Schindelin via GitGitGadget
2022-01-28 1:16 ` Junio C Hamano
2022-01-28 12:01 ` Johannes Schindelin
2022-01-28 12:02 ` [PATCH v3 0/3] Fix two --diff-filter bugs Johannes Schindelin via GitGitGadget
2022-01-28 12:02 ` [PATCH v3 1/3] docs(diff): lose incorrect claim about `diff-files --diff-filter=A` Johannes Schindelin via GitGitGadget
2022-01-28 12:02 ` [PATCH v3 2/3] diff.c: move the diff filter bits definitions up a bit Johannes Schindelin via GitGitGadget
2022-01-28 12:02 ` [PATCH v3 3/3] diff-filter: be more careful when looking for negative bits Johannes Schindelin via GitGitGadget
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=xmqq1r0vt0y7.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
--cc=gitgitgadget@gmail.com \
--cc=johannes.schindelin@gmx.de \
/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;
as well as URLs for NNTP newsgroup(s).