X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=diff.c;h=feced343433f41c2138f09e10e256b2020c89137;hb=1c2ef66f63e60539044d1e0cd8fbfbccd2cefc2e;hp=9fa841010cc21bebc464926b15232b2aace0f5ba;hpb=476e42422d3a62a6aa301e41ba3def6882d37e9e;p=git.git diff --git a/diff.c b/diff.c index 9fa841010..feced3434 100644 --- a/diff.c +++ b/diff.c @@ -581,11 +581,14 @@ static void emit_rewrite_diff(const char *name_a, line_prefix, metainfo, a_name.buf, name_a_tab, reset, line_prefix, metainfo, b_name.buf, name_b_tab, reset, line_prefix, fraginfo); - print_line_count(o->file, lc_a); + if (!o->irreversible_delete) + print_line_count(o->file, lc_a); + else + fprintf(o->file, "?,?"); fprintf(o->file, " +"); print_line_count(o->file, lc_b); fprintf(o->file, " @@%s\n", reset); - if (lc_a) + if (lc_a && !o->irreversible_delete) emit_rewrite_lines(&ecbdata, '-', data_one, size_one); if (lc_b) emit_rewrite_lines(&ecbdata, '+', data_two, size_two); @@ -1538,8 +1541,36 @@ static void show_dirstat(struct diff_options *options) struct diff_filepair *p = q->queue[i]; const char *name; unsigned long copied, added, damage; + int content_changed; + + name = p->two->path ? p->two->path : p->one->path; + + if (p->one->sha1_valid && p->two->sha1_valid) + content_changed = hashcmp(p->one->sha1, p->two->sha1); + else + content_changed = 1; - name = p->one->path ? p->one->path : p->two->path; + if (!content_changed) { + /* + * The SHA1 has not changed, so pre-/post-content is + * identical. We can therefore skip looking at the + * file contents altogether. + */ + damage = 0; + goto found_damage; + } + + if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) { + /* + * In --dirstat-by-file mode, we don't really need to + * look at the actual file contents at all. + * The fact that the SHA1 changed is enough for us to + * add this file to the list of results + * (with each file contributing equal damage). + */ + damage = 1; + goto found_damage; + } if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) { diff_populate_filespec(p->one, 0); @@ -1563,14 +1594,18 @@ static void show_dirstat(struct diff_options *options) /* * Original minus copied is the removed material, * added is the new material. They are both damages - * made to the preimage. In --dirstat-by-file mode, count - * damaged files, not damaged lines. This is done by - * counting only a single damaged line per file. + * made to the preimage. + * If the resulting damage is zero, we know that + * diffcore_count_changes() considers the two entries to + * be identical, but since content_changed is true, we + * know that there must have been _some_ kind of change, + * so we force all entries to have damage > 0. */ damage = (p->one->size - copied) + added; - if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0) + if (!damage) damage = 1; +found_damage: ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc); dir.files[dir.nr].name = name; dir.files[dir.nr].changed = damage; @@ -1949,7 +1984,11 @@ static void builtin_diff(const char *name_a, } } - if (!DIFF_OPT_TST(o, TEXT) && + if (o->irreversible_delete && lbl[1][0] == '/') { + fprintf(o->file, "%s", header.buf); + strbuf_reset(&header); + goto free_ab_and_return; + } else if (!DIFF_OPT_TST(o, TEXT) && ( (!textconv_one && diff_filespec_is_binary(one)) || (!textconv_two && diff_filespec_is_binary(two)) )) { if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) @@ -1969,8 +2008,7 @@ static void builtin_diff(const char *name_a, fprintf(o->file, "%sBinary files %s and %s differ\n", line_prefix, lbl[0], lbl[1]); o->found_changes = 1; - } - else { + } else { /* Crazy xdl interfaces.. */ const char *diffopts = getenv("GIT_DIFF_OPTS"); xpparam_t xpp; @@ -3168,6 +3206,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) return error("invalid argument to -M: %s", arg+2); options->detect_rename = DIFF_DETECT_RENAME; } + else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) { + options->irreversible_delete = 1; + } else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") || !strcmp(arg, "--find-copies")) { if (options->detect_rename == DIFF_DETECT_COPY) @@ -3955,6 +3996,28 @@ static int is_summary_empty(const struct diff_queue_struct *q) return 1; } +static const char rename_limit_warning[] = +"inexact rename detection was skipped due to too many files."; + +static const char degrade_cc_to_c_warning[] = +"only found copies from modified paths due to too many files."; + +static const char rename_limit_advice[] = +"you may want to set your %s variable to at least " +"%d and retry the command."; + +void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc) +{ + if (degraded_cc) + warning(degrade_cc_to_c_warning); + else if (needed) + warning(rename_limit_warning); + else + return; + if (0 < needed && needed < 32767) + warning(rename_limit_advice, varname, needed); +} + void diff_flush(struct diff_options *options) { struct diff_queue_struct *q = &diff_queued_diff; @@ -4236,6 +4299,10 @@ void diffcore_std(struct diff_options *options) int diff_result_code(struct diff_options *opt, int status) { int result = 0; + + diff_warn_rename_limit("diff.renamelimit", + opt->needed_rename_limit, + opt->degraded_cc_to_c); if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && !(opt->output_format & DIFF_FORMAT_CHECKDIFF)) return status; @@ -4349,20 +4416,20 @@ void diff_change(struct diff_options *options, DIFF_OPT_SET(options, HAS_CHANGES); } -void diff_unmerge(struct diff_options *options, - const char *path, - unsigned mode, const unsigned char *sha1) +struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path) { + struct diff_filepair *pair; struct diff_filespec *one, *two; if (options->prefix && strncmp(path, options->prefix, options->prefix_length)) - return; + return NULL; one = alloc_filespec(path); two = alloc_filespec(path); - fill_filespec(one, sha1, mode); - diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1; + pair = diff_queue(&diff_queued_diff, one, two); + pair->is_unmerged = 1; + return pair; } static char *run_textconv(const char *pgm, struct diff_filespec *spec,