Skip to content

Commit 9a16099

Browse files
committed
Merge branch 'js/diff-filter-negation-fix'
"git diff --diff-filter=aR" is now parsed correctly. * js/diff-filter-negation-fix: diff-filter: be more careful when looking for negative bits diff.c: move the diff filter bits definitions up a bit docs(diff): lose incorrect claim about `diff-files --diff-filter=A`
2 parents 70ff41f + 75408ca commit 9a16099

File tree

4 files changed

+60
-59
lines changed

4 files changed

+60
-59
lines changed

Documentation/diff-options.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -628,11 +628,8 @@ ifndef::git-format-patch[]
628628
Also, these upper-case letters can be downcased to exclude. E.g.
629629
`--diff-filter=ad` excludes added and deleted paths.
630630
+
631-
Note that not all diffs can feature all types. For instance, diffs
632-
from the index to the working tree can never have Added entries
633-
(because the set of paths included in the diff is limited by what is in
634-
the index). Similarly, copied and renamed entries cannot appear if
635-
detection for those types is disabled.
631+
Note that not all diffs can feature all types. For instance, copied and
632+
renamed entries cannot appear if detection for those types is disabled.
636633

637634
-S<string>::
638635
Look for differences that change the number of occurrences of

diff.c

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4613,6 +4613,43 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
46134613
prep_parse_options(options);
46144614
}
46154615

4616+
static const char diff_status_letters[] = {
4617+
DIFF_STATUS_ADDED,
4618+
DIFF_STATUS_COPIED,
4619+
DIFF_STATUS_DELETED,
4620+
DIFF_STATUS_MODIFIED,
4621+
DIFF_STATUS_RENAMED,
4622+
DIFF_STATUS_TYPE_CHANGED,
4623+
DIFF_STATUS_UNKNOWN,
4624+
DIFF_STATUS_UNMERGED,
4625+
DIFF_STATUS_FILTER_AON,
4626+
DIFF_STATUS_FILTER_BROKEN,
4627+
'\0',
4628+
};
4629+
4630+
static unsigned int filter_bit['Z' + 1];
4631+
4632+
static void prepare_filter_bits(void)
4633+
{
4634+
int i;
4635+
4636+
if (!filter_bit[DIFF_STATUS_ADDED]) {
4637+
for (i = 0; diff_status_letters[i]; i++)
4638+
filter_bit[(int) diff_status_letters[i]] = (1 << i);
4639+
}
4640+
}
4641+
4642+
static unsigned filter_bit_tst(char status, const struct diff_options *opt)
4643+
{
4644+
return opt->filter & filter_bit[(int) status];
4645+
}
4646+
4647+
unsigned diff_filter_bit(char status)
4648+
{
4649+
prepare_filter_bits();
4650+
return filter_bit[(int) status];
4651+
}
4652+
46164653
void diff_setup_done(struct diff_options *options)
46174654
{
46184655
unsigned check_mask = DIFF_FORMAT_NAME |
@@ -4726,6 +4763,12 @@ void diff_setup_done(struct diff_options *options)
47264763
if (!options->use_color || external_diff())
47274764
options->color_moved = 0;
47284765

4766+
if (options->filter_not) {
4767+
if (!options->filter)
4768+
options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON];
4769+
options->filter &= ~options->filter_not;
4770+
}
4771+
47294772
FREE_AND_NULL(options->parseopts);
47304773
}
47314774

@@ -4817,43 +4860,6 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params)
48174860
return 1;
48184861
}
48194862

4820-
static const char diff_status_letters[] = {
4821-
DIFF_STATUS_ADDED,
4822-
DIFF_STATUS_COPIED,
4823-
DIFF_STATUS_DELETED,
4824-
DIFF_STATUS_MODIFIED,
4825-
DIFF_STATUS_RENAMED,
4826-
DIFF_STATUS_TYPE_CHANGED,
4827-
DIFF_STATUS_UNKNOWN,
4828-
DIFF_STATUS_UNMERGED,
4829-
DIFF_STATUS_FILTER_AON,
4830-
DIFF_STATUS_FILTER_BROKEN,
4831-
'\0',
4832-
};
4833-
4834-
static unsigned int filter_bit['Z' + 1];
4835-
4836-
static void prepare_filter_bits(void)
4837-
{
4838-
int i;
4839-
4840-
if (!filter_bit[DIFF_STATUS_ADDED]) {
4841-
for (i = 0; diff_status_letters[i]; i++)
4842-
filter_bit[(int) diff_status_letters[i]] = (1 << i);
4843-
}
4844-
}
4845-
4846-
static unsigned filter_bit_tst(char status, const struct diff_options *opt)
4847-
{
4848-
return opt->filter & filter_bit[(int) status];
4849-
}
4850-
4851-
unsigned diff_filter_bit(char status)
4852-
{
4853-
prepare_filter_bits();
4854-
return filter_bit[(int) status];
4855-
}
4856-
48574863
static int diff_opt_diff_filter(const struct option *option,
48584864
const char *optarg, int unset)
48594865
{
@@ -4863,21 +4869,6 @@ static int diff_opt_diff_filter(const struct option *option,
48634869
BUG_ON_OPT_NEG(unset);
48644870
prepare_filter_bits();
48654871

4866-
/*
4867-
* If there is a negation e.g. 'd' in the input, and we haven't
4868-
* initialized the filter field with another --diff-filter, start
4869-
* from full set of bits, except for AON.
4870-
*/
4871-
if (!opt->filter) {
4872-
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
4873-
if (optch < 'a' || 'z' < optch)
4874-
continue;
4875-
opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
4876-
opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
4877-
break;
4878-
}
4879-
}
4880-
48814872
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
48824873
unsigned int bit;
48834874
int negate;
@@ -4894,7 +4885,7 @@ static int diff_opt_diff_filter(const struct option *option,
48944885
return error(_("unknown change class '%c' in --diff-filter=%s"),
48954886
optarg[i], optarg);
48964887
if (negate)
4897-
opt->filter &= ~bit;
4888+
opt->filter_not |= bit;
48984889
else
48994890
opt->filter |= bit;
49004891
}

diff.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ struct diff_options {
283283
struct diff_flags flags;
284284

285285
/* diff-filter bits */
286-
unsigned int filter;
286+
unsigned int filter, filter_not;
287287

288288
int use_color;
289289

t/t4202-log.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,19 @@ test_expect_success 'diff-filter=R' '
142142
143143
'
144144

145+
test_expect_success 'multiple --diff-filter bits' '
146+
147+
git log -M --pretty="format:%s" --diff-filter=R HEAD >expect &&
148+
git log -M --pretty="format:%s" --diff-filter=Ra HEAD >actual &&
149+
test_cmp expect actual &&
150+
git log -M --pretty="format:%s" --diff-filter=aR HEAD >actual &&
151+
test_cmp expect actual &&
152+
git log -M --pretty="format:%s" \
153+
--diff-filter=a --diff-filter=R HEAD >actual &&
154+
test_cmp expect actual
155+
156+
'
157+
145158
test_expect_success 'diff-filter=C' '
146159
147160
git log -C -C --pretty="format:%s" --diff-filter=C HEAD >actual &&

0 commit comments

Comments
 (0)