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`
This commit is contained in:
Junio C Hamano 2022-02-16 15:14:30 -08:00
Родитель 70ff41ffcf 75408ca949
Коммит 9a160990ef
4 изменённых файлов: 60 добавлений и 59 удалений

Просмотреть файл

@ -628,11 +628,8 @@ ifndef::git-format-patch[]
Also, these upper-case letters can be downcased to exclude. E.g.
`--diff-filter=ad` excludes added and deleted paths.
+
Note that not all diffs can feature all types. For instance, diffs
from the index to the working tree can never have Added entries
(because the set of paths included in the diff is limited by what is in
the index). Similarly, copied and renamed entries cannot appear if
detection for those types is disabled.
Note that not all diffs can feature all types. For instance, copied and
renamed entries cannot appear if detection for those types is disabled.
-S<string>::
Look for differences that change the number of occurrences of

97
diff.c
Просмотреть файл

@ -4613,6 +4613,43 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
prep_parse_options(options);
}
static const char diff_status_letters[] = {
DIFF_STATUS_ADDED,
DIFF_STATUS_COPIED,
DIFF_STATUS_DELETED,
DIFF_STATUS_MODIFIED,
DIFF_STATUS_RENAMED,
DIFF_STATUS_TYPE_CHANGED,
DIFF_STATUS_UNKNOWN,
DIFF_STATUS_UNMERGED,
DIFF_STATUS_FILTER_AON,
DIFF_STATUS_FILTER_BROKEN,
'\0',
};
static unsigned int filter_bit['Z' + 1];
static void prepare_filter_bits(void)
{
int i;
if (!filter_bit[DIFF_STATUS_ADDED]) {
for (i = 0; diff_status_letters[i]; i++)
filter_bit[(int) diff_status_letters[i]] = (1 << i);
}
}
static unsigned filter_bit_tst(char status, const struct diff_options *opt)
{
return opt->filter & filter_bit[(int) status];
}
unsigned diff_filter_bit(char status)
{
prepare_filter_bits();
return filter_bit[(int) status];
}
void diff_setup_done(struct diff_options *options)
{
unsigned check_mask = DIFF_FORMAT_NAME |
@ -4726,6 +4763,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];
options->filter &= ~options->filter_not;
}
FREE_AND_NULL(options->parseopts);
}
@ -4817,43 +4860,6 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params)
return 1;
}
static const char diff_status_letters[] = {
DIFF_STATUS_ADDED,
DIFF_STATUS_COPIED,
DIFF_STATUS_DELETED,
DIFF_STATUS_MODIFIED,
DIFF_STATUS_RENAMED,
DIFF_STATUS_TYPE_CHANGED,
DIFF_STATUS_UNKNOWN,
DIFF_STATUS_UNMERGED,
DIFF_STATUS_FILTER_AON,
DIFF_STATUS_FILTER_BROKEN,
'\0',
};
static unsigned int filter_bit['Z' + 1];
static void prepare_filter_bits(void)
{
int i;
if (!filter_bit[DIFF_STATUS_ADDED]) {
for (i = 0; diff_status_letters[i]; i++)
filter_bit[(int) diff_status_letters[i]] = (1 << i);
}
}
static unsigned filter_bit_tst(char status, const struct diff_options *opt)
{
return opt->filter & filter_bit[(int) status];
}
unsigned diff_filter_bit(char status)
{
prepare_filter_bits();
return filter_bit[(int) status];
}
static int diff_opt_diff_filter(const struct option *option,
const char *optarg, int unset)
{
@ -4863,21 +4869,6 @@ static int diff_opt_diff_filter(const struct option *option,
BUG_ON_OPT_NEG(unset);
prepare_filter_bits();
/*
* 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.
*/
if (!opt->filter) {
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
if (optch < 'a' || 'z' < optch)
continue;
opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
break;
}
}
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
unsigned int bit;
int negate;
@ -4894,7 +4885,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;
}

2
diff.h
Просмотреть файл

@ -283,7 +283,7 @@ struct diff_options {
struct diff_flags flags;
/* diff-filter bits */
unsigned int filter;
unsigned int filter, filter_not;
int use_color;

Просмотреть файл

@ -142,6 +142,19 @@ test_expect_success 'diff-filter=R' '
'
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
'
test_expect_success 'diff-filter=C' '
git log -C -C --pretty="format:%s" --diff-filter=C HEAD >actual &&