From: Junio C Hamano Date: Thu, 28 Apr 2011 21:11:47 +0000 (-0700) Subject: Merge branch 'jc/diff-irreversible-delete' X-Git-Tag: v1.7.6-rc0~134 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/50d3062ab2cea4e999b8f3bafd211ff348bca600?hp=-c Merge branch 'jc/diff-irreversible-delete' * jc/diff-irreversible-delete: git diff -D: omit the preimage of deletes --- 50d3062ab2cea4e999b8f3bafd211ff348bca600 diff --combined Documentation/diff-options.txt index 7e4bd425e1,30a00d3287..34f01458c2 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@@ -72,10 -72,6 +72,10 @@@ endif::git-format-patch[ a cut-off percent (3% by default) are not shown. The cut-off percent can be set with `--dirstat=`. Changes in a child directory are not counted for the parent directory, unless `--cumulative` is used. ++ +Note that the `--dirstat` option computes the changes while ignoring +the amount of pure code movements within a file. In other words, +rearranging lines in a file is not counted as much as other changes. --dirstat-by-file[=]:: Same as `--dirstat`, but counts changed files instead of lines. @@@ -263,6 -259,19 +263,19 @@@ endif::git-log[ projects, so use it with caution. Giving more than one `-C` option has the same effect. + -D:: + --irreversible-delete:: + Omit the preimage for deletes, i.e. print only the header but not + the diff between the preimage and `/dev/null`. The resulting patch + is not meant to be applied with `patch` nor `git apply`; this is + solely for people who want to just concentrate on reviewing the + text after the change. In addition, the output obviously lack + enough information to apply such a patch in reverse, even manually, + hence the name of the option. + + + When used together with `-B`, omit also the preimage in the deletion part + of a delete/create pair. + -l:: The `-M` and `-C` options require O(n^2) processing time where n is the number of potential rename/copy targets. This diff --combined diff.c index 56758c7dca,05f443c14a..3b40e597d5 --- a/diff.c +++ b/diff.c @@@ -23,7 -23,7 +23,7 @@@ #endif static int diff_detect_rename_default; -static int diff_rename_limit_default = 200; +static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; int diff_use_color_default = -1; static const char *diff_word_regex_cfg; @@@ -245,15 -245,6 +245,15 @@@ static int fill_mmfile(mmfile_t *mf, st return 0; } +/* like fill_mmfile, but only for size, so we can avoid retrieving blob */ +static unsigned long diff_filespec_size(struct diff_filespec *one) +{ + if (!DIFF_FILE_VALID(one)) + return 0; + diff_populate_filespec(one, 1); + return one->size; +} + static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) { char *ptr = mf->ptr; @@@ -581,11 -572,14 +581,14 @@@ static void emit_rewrite_diff(const cha 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); @@@ -615,20 -609,22 +618,20 @@@ static void diff_words_append(char *lin buffer->text.ptr[buffer->text.size] = '\0'; } -struct diff_words_style_elem -{ +struct diff_words_style_elem { const char *prefix; const char *suffix; const char *color; /* NULL; filled in by the setup code if * color is enabled */ }; -struct diff_words_style -{ +struct diff_words_style { enum diff_words_type type; struct diff_words_style_elem new, old, ctx; const char *newline; }; -struct diff_words_style diff_words_styles[] = { +static struct diff_words_style diff_words_styles[] = { { DIFF_WORDS_PORCELAIN, {"+", "\n"}, {"-", "\n"}, {" ", "\n"}, "~\n" }, { DIFF_WORDS_PLAIN, {"{+", "+}"}, {"[-", "-]"}, {"", ""}, "\n" }, { DIFF_WORDS_COLOR, {"", ""}, {"", ""}, {"", ""}, "\n" } @@@ -1242,7 -1238,7 +1245,7 @@@ static void show_stats(struct diffstat_ uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; - const char *reset, *set, *add_c, *del_c; + const char *reset, *add_c, *del_c; const char *line_prefix = ""; struct strbuf *msg = NULL; @@@ -1269,6 -1265,7 +1272,6 @@@ /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); - set = diff_get_color_opt(options, DIFF_PLAIN); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); @@@ -1538,36 -1535,8 +1541,36 @@@ static void show_dirstat(struct diff_op 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; + + 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; + } - name = p->one->path ? p->one->path : p->two->path; + 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); @@@ -1591,18 -1560,14 +1594,18 @@@ /* * 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; @@@ -1981,7 -1946,11 +1984,11 @@@ static void builtin_diff(const char *na } } - 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) @@@ -2001,8 -1970,7 +2008,7 @@@ 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; @@@ -2117,28 -2085,25 +2123,28 @@@ static void builtin_diffstat(const cha data->is_unmerged = 1; return; } - if (complete_rewrite) { + + if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) { + data->is_binary = 1; + data->added = diff_filespec_size(two); + data->deleted = diff_filespec_size(one); + } + + else if (complete_rewrite) { diff_populate_filespec(one, 0); diff_populate_filespec(two, 0); data->deleted = count_lines(one->data, one->size); data->added = count_lines(two->data, two->size); - goto free_and_return; } - if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) - die("unable to read files to diff"); - if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) { - data->is_binary = 1; - data->added = mf2.size; - data->deleted = mf1.size; - } else { + else { /* Crazy xdl interfaces.. */ xpparam_t xpp; xdemitconf_t xecfg; + if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + die("unable to read files to diff"); + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = o->xdl_opts; @@@ -2146,6 -2111,7 +2152,6 @@@ &xpp, &xecfg); } - free_and_return: diff_free_filespec_data(one); diff_free_filespec_data(two); } @@@ -3200,6 -3166,9 +3206,9 @@@ int diff_opt_parse(struct diff_options 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) @@@ -3987,28 -3956,6 +3996,28 @@@ static int is_summary_empty(const struc 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; @@@ -4290,10 -4237,6 +4299,10 @@@ void diffcore_std(struct diff_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; diff --combined diff.h index b8dde8a750,11d13cf70b..6fe1597785 --- a/diff.h +++ b/diff.h @@@ -104,15 -104,14 +104,16 @@@ struct diff_options int interhunkcontext; int break_opt; int detect_rename; + int irreversible_delete; int skip_stat_unmatch; int line_termination; int output_format; int pickaxe_opts; int rename_score; int rename_limit; - int warn_on_too_large_rename; + int needed_rename_limit; + int degraded_cc_to_c; + int show_rename_progress; int dirstat_percent; int setup; int abbrev; @@@ -274,7 -273,6 +275,7 @@@ extern void diffcore_fix_diff_index(str extern int diff_queue_is_empty(void); extern void diff_flush(struct diff_options*); +extern void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc); /* diff-raw status letters */ #define DIFF_STATUS_ADDED 'A'