Merge branch 'jc/hold-diff-remove-q-synonym-for-no-deletion'
authorJunio C Hamano <gitster@pobox.com>
Fri, 7 Mar 2014 23:17:40 +0000 (15:17 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 7 Mar 2014 23:17:41 +0000 (15:17 -0800)
Remove a confusing and deprecated "-q" option from "git diff-files";
"git diff-files --diff-filter=d" can be used instead.

1  2 
diff-lib.c
diff-no-index.c
diff.c
diff.h
diff --combined diff-lib.c
index ec5f722eff72ba3dff4b64f0961fa8e65a259170,872643f6305ad2e1980b57651d0ceacf882938df..044872935c30d84affb1955a7ae03c0986c90bda
@@@ -11,7 -11,6 +11,7 @@@
  #include "unpack-trees.h"
  #include "refs.h"
  #include "submodule.h"
 +#include "dir.h"
  
  /*
   * diff-files
@@@ -65,9 -64,8 +65,9 @@@ static int check_removed(const struct c
   * commits, untracked content and/or modified content).
   */
  static int match_stat_with_submodule(struct diff_options *diffopt,
 -                                    struct cache_entry *ce, struct stat *st,
 -                                    unsigned ce_option, unsigned *dirty_submodule)
 +                                   const struct cache_entry *ce,
 +                                   struct stat *st, unsigned ce_option,
 +                                   unsigned *dirty_submodule)
  {
        int changed = ce_match_stat(ce, st, ce_option);
        if (S_ISGITLINK(ce->ce_mode)) {
@@@ -91,9 -89,6 +91,6 @@@ int run_diff_files(struct rev_info *rev
        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
                              ? 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/");
  
        if (diff_unmerged_stage < 0)
                if (diff_can_quit_early(&revs->diffopt))
                        break;
  
 -              if (!ce_path_match(ce, &revs->prune_data))
 +              if (!ce_path_match(ce, &revs->prune_data, NULL))
                        continue;
  
                if (ce_stage(ce)) {
                        dpath->path = (char *) &(dpath->parent[5]);
  
                        dpath->next = NULL;
 -                      dpath->len = path_len;
                        memcpy(dpath->path, ce->name, path_len);
                        dpath->path[path_len] = '\0';
                        hashclr(dpath->sha1);
  /* A file entry went away or appeared */
  static void diff_index_show_file(struct rev_info *revs,
                                 const char *prefix,
 -                               struct cache_entry *ce,
 +                               const struct cache_entry *ce,
                                 const unsigned char *sha1, int sha1_valid,
                                 unsigned int mode,
                                 unsigned dirty_submodule)
                       sha1, sha1_valid, ce->name, dirty_submodule);
  }
  
 -static int get_stat_data(struct cache_entry *ce,
 +static int get_stat_data(const struct cache_entry *ce,
                         const unsigned char **sha1p,
                         unsigned int *modep,
                         int cached, int match_missing,
  }
  
  static void show_new_file(struct rev_info *revs,
 -                        struct cache_entry *new,
 +                        const struct cache_entry *new,
                          int cached, int match_missing)
  {
        const unsigned char *sha1;
  }
  
  static int show_modified(struct rev_info *revs,
 -                       struct cache_entry *old,
 -                       struct cache_entry *new,
 +                       const struct cache_entry *old,
 +                       const struct cache_entry *new,
                         int report_missing,
                         int cached, int match_missing)
  {
                p = xmalloc(combine_diff_path_size(2, pathlen));
                p->path = (char *) &p->parent[2];
                p->next = NULL;
 -              p->len = pathlen;
                memcpy(p->path, new->name, pathlen);
                p->path[pathlen] = 0;
                p->mode = mode;
   * give you the position and number of entries in the index).
   */
  static void do_oneway_diff(struct unpack_trees_options *o,
 -      struct cache_entry *idx,
 -      struct cache_entry *tree)
 +                         const struct cache_entry *idx,
 +                         const struct cache_entry *tree)
  {
        struct rev_info *revs = o->unpack_data;
        int match_missing, cached;
   * the fairly complex unpack_trees() semantic requirements, including
   * the skipping, the path matching, the type conflict cases etc.
   */
 -static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
 +static int oneway_diff(const struct cache_entry * const *src,
 +                     struct unpack_trees_options *o)
  {
 -      struct cache_entry *idx = src[0];
 -      struct cache_entry *tree = src[1];
 +      const struct cache_entry *idx = src[0];
 +      const struct cache_entry *tree = src[1];
        struct rev_info *revs = o->unpack_data;
  
        /*
        if (tree == o->df_conflict_entry)
                tree = NULL;
  
 -      if (ce_path_match(idx ? idx : tree, &revs->prune_data)) {
 +      if (ce_path_match(idx ? idx : tree, &revs->prune_data, NULL)) {
                do_oneway_diff(o, idx, tree);
                if (diff_can_quit_early(&revs->diffopt)) {
                        o->exiting_early = 1;
@@@ -473,6 -469,7 +470,6 @@@ static int diff_cache(struct rev_info *
        opts.dst_index = NULL;
        opts.pathspec = &revs->diffopt.pathspec;
        opts.pathspec->recursive = 1;
 -      opts.pathspec->max_depth = -1;
  
        init_tree_desc(&t, tree->buffer, tree->size);
        return unpack_trees(1, &t, &opts);
@@@ -498,7 -495,7 +495,7 @@@ int do_diff_cache(const unsigned char *
        struct rev_info revs;
  
        init_revisions(&revs, NULL);
 -      init_pathspec(&revs.prune_data, opt->pathspec.raw);
 +      copy_pathspec(&revs.prune_data, &opt->pathspec);
        revs.diffopt = *opt;
  
        if (diff_cache(&revs, tree_sha1, NULL, 1))
diff --combined diff-no-index.c
index 33e5982a1c61a5726580f40df0a07dadc7e2aaf1,98a9cf1322068b97ad017e2747f3f0f4d313bda7..8e10bff30e5269687e67866c2d3c66d62e3bb883
@@@ -45,7 -45,7 +45,7 @@@ static int get_mode(const char *path, i
  
        if (!path || !strcmp(path, "/dev/null"))
                *mode = 0;
 -#ifdef _WIN32
 +#ifdef GIT_WINDOWS_NATIVE
        else if (!strcasecmp(path, "nul"))
                *mode = 0;
  #endif
@@@ -183,21 -183,46 +183,16 @@@ static int queue_diff(struct diff_optio
  
  void diff_no_index(struct rev_info *revs,
                   int argc, const char **argv,
 -                 int nongit, const char *prefix)
 +                 const char *prefix)
  {
        int i, prefixlen;
-       unsigned deprecated_show_diff_q_option_used = 0;
 -      int no_index = 0;
        const char *paths[2];
  
 -      /* Were we asked to do --no-index explicitly? */
 -      for (i = 1; i < argc; i++) {
 -              if (!strcmp(argv[i], "--")) {
 -                      i++;
 -                      break;
 -              }
 -              if (!strcmp(argv[i], "--no-index"))
 -                      no_index = 1;
 -              if (argv[i][0] != '-')
 -                      break;
 -      }
 -
 -      if (!no_index && !nongit) {
 -              /*
 -               * Inside a git repository, without --no-index.  Only
 -               * when a path outside the repository is given,
 -               * e.g. "git diff /var/tmp/[12]", or "git diff
 -               * Makefile /var/tmp/Makefile", allow it to be used as
 -               * a colourful "diff" replacement.
 -               */
 -              if ((argc != i + 2) ||
 -                  (path_inside_repo(prefix, argv[i]) &&
 -                   path_inside_repo(prefix, argv[i+1])))
 -                      return;
 -      }
 -      if (argc != i + 2)
 -              usagef("git diff %s <path> <path>",
 -                     no_index ? "--no-index" : "[--no-index]");
 -
        diff_setup(&revs->diffopt);
        for (i = 1; i < argc - 2; ) {
                int j;
                if (!strcmp(argv[i], "--no-index"))
                        i++;
-               else if (!strcmp(argv[i], "-q")) {
-                       deprecated_show_diff_q_option_used = 1;
-                       i++;
-               }
                else if (!strcmp(argv[i], "--"))
                        i++;
                else {
        revs->max_count = -2;
        diff_setup_done(&revs->diffopt);
  
-       if (deprecated_show_diff_q_option_used)
-               handle_deprecated_show_diff_q(&revs->diffopt);
        setup_diff_pager(&revs->diffopt);
        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
  
diff --combined diff.c
index e8006666d8a528689157aed0e84d23a5477111be,2d0b5e33f93065172f3a85a22ac8ed643089a53e..7c59bfe2d08edd8fe0f13b5487c1af34043d7ef1
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -30,7 -30,6 +30,7 @@@ static int diff_use_color_default = -1
  static int diff_context_default = 3;
  static const char *diff_word_regex_cfg;
  static const char *external_diff_cmd_cfg;
 +static const char *diff_order_file_cfg;
  int diff_auto_refresh_index = 1;
  static int diff_mnemonic_prefix;
  static int diff_no_prefix;
@@@ -202,8 -201,6 +202,8 @@@ int git_diff_ui_config(const char *var
                return git_config_string(&external_diff_cmd_cfg, var, value);
        if (!strcmp(var, "diff.wordregex"))
                return git_config_string(&diff_word_regex_cfg, var, value);
 +      if (!strcmp(var, "diff.orderfile"))
 +              return git_config_pathname(&diff_order_file_cfg, var, value);
  
        if (!strcmp(var, "diff.ignoresubmodules"))
                handle_ignore_submodules_arg(&default_diff_options, value);
@@@ -238,7 -235,7 +238,7 @@@ int git_diff_basic_config(const char *v
        if (userdiff_config(var, value) < 0)
                return -1;
  
 -      if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
 +      if (starts_with(var, "diff.color.") || starts_with(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
                if (slot < 0)
                        return 0;
                return 0;
        }
  
 -      if (!prefixcmp(var, "submodule."))
 +      if (starts_with(var, "submodule."))
                return parse_submodule_config_option(var, value);
  
        return git_default_config(var, value, cb);
@@@ -672,7 -669,7 +672,7 @@@ static void emit_rewrite_diff(const cha
        memset(&ecbdata, 0, sizeof(ecbdata));
        ecbdata.color_diff = want_color(o->use_color);
        ecbdata.found_changesp = &o->found_changes;
 -      ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
 +      ecbdata.ws_rule = whitespace_rule(name_b);
        ecbdata.opt = o;
        if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
                mmfile_t mf1, mf2;
@@@ -1218,7 -1215,7 +1218,7 @@@ static void fn_out_consume(void *priv, 
                        diff_words_append(line, len,
                                          &ecbdata->diff_words->plus);
                        return;
 -              } else if (!prefixcmp(line, "\\ ")) {
 +              } else if (starts_with(line, "\\ ")) {
                        /*
                         * Eat the "no newline at eof" marker as if we
                         * saw a "+" or "-" line with nothing on it,
@@@ -1686,7 -1683,9 +1686,7 @@@ static void show_stats(struct diffstat_
                del = deleted;
  
                if (graph_width <= max_change) {
 -                      int total = add + del;
 -
 -                      total = scale_linear(add + del, graph_width, max_change);
 +                      int total = scale_linear(add + del, graph_width, max_change);
                        if (total < 2 && add && del)
                                /* width >= 2 due to the sanity check */
                                total = 2;
@@@ -2255,8 -2254,7 +2255,8 @@@ static void builtin_diff(const char *na
                        (!two->mode || S_ISGITLINK(two->mode))) {
                const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
                const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
 -              show_submodule_summary(o->file, one ? one->path : two->path,
 +              show_submodule_summary(o->file, one->path ? one->path : two->path,
 +                              line_prefix,
                                one->sha1, two->sha1, two->dirty_submodule,
                                meta, del, add, reset);
                return;
                ecbdata.label_path = lbl;
                ecbdata.color_diff = want_color(o->use_color);
                ecbdata.found_changesp = &o->found_changes;
 -              ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
 +              ecbdata.ws_rule = whitespace_rule(name_b);
                if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
                        check_blank_at_eof(&mf1, &mf2, &ecbdata);
                ecbdata.opt = o;
                        xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
                if (!diffopts)
                        ;
 -              else if (!prefixcmp(diffopts, "--unified="))
 +              else if (starts_with(diffopts, "--unified="))
                        xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
 -              else if (!prefixcmp(diffopts, "-u"))
 +              else if (starts_with(diffopts, "-u"))
                        xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
                if (o->word_diff)
                        init_diff_words_data(&ecbdata, o, one, two);
@@@ -2587,7 -2585,7 +2587,7 @@@ void fill_filespec(struct diff_filespe
   */
  static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
  {
 -      struct cache_entry *ce;
 +      const struct cache_entry *ce;
        struct stat st;
        int pos, len;
  
@@@ -2678,14 -2676,6 +2678,14 @@@ static int diff_populate_gitlink(struc
  int diff_populate_filespec(struct diff_filespec *s, int size_only)
  {
        int err = 0;
 +      /*
 +       * demote FAIL to WARN to allow inspecting the situation
 +       * instead of refusing.
 +       */
 +      enum safe_crlf crlf_warn = (safe_crlf == SAFE_CRLF_FAIL
 +                                  ? SAFE_CRLF_WARN
 +                                  : safe_crlf);
 +
        if (!DIFF_FILE_VALID(s))
                die("internal error: asking to populate invalid file.");
        if (S_ISDIR(s->mode))
                /*
                 * Convert from working tree format to canonical git format
                 */
 -              if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
 +              if (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {
                        size_t size = 0;
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
@@@ -2902,16 -2892,11 +2902,16 @@@ static void run_external_diff(const cha
                              struct diff_filespec *one,
                              struct diff_filespec *two,
                              const char *xfrm_msg,
 -                            int complete_rewrite)
 +                            int complete_rewrite,
 +                            struct diff_options *o)
  {
        const char *spawn_arg[10];
        int retval;
        const char **arg = &spawn_arg[0];
 +      struct diff_queue_struct *q = &diff_queued_diff;
 +      const char *env[3] = { NULL };
 +      char env_counter[50];
 +      char env_total[50];
  
        if (one && two) {
                struct diff_tempfile *temp_one, *temp_two;
        }
        *arg = NULL;
        fflush(NULL);
 -      retval = run_command_v_opt(spawn_arg, RUN_USING_SHELL);
 +
 +      env[0] = env_counter;
 +      snprintf(env_counter, sizeof(env_counter), "GIT_DIFF_PATH_COUNTER=%d",
 +               ++o->diff_path_counter);
 +      env[1] = env_total;
 +      snprintf(env_total, sizeof(env_total), "GIT_DIFF_PATH_TOTAL=%d", q->nr);
 +
 +      retval = run_command_v_opt_cd_env(spawn_arg, RUN_USING_SHELL, NULL, env);
        remove_tempfile();
        if (retval) {
                fprintf(stderr, "external diff died, stopping at %s.\n", name);
@@@ -3057,7 -3035,7 +3057,7 @@@ static void run_diff_cmd(const char *pg
  
        if (pgm) {
                run_external_diff(pgm, name, other, one, two, xfrm_msg,
 -                                complete_rewrite);
 +                                complete_rewrite, o);
                return;
        }
        if (one && two)
@@@ -3222,8 -3200,6 +3222,8 @@@ void diff_setup(struct diff_options *op
        options->detect_rename = diff_detect_rename_default;
        options->xdl_opts |= diff_algorithm;
  
 +      options->orderfile = diff_order_file_cfg;
 +
        if (diff_no_prefix) {
                options->a_prefix = options->b_prefix = "";
        } else if (!diff_mnemonic_prefix) {
@@@ -3236,9 -3212,6 +3236,9 @@@ void diff_setup_done(struct diff_option
  {
        int count = 0;
  
 +      if (options->set_default)
 +              options->set_default(options);
 +
        if (options->output_format & DIFF_FORMAT_NAME)
                count++;
        if (options->output_format & DIFF_FORMAT_NAME_STATUS)
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
 +
 +      options->diff_path_counter = 0;
  }
  
  static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
@@@ -3410,10 -3381,10 +3410,10 @@@ int parse_long_opt(const char *opt, con
        if (arg[0] != '-' || arg[1] != '-')
                return 0;
        arg += strlen("--");
 -      if (prefixcmp(arg, opt))
 +      if (!starts_with(arg, opt))
                return 0;
        arg += strlen(opt);
 -      if (*arg == '=') { /* sticked form: --option=value */
 +      if (*arg == '=') { /* stuck form: --option=value */
                *optarg = arg + 1;
                return 1;
        }
@@@ -3441,7 -3412,7 +3441,7 @@@ static int stat_opt(struct diff_option
  
        switch (*arg) {
        case '-':
 -              if (!prefixcmp(arg, "-width")) {
 +              if (starts_with(arg, "-width")) {
                        arg += strlen("-width");
                        if (*arg == '=')
                                width = strtoul(arg + 1, &end, 10);
                                width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
 -              } else if (!prefixcmp(arg, "-name-width")) {
 +              } else if (starts_with(arg, "-name-width")) {
                        arg += strlen("-name-width");
                        if (*arg == '=')
                                name_width = strtoul(arg + 1, &end, 10);
                                name_width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
 -              } else if (!prefixcmp(arg, "-graph-width")) {
 +              } else if (starts_with(arg, "-graph-width")) {
                        arg += strlen("-graph-width");
                        if (*arg == '=')
                                graph_width = strtoul(arg + 1, &end, 10);
                                graph_width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
 -              } else if (!prefixcmp(arg, "-count")) {
 +              } else if (starts_with(arg, "-count")) {
                        arg += strlen("-count");
                        if (*arg == '=')
                                count = strtoul(arg + 1, &end, 10);
@@@ -3599,19 -3570,6 +3599,11 @@@ static int parse_diff_filter_opt(const 
        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) {
 +      *fmt &= ~DIFF_FORMAT_NO_OUTPUT;
 +      *fmt |= DIFF_FORMAT_PATCH;
 +}
 +
  int diff_opt_parse(struct diff_options *options, const char **av, int ac)
  {
        const char *arg = av[0];
        int argcount;
  
        /* Output format options */
 -      if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch"))
 -              options->output_format |= DIFF_FORMAT_PATCH;
 -      else if (opt_arg(arg, 'U', "unified", &options->context))
 -              options->output_format |= DIFF_FORMAT_PATCH;
 +      if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch")
 +          || opt_arg(arg, 'U', "unified", &options->context))
 +              enable_patch_output(&options->output_format);
        else if (!strcmp(arg, "--raw"))
                options->output_format |= DIFF_FORMAT_RAW;
 -      else if (!strcmp(arg, "--patch-with-raw"))
 -              options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
 -      else if (!strcmp(arg, "--numstat"))
 +      else if (!strcmp(arg, "--patch-with-raw")) {
 +              enable_patch_output(&options->output_format);
 +              options->output_format |= DIFF_FORMAT_RAW;
 +      } else if (!strcmp(arg, "--numstat"))
                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 (!prefixcmp(arg, "-X"))
 +      else if (starts_with(arg, "-X"))
                return parse_dirstat_opt(options, arg + 2);
 -      else if (!prefixcmp(arg, "--dirstat="))
 +      else if (starts_with(arg, "--dirstat="))
                return parse_dirstat_opt(options, arg + 10);
        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 (!prefixcmp(arg, "--dirstat-by-file=")) {
 +      else if (starts_with(arg, "--dirstat-by-file=")) {
                parse_dirstat_opt(options, "files");
                return parse_dirstat_opt(options, arg + 18);
        }
                options->output_format |= DIFF_FORMAT_CHECKDIFF;
        else if (!strcmp(arg, "--summary"))
                options->output_format |= DIFF_FORMAT_SUMMARY;
 -      else if (!strcmp(arg, "--patch-with-stat"))
 -              options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
 -      else if (!strcmp(arg, "--name-only"))
 +      else if (!strcmp(arg, "--patch-with-stat")) {
 +              enable_patch_output(&options->output_format);
 +              options->output_format |= DIFF_FORMAT_DIFFSTAT;
 +      } else if (!strcmp(arg, "--name-only"))
                options->output_format |= DIFF_FORMAT_NAME;
        else if (!strcmp(arg, "--name-status"))
                options->output_format |= DIFF_FORMAT_NAME_STATUS;
 -      else if (!strcmp(arg, "-s"))
 +      else if (!strcmp(arg, "-s") || !strcmp(arg, "--no-patch"))
                options->output_format |= DIFF_FORMAT_NO_OUTPUT;
 -      else if (!prefixcmp(arg, "--stat"))
 +      else if (starts_with(arg, "--stat"))
                /* --stat, --stat-width, --stat-name-width, or --stat-count */
                return stat_opt(options, av);
  
        /* renames options */
 -      else if (!prefixcmp(arg, "-B") || !prefixcmp(arg, "--break-rewrites=") ||
 +      else if (starts_with(arg, "-B") || starts_with(arg, "--break-rewrites=") ||
                 !strcmp(arg, "--break-rewrites")) {
                if ((options->break_opt = diff_scoreopt_parse(arg)) == -1)
                        return error("invalid argument to -B: %s", arg+2);
        }
 -      else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--find-renames=") ||
 +      else if (starts_with(arg, "-M") || starts_with(arg, "--find-renames=") ||
                 !strcmp(arg, "--find-renames")) {
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return error("invalid argument to -M: %s", arg+2);
        else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) {
                options->irreversible_delete = 1;
        }
 -      else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") ||
 +      else if (starts_with(arg, "-C") || starts_with(arg, "--find-copies=") ||
                 !strcmp(arg, "--find-copies")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
                        DIFF_OPT_SET(options, FIND_COPIES_HARDER);
                DIFF_OPT_CLR(options, RENAME_EMPTY);
        else if (!strcmp(arg, "--relative"))
                DIFF_OPT_SET(options, RELATIVE_NAME);
 -      else if (!prefixcmp(arg, "--relative=")) {
 +      else if (starts_with(arg, "--relative=")) {
                DIFF_OPT_SET(options, RELATIVE_NAME);
                options->prefix = arg + 11;
        }
                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-blank-lines"))
 +              DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
        else if (!strcmp(arg, "--patience"))
                options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
        else if (!strcmp(arg, "--histogram"))
  
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
 -              options->output_format |= DIFF_FORMAT_PATCH;
 +              enable_patch_output(&options->output_format);
                DIFF_OPT_SET(options, BINARY);
        }
        else if (!strcmp(arg, "--full-index"))
                DIFF_OPT_CLR(options, FOLLOW_RENAMES);
        else if (!strcmp(arg, "--color"))
                options->use_color = 1;
 -      else if (!prefixcmp(arg, "--color=")) {
 +      else if (starts_with(arg, "--color=")) {
                int value = git_config_colorbool(NULL, arg+8);
                if (value < 0)
                        return error("option `color' expects \"always\", \"auto\", or \"never\"");
                options->use_color = 1;
                options->word_diff = DIFF_WORDS_COLOR;
        }
 -      else if (!prefixcmp(arg, "--color-words=")) {
 +      else if (starts_with(arg, "--color-words=")) {
                options->use_color = 1;
                options->word_diff = DIFF_WORDS_COLOR;
                options->word_regex = arg + 14;
                if (options->word_diff == DIFF_WORDS_NONE)
                        options->word_diff = DIFF_WORDS_PLAIN;
        }
 -      else if (!prefixcmp(arg, "--word-diff=")) {
 +      else if (starts_with(arg, "--word-diff=")) {
                const char *type = arg + 12;
                if (!strcmp(type, "plain"))
                        options->word_diff = DIFF_WORDS_PLAIN;
        else if (!strcmp(arg, "--ignore-submodules")) {
                DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
                handle_ignore_submodules_arg(options, "all");
 -      } else if (!prefixcmp(arg, "--ignore-submodules=")) {
 +      } else if (starts_with(arg, "--ignore-submodules=")) {
                DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
                handle_ignore_submodules_arg(options, arg + 20);
        } else if (!strcmp(arg, "--submodule"))
                DIFF_OPT_SET(options, SUBMODULE_LOG);
 -      else if (!prefixcmp(arg, "--submodule="))
 +      else if (starts_with(arg, "--submodule="))
                return parse_submodule_opt(options, arg + 12);
  
        /* misc options */
        }
        else if (!strcmp(arg, "--abbrev"))
                options->abbrev = DEFAULT_ABBREV;
 -      else if (!prefixcmp(arg, "--abbrev=")) {
 +      else if (starts_with(arg, "--abbrev=")) {
                options->abbrev = strtoul(arg + 9, NULL, 10);
                if (options->abbrev < MINIMUM_ABBREV)
                        options->abbrev = MINIMUM_ABBREV;
@@@ -3926,15 -3881,15 +3918,15 @@@ static int diff_scoreopt_parse(const ch
        cmd = *opt++;
        if (cmd == '-') {
                /* convert the long-form arguments into short-form versions */
 -              if (!prefixcmp(opt, "break-rewrites")) {
 +              if (starts_with(opt, "break-rewrites")) {
                        opt += strlen("break-rewrites");
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'B';
 -              } else if (!prefixcmp(opt, "find-copies")) {
 +              } else if (starts_with(opt, "find-copies")) {
                        opt += strlen("find-copies");
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'C';
 -              } else if (!prefixcmp(opt, "find-renames")) {
 +              } else if (starts_with(opt, "find-renames")) {
                        opt += strlen("find-renames");
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'M';
@@@ -4139,9 -4094,9 +4131,9 @@@ void diff_debug_filespec(struct diff_fi
                DIFF_FILE_VALID(s) ? "valid" : "invalid",
                s->mode,
                s->sha1_valid ? sha1_to_hex(s->sha1) : "");
 -      fprintf(stderr, "queue[%d] %s size %lu flags %d\n",
 +      fprintf(stderr, "queue[%d] %s size %lu\n",
                x, one ? one : "",
 -              s->size, s->xfrm_flags);
 +              s->size);
  }
  
  void diff_debug_filepair(const struct diff_filepair *p, int i)
@@@ -4344,7 -4299,7 +4336,7 @@@ static void patch_id_consume(void *priv
        int new_len;
  
        /* Ignore line numbers when computing the SHA1 of the patch */
 -      if (!prefixcmp(line, "@@ -"))
 +      if (starts_with(line, "@@ -"))
                return;
  
        new_len = remove_space(line, len);
@@@ -4571,7 -4526,7 +4563,7 @@@ void diff_flush(struct diff_options *op
            DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
                /*
                 * run diff_flush_patch for the exit status. setting
 -               * options->file to /dev/null should be safe, becaue we
 +               * options->file to /dev/null should be safe, because we
                 * aren't supposed to produce any output anyway.
                 */
                if (options->close_file)
@@@ -4697,38 -4652,6 +4689,38 @@@ static int diff_filespec_is_identical(s
        return !memcmp(one->data, two->data, one->size);
  }
  
 +static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
 +{
 +      if (p->done_skip_stat_unmatch)
 +              return p->skip_stat_unmatch_result;
 +
 +      p->done_skip_stat_unmatch = 1;
 +      p->skip_stat_unmatch_result = 0;
 +      /*
 +       * 1. Entries that come from stat info dirtiness
 +       *    always have both sides (iow, not create/delete),
 +       *    one side of the object name is unknown, with
 +       *    the same mode and size.  Keep the ones that
 +       *    do not match these criteria.  They have real
 +       *    differences.
 +       *
 +       * 2. At this point, the file is known to be modified,
 +       *    with the same mode and size, and the object
 +       *    name of one side is unknown.  Need to inspect
 +       *    the identical contents.
 +       */
 +      if (!DIFF_FILE_VALID(p->one) || /* (1) */
 +          !DIFF_FILE_VALID(p->two) ||
 +          (p->one->sha1_valid && p->two->sha1_valid) ||
 +          (p->one->mode != p->two->mode) ||
 +          diff_populate_filespec(p->one, 1) ||
 +          diff_populate_filespec(p->two, 1) ||
 +          (p->one->size != p->two->size) ||
 +          !diff_filespec_is_identical(p->one, p->two)) /* (2) */
 +              p->skip_stat_unmatch_result = 1;
 +      return p->skip_stat_unmatch_result;
 +}
 +
  static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
  {
        int i;
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
  
 -              /*
 -               * 1. Entries that come from stat info dirtiness
 -               *    always have both sides (iow, not create/delete),
 -               *    one side of the object name is unknown, with
 -               *    the same mode and size.  Keep the ones that
 -               *    do not match these criteria.  They have real
 -               *    differences.
 -               *
 -               * 2. At this point, the file is known to be modified,
 -               *    with the same mode and size, and the object
 -               *    name of one side is unknown.  Need to inspect
 -               *    the identical contents.
 -               */
 -              if (!DIFF_FILE_VALID(p->one) || /* (1) */
 -                  !DIFF_FILE_VALID(p->two) ||
 -                  (p->one->sha1_valid && p->two->sha1_valid) ||
 -                  (p->one->mode != p->two->mode) ||
 -                  diff_populate_filespec(p->one, 1) ||
 -                  diff_populate_filespec(p->two, 1) ||
 -                  (p->one->size != p->two->size) ||
 -                  !diff_filespec_is_identical(p->one, p->two)) /* (2) */
 +              if (diff_filespec_check_stat_unmatch(p))
                        diff_q(&outq, p);
                else {
                        /*
@@@ -4902,7 -4845,6 +4894,7 @@@ void diff_change(struct diff_options *o
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
  {
        struct diff_filespec *one, *two;
 +      struct diff_filepair *p;
  
        if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
            is_submodule_ignored(concatpath, options))
        fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
        one->dirty_submodule = old_dirty_submodule;
        two->dirty_submodule = new_dirty_submodule;
 +      p = diff_queue(&diff_queued_diff, one, two);
  
 -      diff_queue(&diff_queued_diff, one, two);
 -      if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 -              DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 +              return;
 +
 +      if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
 +          !diff_filespec_check_stat_unmatch(p))
 +              return;
 +
 +      DIFF_OPT_SET(options, HAS_CHANGES);
  }
  
  struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
diff --combined diff.h
index e79f3b3ff09aede32e5bdcf2fbbcaaa130ef6bbb,a36720752f08fc26ca2ada0b2688b726518e13d6..a24a767db78d8e864175cf342f03fc48e159e06e
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -5,7 -5,6 +5,7 @@@
  #define DIFF_H
  
  #include "tree-walk.h"
 +#include "pathspec.h"
  
  struct rev_info;
  struct diff_options;
@@@ -88,9 -87,8 +88,9 @@@ typedef struct strbuf *(*diff_prefix_fn
  #define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
  
  #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
 -#define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
 -#define DIFF_OPT_CLR(opts, flag)    ((opts)->flags &= ~DIFF_OPT_##flag)
 +#define DIFF_OPT_TOUCHED(opts, flag)    ((opts)->touched_flags & DIFF_OPT_##flag)
 +#define DIFF_OPT_SET(opts, flag)    (((opts)->flags |= DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
 +#define DIFF_OPT_CLR(opts, flag)    (((opts)->flags &= ~DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
  #define DIFF_XDL_TST(opts, flag)    ((opts)->xdl_opts & XDF_##flag)
  #define DIFF_XDL_SET(opts, flag)    ((opts)->xdl_opts |= XDF_##flag)
  #define DIFF_XDL_CLR(opts, flag)    ((opts)->xdl_opts &= ~XDF_##flag)
@@@ -110,7 -108,6 +110,7 @@@ struct diff_options 
        const char *single_follow;
        const char *a_prefix, *b_prefix;
        unsigned flags;
 +      unsigned touched_flags;
  
        /* diff-filter bits */
        unsigned int filter;
        /* to support internal diff recursion by --follow hack*/
        int found_follow;
  
 +      void (*set_default)(struct diff_options *);
 +
        FILE *file;
        int close_file;
  
        diff_prefix_fn_t output_prefix;
        int output_prefix_length;
        void *output_prefix_data;
 +
 +      int diff_path_counter;
  };
  
  enum color_diff {
@@@ -189,6 -182,8 +189,6 @@@ const char *diff_line_prefix(struct dif
  
  extern const char mime_boundary_leader[];
  
 -extern void diff_tree_setup_paths(const char **paths, struct diff_options *);
 -extern void diff_tree_release_paths(struct diff_options *);
  extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
                     const char *base, struct diff_options *opt);
  extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
@@@ -198,6 -193,7 +198,6 @@@ extern int diff_root_tree_sha1(const un
  
  struct combine_diff_path {
        struct combine_diff_path *next;
 -      int len;
        char *path;
        unsigned int mode;
        unsigned char sha1[20];
@@@ -245,7 -241,7 +245,7 @@@ extern struct diff_filepair *diff_unmer
  #define DIFF_SETUP_USE_SIZE_CACHE     4
  
  /*
 - * Poor man's alternative to parse-option, to allow both sticked form
 + * Poor man's alternative to parse-option, to allow both stuck form
   * (--option=value) and separate form (--option value).
   */
  extern int parse_long_opt(const char *opt, const char **argv,
@@@ -331,7 -327,7 +331,7 @@@ extern int diff_flush_patch_id(struct d
  
  extern int diff_result_code(struct diff_options *, int);
  
 -extern void diff_no_index(struct rev_info *, int, const char **, int, const char *);
 +extern void diff_no_index(struct rev_info *, int, const char **, const char *);
  
  extern int index_differs_from(const char *def, int diff_flags);
  
@@@ -345,8 -341,6 +345,6 @@@ extern int parse_rename_score(const cha
  
  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,
                              int insertions, int deletions);
  extern void setup_diff_pager(struct diff_options *);