Skip to content

Commit 01a2a03

Browse files
committed
Merge branch 'jc/diff-filter-negation'
Teach "git diff --diff-filter" to express "I do not want to see these classes of changes" more directly by listing only the unwanted ones in lowercase (e.g. "--diff-filter=d" will show everything but deletion) and deprecate "diff-files -q" which did the same thing as "--diff-filter=d". * jc/diff-filter-negation: diff: deprecate -q option to diff-files diff: allow lowercase letter to specify what change class to exclude diff: reject unknown change class given to --diff-filter diff: preparse --diff-filter string argument diff: factor out match_filter() diff: pass the whole diff_options to diffcore_apply_filter()
2 parents a5e10f8 + 95a7c54 commit 01a2a03

File tree

4 files changed

+118
-29
lines changed

4 files changed

+118
-29
lines changed

diff-lib.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
8787
{
8888
int entries, i;
8989
int diff_unmerged_stage = revs->max_count;
90-
int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
9190
unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
9291
? CE_MATCH_RACY_IS_DIRTY : 0);
9392

93+
if (option & DIFF_SILENT_ON_REMOVED)
94+
handle_deprecated_show_diff_q(&revs->diffopt);
95+
9496
diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
9597

9698
if (diff_unmerged_stage < 0)
@@ -137,8 +139,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
137139
perror(ce->name);
138140
continue;
139141
}
140-
if (silent_on_removed)
141-
continue;
142142
wt_mode = 0;
143143
}
144144
dpath->mode = wt_mode;
@@ -204,8 +204,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
204204
perror(ce->name);
205205
continue;
206206
}
207-
if (silent_on_removed)
208-
continue;
209207
diff_addremove(&revs->diffopt, '-', ce->ce_mode,
210208
ce->sha1, !is_null_sha1(ce->sha1),
211209
ce->name, 0);

diff-no-index.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ void diff_no_index(struct rev_info *revs,
187187
{
188188
int i, prefixlen;
189189
int no_index = 0;
190-
unsigned options = 0;
190+
unsigned deprecated_show_diff_q_option_used = 0;
191191
const char *paths[2];
192192

193193
/* Were we asked to do --no-index explicitly? */
@@ -225,7 +225,7 @@ void diff_no_index(struct rev_info *revs,
225225
if (!strcmp(argv[i], "--no-index"))
226226
i++;
227227
else if (!strcmp(argv[i], "-q")) {
228-
options |= DIFF_SILENT_ON_REMOVED;
228+
deprecated_show_diff_q_option_used = 1;
229229
i++;
230230
}
231231
else if (!strcmp(argv[i], "--"))
@@ -260,6 +260,9 @@ void diff_no_index(struct rev_info *revs,
260260
revs->max_count = -2;
261261
diff_setup_done(&revs->diffopt);
262262

263+
if (deprecated_show_diff_q_option_used)
264+
handle_deprecated_show_diff_q(&revs->diffopt);
265+
263266
setup_diff_pager(&revs->diffopt);
264267
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
265268

diff.c

Lines changed: 104 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,6 +3503,88 @@ static int parse_submodule_opt(struct diff_options *options, const char *value)
35033503
return 1;
35043504
}
35053505

3506+
static const char diff_status_letters[] = {
3507+
DIFF_STATUS_ADDED,
3508+
DIFF_STATUS_COPIED,
3509+
DIFF_STATUS_DELETED,
3510+
DIFF_STATUS_MODIFIED,
3511+
DIFF_STATUS_RENAMED,
3512+
DIFF_STATUS_TYPE_CHANGED,
3513+
DIFF_STATUS_UNKNOWN,
3514+
DIFF_STATUS_UNMERGED,
3515+
DIFF_STATUS_FILTER_AON,
3516+
DIFF_STATUS_FILTER_BROKEN,
3517+
'\0',
3518+
};
3519+
3520+
static unsigned int filter_bit['Z' + 1];
3521+
3522+
static void prepare_filter_bits(void)
3523+
{
3524+
int i;
3525+
3526+
if (!filter_bit[DIFF_STATUS_ADDED]) {
3527+
for (i = 0; diff_status_letters[i]; i++)
3528+
filter_bit[(int) diff_status_letters[i]] = (1 << i);
3529+
}
3530+
}
3531+
3532+
static unsigned filter_bit_tst(char status, const struct diff_options *opt)
3533+
{
3534+
return opt->filter & filter_bit[(int) status];
3535+
}
3536+
3537+
static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt)
3538+
{
3539+
int i, optch;
3540+
3541+
prepare_filter_bits();
3542+
3543+
/*
3544+
* If there is a negation e.g. 'd' in the input, and we haven't
3545+
* initialized the filter field with another --diff-filter, start
3546+
* from full set of bits, except for AON.
3547+
*/
3548+
if (!opt->filter) {
3549+
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
3550+
if (optch < 'a' || 'z' < optch)
3551+
continue;
3552+
opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
3553+
opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
3554+
break;
3555+
}
3556+
}
3557+
3558+
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
3559+
unsigned int bit;
3560+
int negate;
3561+
3562+
if ('a' <= optch && optch <= 'z') {
3563+
negate = 1;
3564+
optch = toupper(optch);
3565+
} else {
3566+
negate = 0;
3567+
}
3568+
3569+
bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0;
3570+
if (!bit)
3571+
return optarg[i];
3572+
if (negate)
3573+
opt->filter &= ~bit;
3574+
else
3575+
opt->filter |= bit;
3576+
}
3577+
return 0;
3578+
}
3579+
3580+
/* Used only by "diff-files" and "diff --no-index" */
3581+
void handle_deprecated_show_diff_q(struct diff_options *opt)
3582+
{
3583+
warning("'diff -q' and 'diff-files -q' are deprecated.");
3584+
warning("Use 'diff --diff-filter=d' instead to ignore deleted filepairs.");
3585+
parse_diff_filter_opt("d", opt);
3586+
}
3587+
35063588
static void enable_patch_output(int *fmt) {
35073589
*fmt &= ~DIFF_FORMAT_NO_OUTPUT;
35083590
*fmt |= DIFF_FORMAT_PATCH;
@@ -3732,7 +3814,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
37323814
return argcount;
37333815
}
37343816
else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
3735-
options->filter = optarg;
3817+
int offending = parse_diff_filter_opt(optarg, options);
3818+
if (offending)
3819+
die("unknown change class '%c' in --diff-filter=%s",
3820+
offending, optarg);
37363821
return argcount;
37373822
}
37383823
else if (!strcmp(arg, "--abbrev"))
@@ -4524,27 +4609,32 @@ void diff_flush(struct diff_options *options)
45244609
}
45254610
}
45264611

4527-
static void diffcore_apply_filter(const char *filter)
4612+
static int match_filter(const struct diff_options *options, const struct diff_filepair *p)
4613+
{
4614+
return (((p->status == DIFF_STATUS_MODIFIED) &&
4615+
((p->score &&
4616+
filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) ||
4617+
(!p->score &&
4618+
filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) ||
4619+
((p->status != DIFF_STATUS_MODIFIED) &&
4620+
filter_bit_tst(p->status, options)));
4621+
}
4622+
4623+
static void diffcore_apply_filter(struct diff_options *options)
45284624
{
45294625
int i;
45304626
struct diff_queue_struct *q = &diff_queued_diff;
45314627
struct diff_queue_struct outq;
4628+
45324629
DIFF_QUEUE_CLEAR(&outq);
45334630

4534-
if (!filter)
4631+
if (!options->filter)
45354632
return;
45364633

4537-
if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
4634+
if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) {
45384635
int found;
45394636
for (i = found = 0; !found && i < q->nr; i++) {
4540-
struct diff_filepair *p = q->queue[i];
4541-
if (((p->status == DIFF_STATUS_MODIFIED) &&
4542-
((p->score &&
4543-
strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
4544-
(!p->score &&
4545-
strchr(filter, DIFF_STATUS_MODIFIED)))) ||
4546-
((p->status != DIFF_STATUS_MODIFIED) &&
4547-
strchr(filter, p->status)))
4637+
if (match_filter(options, q->queue[i]))
45484638
found++;
45494639
}
45504640
if (found)
@@ -4562,14 +4652,7 @@ static void diffcore_apply_filter(const char *filter)
45624652
/* Only the matching ones */
45634653
for (i = 0; i < q->nr; i++) {
45644654
struct diff_filepair *p = q->queue[i];
4565-
4566-
if (((p->status == DIFF_STATUS_MODIFIED) &&
4567-
((p->score &&
4568-
strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
4569-
(!p->score &&
4570-
strchr(filter, DIFF_STATUS_MODIFIED)))) ||
4571-
((p->status != DIFF_STATUS_MODIFIED) &&
4572-
strchr(filter, p->status)))
4655+
if (match_filter(options, p))
45734656
diff_q(&outq, p);
45744657
else
45754658
diff_free_filepair(p);
@@ -4676,7 +4759,7 @@ void diffcore_std(struct diff_options *options)
46764759
if (!options->found_follow)
46774760
/* See try_to_follow_renames() in tree-diff.c */
46784761
diff_resolve_rename_copy();
4679-
diffcore_apply_filter(options->filter);
4762+
diffcore_apply_filter(options);
46804763

46814764
if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
46824765
DIFF_OPT_SET(options, HAS_CHANGES);

diff.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,15 @@ enum diff_words_type {
103103
};
104104

105105
struct diff_options {
106-
const char *filter;
107106
const char *orderfile;
108107
const char *pickaxe;
109108
const char *single_follow;
110109
const char *a_prefix, *b_prefix;
111110
unsigned flags;
111+
112+
/* diff-filter bits */
113+
unsigned int filter;
114+
112115
int use_color;
113116
int context;
114117
int interhunkcontext;
@@ -338,6 +341,8 @@ extern int parse_rename_score(const char **cp_p);
338341

339342
extern long parse_algorithm_value(const char *value);
340343

344+
extern void handle_deprecated_show_diff_q(struct diff_options *);
345+
341346
extern int print_stat_summary(FILE *fp, int files,
342347
int insertions, int deletions);
343348
extern void setup_diff_pager(struct diff_options *);

0 commit comments

Comments
 (0)