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()maint
						commit
						01a2a03c56
					
				|  | @ -87,10 +87,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option) | ||||||
| { | { | ||||||
| 	int entries, i; | 	int entries, i; | ||||||
| 	int diff_unmerged_stage = revs->max_count; | 	int diff_unmerged_stage = revs->max_count; | ||||||
| 	int silent_on_removed = option & DIFF_SILENT_ON_REMOVED; |  | ||||||
| 	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED) | 	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED) | ||||||
| 			      ? CE_MATCH_RACY_IS_DIRTY : 0); | 			      ? CE_MATCH_RACY_IS_DIRTY : 0); | ||||||
|  |  | ||||||
|  | 	if (option & DIFF_SILENT_ON_REMOVED) | ||||||
|  | 		handle_deprecated_show_diff_q(&revs->diffopt); | ||||||
|  |  | ||||||
| 	diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); | 	diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); | ||||||
|  |  | ||||||
| 	if (diff_unmerged_stage < 0) | 	if (diff_unmerged_stage < 0) | ||||||
|  | @ -137,8 +139,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option) | ||||||
| 					perror(ce->name); | 					perror(ce->name); | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 				if (silent_on_removed) |  | ||||||
| 					continue; |  | ||||||
| 				wt_mode = 0; | 				wt_mode = 0; | ||||||
| 			} | 			} | ||||||
| 			dpath->mode = wt_mode; | 			dpath->mode = wt_mode; | ||||||
|  | @ -204,8 +204,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option) | ||||||
| 				perror(ce->name); | 				perror(ce->name); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (silent_on_removed) |  | ||||||
| 				continue; |  | ||||||
| 			diff_addremove(&revs->diffopt, '-', ce->ce_mode, | 			diff_addremove(&revs->diffopt, '-', ce->ce_mode, | ||||||
| 				       ce->sha1, !is_null_sha1(ce->sha1), | 				       ce->sha1, !is_null_sha1(ce->sha1), | ||||||
| 				       ce->name, 0); | 				       ce->name, 0); | ||||||
|  |  | ||||||
|  | @ -187,7 +187,7 @@ void diff_no_index(struct rev_info *revs, | ||||||
| { | { | ||||||
| 	int i, prefixlen; | 	int i, prefixlen; | ||||||
| 	int no_index = 0; | 	int no_index = 0; | ||||||
| 	unsigned options = 0; | 	unsigned deprecated_show_diff_q_option_used = 0; | ||||||
| 	const char *paths[2]; | 	const char *paths[2]; | ||||||
|  |  | ||||||
| 	/* Were we asked to do --no-index explicitly? */ | 	/* Were we asked to do --no-index explicitly? */ | ||||||
|  | @ -225,7 +225,7 @@ void diff_no_index(struct rev_info *revs, | ||||||
| 		if (!strcmp(argv[i], "--no-index")) | 		if (!strcmp(argv[i], "--no-index")) | ||||||
| 			i++; | 			i++; | ||||||
| 		else if (!strcmp(argv[i], "-q")) { | 		else if (!strcmp(argv[i], "-q")) { | ||||||
| 			options |= DIFF_SILENT_ON_REMOVED; | 			deprecated_show_diff_q_option_used = 1; | ||||||
| 			i++; | 			i++; | ||||||
| 		} | 		} | ||||||
| 		else if (!strcmp(argv[i], "--")) | 		else if (!strcmp(argv[i], "--")) | ||||||
|  | @ -260,6 +260,9 @@ void diff_no_index(struct rev_info *revs, | ||||||
| 	revs->max_count = -2; | 	revs->max_count = -2; | ||||||
| 	diff_setup_done(&revs->diffopt); | 	diff_setup_done(&revs->diffopt); | ||||||
|  |  | ||||||
|  | 	if (deprecated_show_diff_q_option_used) | ||||||
|  | 		handle_deprecated_show_diff_q(&revs->diffopt); | ||||||
|  |  | ||||||
| 	setup_diff_pager(&revs->diffopt); | 	setup_diff_pager(&revs->diffopt); | ||||||
| 	DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); | 	DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										125
									
								
								diff.c
								
								
								
								
							
							
						
						
									
										125
									
								
								diff.c
								
								
								
								
							|  | @ -3503,6 +3503,88 @@ static int parse_submodule_opt(struct diff_options *options, const char *value) | ||||||
| 	return 1; | 	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]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) | ||||||
|  | { | ||||||
|  | 	int i, optch; | ||||||
|  |  | ||||||
|  | 	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; | ||||||
|  |  | ||||||
|  | 		if ('a' <= optch && optch <= 'z') { | ||||||
|  | 			negate = 1; | ||||||
|  | 			optch = toupper(optch); | ||||||
|  | 		} else { | ||||||
|  | 			negate = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0; | ||||||
|  | 		if (!bit) | ||||||
|  | 			return optarg[i]; | ||||||
|  | 		if (negate) | ||||||
|  | 			opt->filter &= ~bit; | ||||||
|  | 		else | ||||||
|  | 			opt->filter |= bit; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Used only by "diff-files" and "diff --no-index" */ | ||||||
|  | void handle_deprecated_show_diff_q(struct diff_options *opt) | ||||||
|  | { | ||||||
|  | 	warning("'diff -q' and 'diff-files -q' are deprecated."); | ||||||
|  | 	warning("Use 'diff --diff-filter=d' instead to ignore deleted filepairs."); | ||||||
|  | 	parse_diff_filter_opt("d", opt); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void enable_patch_output(int *fmt) { | static void enable_patch_output(int *fmt) { | ||||||
| 	*fmt &= ~DIFF_FORMAT_NO_OUTPUT; | 	*fmt &= ~DIFF_FORMAT_NO_OUTPUT; | ||||||
| 	*fmt |= DIFF_FORMAT_PATCH; | 	*fmt |= DIFF_FORMAT_PATCH; | ||||||
|  | @ -3732,7 +3814,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) | ||||||
| 		return argcount; | 		return argcount; | ||||||
| 	} | 	} | ||||||
| 	else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { | 	else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { | ||||||
| 		options->filter = optarg; | 		int offending = parse_diff_filter_opt(optarg, options); | ||||||
|  | 		if (offending) | ||||||
|  | 			die("unknown change class '%c' in --diff-filter=%s", | ||||||
|  | 			    offending, optarg); | ||||||
| 		return argcount; | 		return argcount; | ||||||
| 	} | 	} | ||||||
| 	else if (!strcmp(arg, "--abbrev")) | 	else if (!strcmp(arg, "--abbrev")) | ||||||
|  | @ -4524,27 +4609,32 @@ free_queue: | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static void diffcore_apply_filter(const char *filter) | static int match_filter(const struct diff_options *options, const struct diff_filepair *p) | ||||||
|  | { | ||||||
|  | 	return (((p->status == DIFF_STATUS_MODIFIED) && | ||||||
|  | 		 ((p->score && | ||||||
|  | 		   filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) || | ||||||
|  | 		  (!p->score && | ||||||
|  | 		   filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) || | ||||||
|  | 		((p->status != DIFF_STATUS_MODIFIED) && | ||||||
|  | 		 filter_bit_tst(p->status, options))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void diffcore_apply_filter(struct diff_options *options) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	struct diff_queue_struct *q = &diff_queued_diff; | 	struct diff_queue_struct *q = &diff_queued_diff; | ||||||
| 	struct diff_queue_struct outq; | 	struct diff_queue_struct outq; | ||||||
|  |  | ||||||
| 	DIFF_QUEUE_CLEAR(&outq); | 	DIFF_QUEUE_CLEAR(&outq); | ||||||
|  |  | ||||||
| 	if (!filter) | 	if (!options->filter) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	if (strchr(filter, DIFF_STATUS_FILTER_AON)) { | 	if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) { | ||||||
| 		int found; | 		int found; | ||||||
| 		for (i = found = 0; !found && i < q->nr; i++) { | 		for (i = found = 0; !found && i < q->nr; i++) { | ||||||
| 			struct diff_filepair *p = q->queue[i]; | 			if (match_filter(options, q->queue[i])) | ||||||
| 			if (((p->status == DIFF_STATUS_MODIFIED) && |  | ||||||
| 			     ((p->score && |  | ||||||
| 			       strchr(filter, DIFF_STATUS_FILTER_BROKEN)) || |  | ||||||
| 			      (!p->score && |  | ||||||
| 			       strchr(filter, DIFF_STATUS_MODIFIED)))) || |  | ||||||
| 			    ((p->status != DIFF_STATUS_MODIFIED) && |  | ||||||
| 			     strchr(filter, p->status))) |  | ||||||
| 				found++; | 				found++; | ||||||
| 		} | 		} | ||||||
| 		if (found) | 		if (found) | ||||||
|  | @ -4562,14 +4652,7 @@ static void diffcore_apply_filter(const char *filter) | ||||||
| 		/* Only the matching ones */ | 		/* Only the matching ones */ | ||||||
| 		for (i = 0; i < q->nr; i++) { | 		for (i = 0; i < q->nr; i++) { | ||||||
| 			struct diff_filepair *p = q->queue[i]; | 			struct diff_filepair *p = q->queue[i]; | ||||||
|  | 			if (match_filter(options, p)) | ||||||
| 			if (((p->status == DIFF_STATUS_MODIFIED) && |  | ||||||
| 			     ((p->score && |  | ||||||
| 			       strchr(filter, DIFF_STATUS_FILTER_BROKEN)) || |  | ||||||
| 			      (!p->score && |  | ||||||
| 			       strchr(filter, DIFF_STATUS_MODIFIED)))) || |  | ||||||
| 			    ((p->status != DIFF_STATUS_MODIFIED) && |  | ||||||
| 			     strchr(filter, p->status))) |  | ||||||
| 				diff_q(&outq, p); | 				diff_q(&outq, p); | ||||||
| 			else | 			else | ||||||
| 				diff_free_filepair(p); | 				diff_free_filepair(p); | ||||||
|  | @ -4676,7 +4759,7 @@ void diffcore_std(struct diff_options *options) | ||||||
| 	if (!options->found_follow) | 	if (!options->found_follow) | ||||||
| 		/* See try_to_follow_renames() in tree-diff.c */ | 		/* See try_to_follow_renames() in tree-diff.c */ | ||||||
| 		diff_resolve_rename_copy(); | 		diff_resolve_rename_copy(); | ||||||
| 	diffcore_apply_filter(options->filter); | 	diffcore_apply_filter(options); | ||||||
|  |  | ||||||
| 	if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) | 	if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) | ||||||
| 		DIFF_OPT_SET(options, HAS_CHANGES); | 		DIFF_OPT_SET(options, HAS_CHANGES); | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								diff.h
								
								
								
								
							
							
						
						
									
										7
									
								
								diff.h
								
								
								
								
							|  | @ -103,12 +103,15 @@ enum diff_words_type { | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct diff_options { | struct diff_options { | ||||||
| 	const char *filter; |  | ||||||
| 	const char *orderfile; | 	const char *orderfile; | ||||||
| 	const char *pickaxe; | 	const char *pickaxe; | ||||||
| 	const char *single_follow; | 	const char *single_follow; | ||||||
| 	const char *a_prefix, *b_prefix; | 	const char *a_prefix, *b_prefix; | ||||||
| 	unsigned flags; | 	unsigned flags; | ||||||
|  |  | ||||||
|  | 	/* diff-filter bits */ | ||||||
|  | 	unsigned int filter; | ||||||
|  |  | ||||||
| 	int use_color; | 	int use_color; | ||||||
| 	int context; | 	int context; | ||||||
| 	int interhunkcontext; | 	int interhunkcontext; | ||||||
|  | @ -338,6 +341,8 @@ extern int parse_rename_score(const char **cp_p); | ||||||
|  |  | ||||||
| extern long parse_algorithm_value(const char *value); | extern long parse_algorithm_value(const char *value); | ||||||
|  |  | ||||||
|  | extern void handle_deprecated_show_diff_q(struct diff_options *); | ||||||
|  |  | ||||||
| extern int print_stat_summary(FILE *fp, int files, | extern int print_stat_summary(FILE *fp, int files, | ||||||
| 			      int insertions, int deletions); | 			      int insertions, int deletions); | ||||||
| extern void setup_diff_pager(struct diff_options *); | extern void setup_diff_pager(struct diff_options *); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano