From: Junio C Hamano Date: Tue, 23 Jan 2018 21:16:37 +0000 (-0800) Subject: Merge branch 'sb/diff-blobfind-pickaxe' X-Git-Tag: v2.17.0-rc0~147 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/c0d75f0e2e2cbf432358bfd00be593fd28e257a3?ds=inline;hp=-c Merge branch 'sb/diff-blobfind-pickaxe' "diff" family of commands learned "--find-object=" option to limit the findings to changes that involve the named object. * sb/diff-blobfind-pickaxe: diff: use HAS_MULTI_BITS instead of counting bits manually diff: properly error out when combining multiple pickaxe options diffcore: add a pickaxe option to find a specific blob diff: introduce DIFF_PICKAXE_KINDS_MASK diff: migrate diff_flags.pickaxe_ignore_case to a pickaxe_opts bit diff.h: make pickaxe_opts an unsigned bit field --- c0d75f0e2e2cbf432358bfd00be593fd28e257a3 diff --combined Documentation/diff-options.txt index 743af97b06,f9cf85db05..c330c01ff0 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@@ -80,16 -80,6 +80,16 @@@ endif::git-format-patch[ --histogram:: Generate a diff using the "histogram diff" algorithm. +--anchored=:: + Generate a diff using the "anchored diff" algorithm. ++ +This option may be specified more than once. ++ +If a line exists in both the source and destination, exists only once, +and starts with this text, this algorithm attempts to prevent it from +appearing as a deletion or addition in the output. It uses the "patience +diff" algorithm internally. + --diff-algorithm={patience|minimal|histogram|myers}:: Choose a diff algorithm. The variants are as follows: + @@@ -469,12 -459,6 +469,12 @@@ 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. -S:: Look for differences that change the number of occurrences of @@@ -508,6 -492,15 +508,15 @@@ occurrences of that string did not chan See the 'pickaxe' entry in linkgit:gitdiffcore[7] for more information. + --find-object=:: + Look for differences that change the number of occurrences of + the specified object. Similar to `-S`, just the argument is different + in that it doesn't search for a specific string but for a specific + object id. + + + The object can be a blob or a submodule commit. It implies the `-t` option in + `git-log` to also find trees. + --pickaxe-all:: When `-S` or `-G` finds a change, show all the changes in that changeset, not just the files that contain the change @@@ -516,6 -509,7 +525,7 @@@ --pickaxe-regex:: Treat the given to `-S` as an extended POSIX regular expression to match. + endif::git-format-patch[] -O:: @@@ -573,9 -567,6 +583,9 @@@ endif::git-format-patch[ --text:: Treat all files as text. +--ignore-cr-at-eol:: + Ignore carrige-return at the end of line when doing a comparison. + --ignore-space-at-eol:: Ignore changes in whitespace at EOL. diff --combined builtin/log.c index 14fdf39165,bd6f2d1efb..46b4ca13e5 --- a/builtin/log.c +++ b/builtin/log.c @@@ -142,19 -142,11 +142,19 @@@ static void cmd_log_init_finish(int arg struct userformat_want w; int quiet = 0, source = 0, mailmap = 0; static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP}; + static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP; + static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP; + struct decoration_filter decoration_filter = {&decorate_refs_include, + &decorate_refs_exclude}; const struct option builtin_log_options[] = { OPT__QUIET(&quiet, N_("suppress diff output")), OPT_BOOL(0, "source", &source, N_("show source")), OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")), + OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include, + N_("pattern"), N_("only decorate refs that match ")), + OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude, + N_("pattern"), N_("do not decorate refs that match ")), { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"), PARSE_OPT_OPTARG, decorate_callback}, OPT_CALLBACK('L', NULL, &line_cb, "n,m:file", @@@ -188,8 -180,8 +188,8 @@@ if (rev->show_notes) init_display_notes(&rev->notes_opt); - if (rev->diffopt.pickaxe || rev->diffopt.filter || - rev->diffopt.flags.follow_renames) + if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) || + rev->diffopt.filter || rev->diffopt.flags.follow_renames) rev->always_show_header = 0; if (source) @@@ -213,7 -205,7 +213,7 @@@ if (decoration_style) { rev->show_decorations = 1; - load_ref_decorations(decoration_style); + load_ref_decorations(&decoration_filter, decoration_style); } if (rev->line_level_traverse) diff --combined diff.c index db4696fdf5,c2ee81a1fa..0a9a0cdf18 --- a/diff.c +++ b/diff.c @@@ -246,7 -246,7 +246,7 @@@ static int parse_ws_error_highlight(con */ void init_diff_ui_defaults(void) { - diff_detect_rename_default = 1; + diff_detect_rename_default = DIFF_DETECT_RENAME; } int git_diff_heuristic_config(const char *var, const char *value, void *cb) @@@ -3210,8 -3210,6 +3210,8 @@@ static void builtin_diff(const char *na ecbdata.opt = o; ecbdata.header = header.len ? &header : NULL; xpp.flags = o->xdl_opts; + xpp.anchors = o->anchors; + xpp.anchors_nr = o->anchors_nr; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; xecfg.flags = XDL_EMIT_FUNCNAMES; @@@ -3304,8 -3302,6 +3304,8 @@@ static void builtin_diffstat(const cha memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = o->xdl_opts; + xpp.anchors = o->anchors; + xpp.anchors_nr = o->anchors_nr; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, @@@ -4086,6 -4082,7 +4086,7 @@@ void diff_setup(struct diff_options *op options->interhunkcontext = diff_interhunk_context_default; options->ws_error_highlight = ws_error_highlight_default; options->flags.rename_empty = 1; + options->objfind = NULL; /* pathchange left =NULL by default */ options->change = diff_change; @@@ -4110,22 -4107,20 +4111,20 @@@ void diff_setup_done(struct diff_options *options) { - int count = 0; + unsigned check_mask = DIFF_FORMAT_NAME | + DIFF_FORMAT_NAME_STATUS | + DIFF_FORMAT_CHECKDIFF | + DIFF_FORMAT_NO_OUTPUT; if (options->set_default) options->set_default(options); - if (options->output_format & DIFF_FORMAT_NAME) - count++; - if (options->output_format & DIFF_FORMAT_NAME_STATUS) - count++; - if (options->output_format & DIFF_FORMAT_CHECKDIFF) - count++; - if (options->output_format & DIFF_FORMAT_NO_OUTPUT) - count++; - if (count > 1) + if (HAS_MULTI_BITS(options->output_format & check_mask)) die(_("--name-only, --name-status, --check and -s are mutually exclusive")); + if (HAS_MULTI_BITS(options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK)) + die(_("-G, -S and --find-object are mutually exclusive")); + /* * Most of the time we can say "there are changes" * only by checking if there are changed paths, but @@@ -4133,7 -4128,9 +4132,7 @@@ * inside contents. */ - if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) || - DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) || - DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL)) + if ((options->xdl_opts & XDF_WHITESPACE_FLAGS)) options->flags.diff_from_contents = 1; else options->flags.diff_from_contents = 0; @@@ -4175,7 -4172,7 +4174,7 @@@ /* * Also pickaxe would not work very well if you do not say recursive */ - if (options->pickaxe) + if (options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) options->flags.recursive = 1; /* * When patches are generated, submodules diffed against the work tree @@@ -4489,6 -4486,23 +4488,23 @@@ static int parse_ws_error_highlight_opt return 1; } + static int parse_objfind_opt(struct diff_options *opt, const char *arg) + { + struct object_id oid; + + if (get_oid(arg, &oid)) + return error("unable to resolve '%s'", arg); + + if (!opt->objfind) + opt->objfind = xcalloc(1, sizeof(*opt->objfind)); + + opt->pickaxe_opts |= DIFF_PICKAXE_KIND_OBJFIND; + opt->flags.recursive = 1; + opt->flags.tree_in_recursive = 1; + oidset_insert(opt->objfind, &oid); + return 1; + } + int diff_opt_parse(struct diff_options *options, const char **av, int ac, const char *prefix) { @@@ -4512,12 -4526,17 +4528,12 @@@ options->output_format |= DIFF_FORMAT_NUMSTAT; else if (!strcmp(arg, "--shortstat")) options->output_format |= DIFF_FORMAT_SHORTSTAT; - else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat")) - return parse_dirstat_opt(options, ""); - else if (skip_prefix(arg, "-X", &arg)) - return parse_dirstat_opt(options, arg); - else if (skip_prefix(arg, "--dirstat=", &arg)) + else if (skip_prefix(arg, "-X", &arg) || + skip_to_optional_arg(arg, "--dirstat", &arg)) return parse_dirstat_opt(options, arg); else if (!strcmp(arg, "--cumulative")) return parse_dirstat_opt(options, "cumulative"); - else if (!strcmp(arg, "--dirstat-by-file")) - return parse_dirstat_opt(options, "files"); - else if (skip_prefix(arg, "--dirstat-by-file=", &arg)) { + else if (skip_to_optional_arg(arg, "--dirstat-by-file", &arg)) { parse_dirstat_opt(options, "files"); return parse_dirstat_opt(options, arg); } @@@ -4539,13 -4558,13 +4555,13 @@@ return stat_opt(options, av); /* renames options */ - else if (starts_with(arg, "-B") || starts_with(arg, "--break-rewrites=") || - !strcmp(arg, "--break-rewrites")) { + else if (starts_with(arg, "-B") || + skip_to_optional_arg(arg, "--break-rewrites", NULL)) { if ((options->break_opt = diff_scoreopt_parse(arg)) == -1) return error("invalid argument to -B: %s", arg+2); } - else if (starts_with(arg, "-M") || starts_with(arg, "--find-renames=") || - !strcmp(arg, "--find-renames")) { + else if (starts_with(arg, "-M") || + skip_to_optional_arg(arg, "--find-renames", NULL)) { if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) return error("invalid argument to -M: %s", arg+2); options->detect_rename = DIFF_DETECT_RENAME; @@@ -4553,8 -4572,8 +4569,8 @@@ else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) { options->irreversible_delete = 1; } - else if (starts_with(arg, "-C") || starts_with(arg, "--find-copies=") || - !strcmp(arg, "--find-copies")) { + else if (starts_with(arg, "-C") || + skip_to_optional_arg(arg, "--find-copies", NULL)) { if (options->detect_rename == DIFF_DETECT_COPY) options->flags.find_copies_harder = 1; if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) @@@ -4567,10 -4586,11 +4583,10 @@@ options->flags.rename_empty = 1; else if (!strcmp(arg, "--no-rename-empty")) options->flags.rename_empty = 0; - else if (!strcmp(arg, "--relative")) - options->flags.relative_name = 1; - else if (skip_prefix(arg, "--relative=", &arg)) { + else if (skip_to_optional_arg_default(arg, "--relative", &arg, NULL)) { options->flags.relative_name = 1; - options->prefix = arg; + if (arg) + options->prefix = arg; } /* xdiff options */ @@@ -4584,26 -4604,15 +4600,26 @@@ DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE); else if (!strcmp(arg, "--ignore-space-at-eol")) DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); + else if (!strcmp(arg, "--ignore-cr-at-eol")) + DIFF_XDL_SET(options, IGNORE_CR_AT_EOL); else if (!strcmp(arg, "--ignore-blank-lines")) DIFF_XDL_SET(options, IGNORE_BLANK_LINES); else if (!strcmp(arg, "--indent-heuristic")) DIFF_XDL_SET(options, INDENT_HEURISTIC); else if (!strcmp(arg, "--no-indent-heuristic")) DIFF_XDL_CLR(options, INDENT_HEURISTIC); - else if (!strcmp(arg, "--patience")) + else if (!strcmp(arg, "--patience")) { + int i; options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); - else if (!strcmp(arg, "--histogram")) + /* + * Both --patience and --anchored use PATIENCE_DIFF + * internally, so remove any anchors previously + * specified. + */ + for (i = 0; i < options->anchors_nr; i++) + free(options->anchors[i]); + options->anchors_nr = 0; + } else if (!strcmp(arg, "--histogram")) options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF); else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) { long value = parse_algorithm_value(optarg); @@@ -4615,11 -4624,6 +4631,11 @@@ options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK; options->xdl_opts |= value; return argcount; + } else if (skip_prefix(arg, "--anchored=", &arg)) { + options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); + ALLOC_GROW(options->anchors, options->anchors_nr + 1, + options->anchors_alloc); + options->anchors[options->anchors_nr++] = xstrdup(arg); } /* flags options */ @@@ -4640,7 -4644,9 +4656,7 @@@ else if (!strcmp(arg, "--no-follow")) { options->flags.follow_renames = 0; options->flags.default_follow_renames = 0; - } else if (!strcmp(arg, "--color")) - options->use_color = 1; - else if (skip_prefix(arg, "--color=", &arg)) { + } else if (skip_to_optional_arg_default(arg, "--color", &arg, "always")) { int value = git_config_colorbool(NULL, arg); if (value < 0) return error("option `color' expects \"always\", \"auto\", or \"never\""); @@@ -4660,10 -4666,15 +4676,10 @@@ if (cm < 0) die("bad --color-moved argument: %s", arg); options->color_moved = cm; - } else if (!strcmp(arg, "--color-words")) { + } else if (skip_to_optional_arg_default(arg, "--color-words", &options->word_regex, NULL)) { options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } - else if (skip_prefix(arg, "--color-words=", &arg)) { - options->use_color = 1; - options->word_diff = DIFF_WORDS_COLOR; - options->word_regex = arg; - } else if (!strcmp(arg, "--word-diff")) { if (options->word_diff == DIFF_WORDS_NONE) options->word_diff = DIFF_WORDS_PLAIN; @@@ -4701,10 -4712,15 +4717,10 @@@ options->flags.textconv_set_via_cmdline = 1; } else if (!strcmp(arg, "--no-textconv")) options->flags.allow_textconv = 0; - else if (!strcmp(arg, "--ignore-submodules")) { - options->flags.override_submodule_config = 1; - handle_ignore_submodules_arg(options, "all"); - } else if (skip_prefix(arg, "--ignore-submodules=", &arg)) { + else if (skip_to_optional_arg_default(arg, "--ignore-submodules", &arg, "all")) { options->flags.override_submodule_config = 1; handle_ignore_submodules_arg(options, arg); - } else if (!strcmp(arg, "--submodule")) - options->submodule_format = DIFF_SUBMODULE_LOG; - else if (skip_prefix(arg, "--submodule=", &arg)) + } else if (skip_to_optional_arg_default(arg, "--submodule", &arg, "log")) return parse_submodule_opt(options, arg); else if (skip_prefix(arg, "--ws-error-highlight=", &arg)) return parse_ws_error_highlight_opt(options, arg); @@@ -4736,7 -4752,8 +4752,8 @@@ else if ((argcount = short_opt('O', av, &optarg))) { options->orderfile = prefix_filename(prefix, optarg); return argcount; - } + } else if (skip_prefix(arg, "--find-object=", &arg)) + return parse_objfind_opt(options, arg); else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { int offending = parse_diff_filter_opt(optarg, options); if (offending) @@@ -4902,20 -4919,14 +4919,20 @@@ const char *diff_aligned_abbrev(const s int abblen; const char *abbrev; + /* Do we want all 40 hex characters? */ if (len == GIT_SHA1_HEXSZ) return oid_to_hex(oid); + /* An abbreviated value is fine, possibly followed by an ellipsis. */ abbrev = diff_abbrev_oid(oid, len); + + if (!print_sha1_ellipsis()) + return abbrev; + abblen = strlen(abbrev); /* - * In well-behaved cases, where the abbbreviated result is the + * In well-behaved cases, where the abbreviated result is the * same as the requested length, append three dots after the * abbreviation (hence the whole logic is limited to the case * where abblen < 37); when the actual abbreviated result is a @@@ -5460,7 -5471,7 +5477,7 @@@ void diff_warn_rename_limit(const char warning(_(rename_limit_warning)); else return; - if (0 < needed && needed < 32767) + if (0 < needed) warning(_(rename_limit_advice), varname, needed); } @@@ -5783,7 -5794,7 +5800,7 @@@ void diffcore_std(struct diff_options * if (options->break_opt != -1) diffcore_merge_broken(); } - if (options->pickaxe) + if (options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) diffcore_pickaxe(options); if (options->orderfile) diffcore_order(options->orderfile); diff --combined diff.h index 7cf276f077,8a56cac2ad..6bd278aac1 --- a/diff.h +++ b/diff.h @@@ -7,6 -7,7 +7,7 @@@ #include "tree-walk.h" #include "pathspec.h" #include "object.h" + #include "oidset.h" struct rev_info; struct diff_options; @@@ -91,7 -92,6 +92,6 @@@ struct diff_flags unsigned override_submodule_config:1; unsigned dirstat_by_line:1; unsigned funccontext:1; - unsigned pickaxe_ignore_case:1; unsigned default_follow_renames:1; }; @@@ -146,7 -146,7 +146,7 @@@ struct diff_options int skip_stat_unmatch; int line_termination; int output_format; - int pickaxe_opts; + unsigned pickaxe_opts; int rename_score; int rename_limit; int needed_rename_limit; @@@ -166,10 -166,6 +166,10 @@@ const char *stat_sep; long xdl_opts; + /* see Documentation/diff-options.txt */ + char **anchors; + size_t anchors_nr, anchors_alloc; + int stat_width; int stat_name_width; int stat_graph_width; @@@ -178,6 -174,8 +178,8 @@@ enum diff_words_type word_diff; enum diff_submodule_format submodule_format; + struct oidset *objfind; + /* this is set by diffcore for DIFF_FORMAT_PATCH */ int found_changes; @@@ -330,6 -328,13 +332,13 @@@ extern void diff_setup_done(struct diff #define DIFF_PICKAXE_KIND_S 4 /* traditional plumbing counter */ #define DIFF_PICKAXE_KIND_G 8 /* grep in the patch */ + #define DIFF_PICKAXE_KIND_OBJFIND 16 /* specific object IDs */ + + #define DIFF_PICKAXE_KINDS_MASK (DIFF_PICKAXE_KIND_S | \ + DIFF_PICKAXE_KIND_G | \ + DIFF_PICKAXE_KIND_OBJFIND) + + #define DIFF_PICKAXE_IGNORE_CASE 32 extern void diffcore_std(struct diff_options *); extern void diffcore_fix_diff_index(struct diff_options *); diff --combined revision.c index 1f7454c947,30f65b3bbd..a60628fbff --- a/revision.c +++ b/revision.c @@@ -1832,7 -1832,7 +1832,7 @@@ static int handle_revision_opt(struct r revs->simplify_by_decoration = 1; revs->limited = 1; revs->prune = 1; - load_ref_decorations(DECORATE_SHORT_REFS); + load_ref_decorations(NULL, DECORATE_SHORT_REFS); } else if (!strcmp(arg, "--date-order")) { revs->sort_order = REV_SORT_BY_COMMIT_DATE; revs->topo_order = 1; @@@ -1855,8 -1855,6 +1855,8 @@@ revs->dense = 0; } else if (!strcmp(arg, "--show-all")) { revs->show_all = 1; + } else if (!strcmp(arg, "--in-commit-order")) { + revs->tree_blobs_in_commit_order = 1; } else if (!strcmp(arg, "--remove-empty")) { revs->remove_empty_trees = 1; } else if (!strcmp(arg, "--merges")) { @@@ -2078,7 -2076,7 +2078,7 @@@ revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_ERE; } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) { revs->grep_filter.ignore_case = 1; - revs->diffopt.flags.pickaxe_ignore_case = 1; + revs->diffopt.pickaxe_opts |= DIFF_PICKAXE_IGNORE_CASE; } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) { revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_FIXED; } else if (!strcmp(arg, "--perl-regexp") || !strcmp(arg, "-P")) { @@@ -2409,11 -2407,14 +2409,14 @@@ int setup_revisions(int argc, const cha revs->diff = 1; /* Pickaxe, diff-filter and rename following need diffs */ - if (revs->diffopt.pickaxe || + if ((revs->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) || revs->diffopt.filter || revs->diffopt.flags.follow_renames) revs->diff = 1; + if (revs->diffopt.objfind) + revs->simplify_history = 0; + if (revs->topo_order) revs->limited = 1; @@@ -2862,7 -2863,8 +2865,7 @@@ int prepare_revision_walk(struct rev_in } } } - if (!revs->leak_pending) - object_array_clear(&old_pending); + object_array_clear(&old_pending); /* Signal whether we need per-parent treesame decoration */ if (revs->simplify_merges ||