X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=diff.c;h=71b340c5368fb287ce7d7b242aa51436ed5dda93;hb=10455d2a955a29db1809be139177e4e298771eb0;hp=7bbe7590b2e6b8c1f153902e0375df193c5268f2;hpb=070739fd351702ea9bb4f65595728ae25a488075;p=git.git diff --git a/diff.c b/diff.c index 7bbe7590b..71b340c53 100644 --- a/diff.c +++ b/diff.c @@ -16,11 +16,10 @@ #define FAST_WORKING_DIRECTORY 1 #endif -static int use_size_cache; - static int diff_detect_rename_default; -static int diff_rename_limit_default = -1; +static int diff_rename_limit_default = 100; static int diff_use_color_default; +int diff_auto_refresh_index = 1; static char diff_colors[][COLOR_MAXLEN] = { "\033[m", /* reset */ @@ -58,6 +57,14 @@ static struct ll_diff_driver { char *cmd; } *user_diff, **user_diff_tail; +static void read_config_if_needed(void) +{ + if (!user_diff_tail) { + user_diff_tail = &user_diff; + git_config(git_diff_ui_config); + } +} + /* * Currently there is only "diff..command" variable; * because there are "diff.color." variables, we are parsing @@ -95,6 +102,45 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val return 0; } +/* + * 'diff..funcname' attribute can be specified in the configuration + * to define a customized regexp to find the beginning of a function to + * be used for hunk header lines of "diff -p" style output. + */ +static struct funcname_pattern { + char *name; + char *pattern; + struct funcname_pattern *next; +} *funcname_pattern_list; + +static int parse_funcname_pattern(const char *var, const char *ep, const char *value) +{ + const char *name; + int namelen; + struct funcname_pattern *pp; + + name = var + 5; /* "diff." */ + namelen = ep - name; + + for (pp = funcname_pattern_list; pp; pp = pp->next) + if (!strncmp(pp->name, name, namelen) && !pp->name[namelen]) + break; + if (!pp) { + char *namebuf; + pp = xcalloc(1, sizeof(*pp)); + namebuf = xmalloc(namelen + 1); + memcpy(namebuf, name, namelen); + namebuf[namelen] = 0; + pp->name = namebuf; + pp->next = funcname_pattern_list; + funcname_pattern_list = pp; + } + if (pp->pattern) + free(pp->pattern); + pp->pattern = xstrdup(value); + return 0; +} + /* * These are to give UI layer defaults. * The core-level commands such as git-diff-files should @@ -121,11 +167,19 @@ int git_diff_ui_config(const char *var, const char *value) diff_detect_rename_default = DIFF_DETECT_RENAME; return 0; } + if (!strcmp(var, "diff.autorefreshindex")) { + diff_auto_refresh_index = git_config_bool(var, value); + return 0; + } if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); - if (ep != var + 4 && !strcmp(ep, ".command")) - return parse_lldiff_command(var, ep, value); + if (ep != var + 4) { + if (!strcmp(ep, ".command")) + return parse_lldiff_command(var, ep, value); + if (!strcmp(ep, ".funcname")) + return parse_funcname_pattern(var, ep, value); + } } if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); @@ -188,13 +242,11 @@ static const char *external_diff(void) return external_diff_cmd; } -#define TEMPFILE_PATH_LEN 50 - static struct diff_tempfile { const char *name; /* filename external diff should read from */ char hex[41]; char mode[10]; - char tmp_path[TEMPFILE_PATH_LEN]; + char tmp_path[PATH_MAX]; } diff_temp[2]; static int count_lines(const char *data, int size) @@ -394,6 +446,7 @@ static void diff_words_show(struct diff_words_data *diff_words) mmfile_t minus, plus; int i; + memset(&xecfg, 0, sizeof(xecfg)); minus.size = diff_words->minus.text.size; minus.ptr = xmalloc(minus.size); memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size); @@ -412,7 +465,6 @@ static void diff_words_show(struct diff_words_data *diff_words) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; - xecfg.flags = 0; ecb.outf = xdiff_outf; ecb.priv = diff_words; diff_words->xm.consume = fn_out_diff_words_aux; @@ -1106,35 +1158,111 @@ static void setup_diff_attr_check(struct git_attr_check *check) { static struct git_attr *attr_diff; - if (!attr_diff) + if (!attr_diff) { attr_diff = git_attr("diff", 4); - check->attr = attr_diff; + } + check[0].attr = attr_diff; } -#define FIRST_FEW_BYTES 8000 -static int file_is_binary(struct diff_filespec *one) +static void diff_filespec_check_attr(struct diff_filespec *one) { - unsigned long sz; struct git_attr_check attr_diff_check; + int check_from_data = 0; + + if (one->checked_attr) + return; setup_diff_attr_check(&attr_diff_check); + one->is_binary = 0; + one->funcname_pattern_ident = NULL; + if (!git_checkattr(one->path, 1, &attr_diff_check)) { - const char *value = attr_diff_check.value; + const char *value; + + /* binaryness */ + value = attr_diff_check.value; if (ATTR_TRUE(value)) - return 0; + ; else if (ATTR_FALSE(value)) - return 1; + one->is_binary = 1; + else + check_from_data = 1; + + /* funcname pattern ident */ + if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value)) + ; + else + one->funcname_pattern_ident = value; } - if (!one->data) { - if (!DIFF_FILE_VALID(one)) - return 0; - diff_populate_filespec(one, 0); + if (check_from_data) { + if (!one->data && DIFF_FILE_VALID(one)) + diff_populate_filespec(one, 0); + + if (one->data) + one->is_binary = buffer_is_binary(one->data, one->size); } - sz = one->size; - if (FIRST_FEW_BYTES < sz) - sz = FIRST_FEW_BYTES; - return !!memchr(one->data, 0, sz); +} + +int diff_filespec_is_binary(struct diff_filespec *one) +{ + diff_filespec_check_attr(one); + return one->is_binary; +} + +static const char *funcname_pattern(const char *ident) +{ + struct funcname_pattern *pp; + + read_config_if_needed(); + for (pp = funcname_pattern_list; pp; pp = pp->next) + if (!strcmp(ident, pp->name)) + return pp->pattern; + return NULL; +} + +static struct builtin_funcname_pattern { + const char *name; + const char *pattern; +} builtin_funcname_pattern[] = { + { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" + "new\\|return\\|switch\\|throw\\|while\\)\n" + "^[ ]*\\(\\([ ]*" + "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}" + "[ ]*([^;]*$\\)" }, + { "tex", "^\\(\\\\\\(sub\\)*section{.*\\)$" }, +}; + +static const char *diff_funcname_pattern(struct diff_filespec *one) +{ + const char *ident, *pattern; + int i; + + diff_filespec_check_attr(one); + ident = one->funcname_pattern_ident; + + if (!ident) + /* + * If the config file has "funcname.default" defined, that + * regexp is used; otherwise NULL is returned and xemit uses + * the built-in default. + */ + return funcname_pattern("default"); + + /* Look up custom "funcname.$ident" regexp from config. */ + pattern = funcname_pattern(ident); + if (pattern) + return pattern; + + /* + * And define built-in fallback patterns here. Note that + * these can be overriden by the user's config settings. + */ + for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++) + if (!strcmp(ident, builtin_funcname_pattern[i].name)) + return builtin_funcname_pattern[i].pattern; + + return NULL; } static void builtin_diff(const char *name_a, @@ -1191,7 +1319,8 @@ static void builtin_diff(const char *name_a, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - if (!o->text && (file_is_binary(one) || file_is_binary(two))) { + if (!o->text && + (diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) { /* Quite common confusing case */ if (mf1.size == mf2.size && !memcmp(mf1.ptr, mf2.ptr, mf1.size)) @@ -1210,7 +1339,13 @@ static void builtin_diff(const char *name_a, xdemitconf_t xecfg; xdemitcb_t ecb; struct emit_callback ecbdata; + const char *funcname_pattern; + + funcname_pattern = diff_funcname_pattern(one); + if (!funcname_pattern) + funcname_pattern = diff_funcname_pattern(two); + memset(&xecfg, 0, sizeof(xecfg)); memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.label_path = lbl; ecbdata.color_diff = o->color_diff; @@ -1218,6 +1353,8 @@ static void builtin_diff(const char *name_a, xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; + if (funcname_pattern) + xdiff_set_find_func(&xecfg, funcname_pattern); if (!diffopts) ; else if (!prefixcmp(diffopts, "--unified=")) @@ -1236,6 +1373,8 @@ static void builtin_diff(const char *name_a, } free_ab_and_return: + diff_free_filespec_data(one); + diff_free_filespec_data(two); free(a_one); free(b_two); return; @@ -1262,12 +1401,12 @@ static void builtin_diffstat(const char *name_a, const char *name_b, diff_populate_filespec(two, 0); data->deleted = count_lines(one->data, one->size); data->added = count_lines(two->data, two->size); - return; + goto free_and_return; } if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - if (file_is_binary(one) || file_is_binary(two)) { + if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) { data->is_binary = 1; data->added = mf2.size; data->deleted = mf1.size; @@ -1277,13 +1416,16 @@ static void builtin_diffstat(const char *name_a, const char *name_b, xdemitconf_t xecfg; xdemitcb_t ecb; + memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; - xecfg.ctxlen = 0; - xecfg.flags = 0; ecb.outf = xdiff_outf; ecb.priv = diffstat; xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } + + free_and_return: + diff_free_filespec_data(one); + diff_free_filespec_data(two); } static void builtin_checkdiff(const char *name_a, const char *name_b, @@ -1305,21 +1447,23 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - if (file_is_binary(two)) - return; + if (diff_filespec_is_binary(two)) + goto free_and_return; else { /* Crazy xdl interfaces.. */ xpparam_t xpp; xdemitconf_t xecfg; xdemitcb_t ecb; + memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL; - xecfg.ctxlen = 0; - xecfg.flags = 0; ecb.outf = xdiff_outf; ecb.priv = &data; xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } + free_and_return: + diff_free_filespec_data(one); + diff_free_filespec_data(two); } struct diff_filespec *alloc_filespec(const char *path) @@ -1344,7 +1488,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1, } /* - * Given a name and sha1 pair, if the dircache tells us the file in + * Given a name and sha1 pair, if the index tells us the file in * the work tree has that object contents, return true, so that * prepare_temp_file() does not have to inflate and extract. */ @@ -1399,61 +1543,12 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int return 1; } -static struct sha1_size_cache { - unsigned char sha1[20]; - unsigned long size; -} **sha1_size_cache; -static int sha1_size_cache_nr, sha1_size_cache_alloc; - -static struct sha1_size_cache *locate_size_cache(unsigned char *sha1, - int find_only, - unsigned long size) -{ - int first, last; - struct sha1_size_cache *e; - - first = 0; - last = sha1_size_cache_nr; - while (last > first) { - int cmp, next = (last + first) >> 1; - e = sha1_size_cache[next]; - cmp = hashcmp(e->sha1, sha1); - if (!cmp) - return e; - if (cmp < 0) { - last = next; - continue; - } - first = next+1; - } - /* not found */ - if (find_only) - return NULL; - /* insert to make it at "first" */ - if (sha1_size_cache_alloc <= sha1_size_cache_nr) { - sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc); - sha1_size_cache = xrealloc(sha1_size_cache, - sha1_size_cache_alloc * - sizeof(*sha1_size_cache)); - } - sha1_size_cache_nr++; - if (first < sha1_size_cache_nr) - memmove(sha1_size_cache + first + 1, sha1_size_cache + first, - (sha1_size_cache_nr - first - 1) * - sizeof(*sha1_size_cache)); - e = xmalloc(sizeof(struct sha1_size_cache)); - sha1_size_cache[first] = e; - hashcpy(e->sha1, sha1); - e->size = size; - return e; -} - static int populate_from_stdin(struct diff_filespec *s) { #define INCREMENT 1024 char *buf; unsigned long size; - int got; + ssize_t got; size = 0; buf = NULL; @@ -1503,13 +1598,13 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) if (S_ISDIR(s->mode)) return -1; - if (!use_size_cache) - size_only = 0; - if (s->data) - return err; + return 0; + + if (size_only && 0 < s->size) + return 0; - if (S_ISDIRLNK(s->mode)) + if (S_ISGITLINK(s->mode)) return diff_populate_gitlink(s, size_only); if (!s->sha1_valid || @@ -1570,19 +1665,8 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) } else { enum object_type type; - struct sha1_size_cache *e; - - if (size_only && use_size_cache && - (e = locate_size_cache(s->sha1, 1, 0)) != NULL) { - s->size = e->size; - return 0; - } - - if (size_only) { + if (size_only) type = sha1_object_info(s->sha1, &s->size); - if (use_size_cache && 0 < type) - locate_size_cache(s->sha1, 0, s->size); - } else { s->data = read_sha1_file(s->sha1, &type, &s->size); s->should_free = 1; @@ -1591,14 +1675,22 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) return 0; } -void diff_free_filespec_data(struct diff_filespec *s) +void diff_free_filespec_blob(struct diff_filespec *s) { if (s->should_free) free(s->data); else if (s->should_munmap) munmap(s->data, s->size); - s->should_free = s->should_munmap = 0; - s->data = NULL; + + if (s->should_free || s->should_munmap) { + s->should_free = s->should_munmap = 0; + s->data = NULL; + } +} + +void diff_free_filespec_data(struct diff_filespec *s) +{ + diff_free_filespec_blob(s); free(s->cnt_data); s->cnt_data = NULL; } @@ -1611,9 +1703,9 @@ static void prep_temp_blob(struct diff_tempfile *temp, { int fd; - fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX"); + fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX"); if (fd < 0) - die("unable to create temp-file"); + die("unable to create temp-file: %s", strerror(errno)); if (write_in_full(fd, blob, size) != size) die("unable to write temp-file"); close(fd); @@ -1810,10 +1902,7 @@ static const char *external_diff_attr(const char *name) !ATTR_UNSET(value)) { struct ll_diff_driver *drv; - if (!user_diff_tail) { - user_diff_tail = &user_diff; - git_config(git_diff_ui_config); - } + read_config_if_needed(); for (drv = user_diff; drv; drv = drv->next) if (!strcmp(drv->name, value)) return drv->cmd; @@ -1870,6 +1959,11 @@ static void diff_fill_sha1_info(struct diff_filespec *one) hashclr(one->sha1); } +static int similarity_index(struct diff_filepair *p) +{ + return p->score * 100 / MAX_SCORE; +} + static void run_diff(struct diff_filepair *p, struct diff_options *o) { const char *pgm = external_diff(); @@ -1904,23 +1998,20 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) "similarity index %d%%\n" "copy from %s\n" "copy to %s\n", - (int)(0.5 + p->score * 100.0/MAX_SCORE), - name_munged, other_munged); + similarity_index(p), name_munged, other_munged); break; case DIFF_STATUS_RENAMED: len += snprintf(msg + len, sizeof(msg) - len, "similarity index %d%%\n" "rename from %s\n" "rename to %s\n", - (int)(0.5 + p->score * 100.0/MAX_SCORE), - name_munged, other_munged); + similarity_index(p), name_munged, other_munged); break; case DIFF_STATUS_MODIFIED: if (p->score) { len += snprintf(msg + len, sizeof(msg) - len, "dissimilarity index %d%%\n", - (int)(0.5 + p->score * - 100.0/MAX_SCORE)); + similarity_index(p)); complete_rewrite = 1; break; } @@ -1935,8 +2026,8 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) if (o->binary) { mmfile_t mf; - if ((!fill_mmfile(&mf, one) && file_is_binary(one)) || - (!fill_mmfile(&mf, two) && file_is_binary(two))) + if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || + (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) abbrev = 40; } len += snprintf(msg + len, sizeof(msg) - len, @@ -2090,8 +2181,6 @@ int diff_setup_done(struct diff_options *options) */ read_cache(); } - if (options->setup & DIFF_SETUP_USE_SIZE_CACHE) - use_size_cache = 1; if (options->abbrev <= 0 || 40 < options->abbrev) options->abbrev = 40; /* full */ @@ -2162,6 +2251,8 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va return 1; } +static int diff_scoreopt_parse(const char *opt); + int diff_opt_parse(struct diff_options *options, const char **av, int ac) { const char *arg = av[0]; @@ -2258,6 +2349,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->detect_rename = DIFF_DETECT_RENAME; } else if (!prefixcmp(arg, "-C")) { + if (options->detect_rename == DIFF_DETECT_COPY) + options->find_copies_harder = 1; if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) return -1; @@ -2265,6 +2358,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--find-copies-harder")) options->find_copies_harder = 1; + else if (!strcmp(arg, "--follow")) + options->follow_renames = 1; else if (!strcmp(arg, "--abbrev")) options->abbrev = DEFAULT_ABBREV; else if (!prefixcmp(arg, "--abbrev=")) { @@ -2292,6 +2387,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->exit_with_status = 1; else if (!strcmp(arg, "--quiet")) options->quiet = 1; + else if (!strcmp(arg, "--ext-diff")) + options->allow_external = 1; + else if (!strcmp(arg, "--no-ext-diff")) + options->allow_external = 0; else return 0; return 1; @@ -2333,7 +2432,7 @@ static int parse_num(const char **cp_p) return (int)((num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale)); } -int diff_scoreopt_parse(const char *opt) +static int diff_scoreopt_parse(const char *opt) { int opt1, opt2, cmd; @@ -2440,8 +2539,7 @@ static void diff_flush_raw(struct diff_filepair *p, } if (p->score) - sprintf(status, "%c%03d", p->status, - (int)(0.5 + p->score * 100.0/MAX_SCORE)); + sprintf(status, "%c%03d", p->status, similarity_index(p)); else { status[0] = p->status; status[1] = 0; @@ -2466,7 +2564,8 @@ static void diff_flush_raw(struct diff_filepair *p, printf("%s ", diff_unique_abbrev(p->two->sha1, abbrev)); } - printf("%s%c%s", status, inter_name_termination, path_one); + printf("%s%c%s", status, inter_name_termination, + two_paths || p->one->mode ? path_one : path_two); if (two_paths) printf("%c%s", inter_name_termination, path_two); putchar(line_termination); @@ -2723,8 +2822,7 @@ static void show_rename_copy(const char *renamecopy, struct diff_filepair *p) { char *names = pprint_rename(p->one->path, p->two->path); - printf(" %s %s (%d%%)\n", renamecopy, names, - (int)(0.5 + p->score * 100.0/MAX_SCORE)); + printf(" %s %s (%d%%)\n", renamecopy, names, similarity_index(p)); free(names); show_mode_change(p, 0); } @@ -2748,7 +2846,7 @@ static void diff_summary(struct diff_filepair *p) if (p->score) { char *name = quote_one(p->two->path); printf(" rewrite %s (%d%%)\n", name, - (int)(0.5 + p->score * 100.0/MAX_SCORE)); + similarity_index(p)); free(name); show_mode_change(p, 0); } else show_mode_change(p, 1); @@ -2812,6 +2910,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) struct diff_filepair *p = q->queue[i]; int len1, len2; + memset(&xecfg, 0, sizeof(xecfg)); if (p->status == 0) return error("internal diff status error"); if (p->status == DIFF_STATUS_UNKNOWN) @@ -2830,10 +2929,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) fill_mmfile(&mf2, p->two) < 0) return error("unable to read files to diff"); - /* Maybe hash p->two? into the patch id? */ - if (file_is_binary(p->two)) - continue; - len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); if (p->one->mode == 0) @@ -3054,10 +3149,77 @@ static void diffcore_apply_filter(const char *filter) *q = outq; } +/* Check whether two filespecs with the same mode and size are identical */ +static int diff_filespec_is_identical(struct diff_filespec *one, + struct diff_filespec *two) +{ + if (S_ISGITLINK(one->mode)) { + diff_fill_sha1_info(one); + diff_fill_sha1_info(two); + return !hashcmp(one->sha1, two->sha1); + } + if (diff_populate_filespec(one, 0)) + return 0; + if (diff_populate_filespec(two, 0)) + return 0; + return !memcmp(one->data, two->data, one->size); +} + +static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) +{ + int i; + struct diff_queue_struct *q = &diff_queued_diff; + struct diff_queue_struct outq; + outq.queue = NULL; + outq.nr = outq.alloc = 0; + + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + + /* + * 1. Entries that come from stat info dirtyness + * 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) */ + diff_q(&outq, p); + else { + /* + * The caller can subtract 1 from skip_stat_unmatch + * to determine how many paths were dirty only + * due to stat info mismatch. + */ + if (!diffopt->no_index) + diffopt->skip_stat_unmatch++; + diff_free_filepair(p); + } + } + free(q->queue); + *q = outq; +} + void diffcore_std(struct diff_options *options) { if (options->quiet) return; + + if (options->skip_stat_unmatch && !options->find_copies_harder) + diffcore_skip_stat_unmatch(options); if (options->break_opt != -1) diffcore_break(options->break_opt); if (options->detect_rename) @@ -3090,7 +3252,7 @@ void diff_addremove(struct diff_options *options, * entries to the diff-core. They will be prefixed * with something like '=' or '*' (I haven't decided * which but should not make any difference). - * Feeding the same new and old to diff_change() + * Feeding the same new and old to diff_change() * also has the same effect. * Before the final output happens, they are pruned after * merged into rename/copy pairs as appropriate. @@ -3117,7 +3279,7 @@ void diff_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *base, const char *path) + const char *base, const char *path) { char concatpath[PATH_MAX]; struct diff_filespec *one, *two;