diff options
Diffstat (limited to 'diff.c')
-rw-r--r-- | diff.c | 164 |
1 files changed, 106 insertions, 58 deletions
@@ -18,6 +18,7 @@ #include "ll-merge.h" #include "string-list.h" #include "argv-array.h" +#include "graph.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -26,6 +27,7 @@ #endif static int diff_detect_rename_default; +static int diff_indent_heuristic; /* experimental */ static int diff_compaction_heuristic; /* experimental */ static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; @@ -54,6 +56,11 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* FUNCINFO */ }; +static NORETURN void die_want_option(const char *option_name) +{ + die(_("option '%s' requires a value"), option_name); +} + static int parse_diff_color_slot(const char *var) { if (!strcasecmp(var, "context") || !strcasecmp(var, "plain")) @@ -131,9 +138,11 @@ static int parse_dirstat_params(struct diff_options *options, const char *params static int parse_submodule_params(struct diff_options *options, const char *value) { if (!strcmp(value, "log")) - DIFF_OPT_SET(options, SUBMODULE_LOG); + options->submodule_format = DIFF_SUBMODULE_LOG; else if (!strcmp(value, "short")) - DIFF_OPT_CLR(options, SUBMODULE_LOG); + options->submodule_format = DIFF_SUBMODULE_SHORT; + else if (!strcmp(value, "diff")) + options->submodule_format = DIFF_SUBMODULE_INLINE_DIFF; else return -1; return 0; @@ -174,6 +183,21 @@ void init_diff_ui_defaults(void) diff_detect_rename_default = 1; } +int git_diff_heuristic_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "diff.indentheuristic")) { + diff_indent_heuristic = git_config_bool(var, value); + if (diff_indent_heuristic) + diff_compaction_heuristic = 0; + } + if (!strcmp(var, "diff.compactionheuristic")) { + diff_compaction_heuristic = git_config_bool(var, value); + if (diff_compaction_heuristic) + diff_indent_heuristic = 0; + } + return 0; +} + int git_diff_ui_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { @@ -190,10 +214,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_detect_rename_default = git_config_rename(var, value); return 0; } - if (!strcmp(var, "diff.compactionheuristic")) { - diff_compaction_heuristic = git_config_bool(var, value); - return 0; - } if (!strcmp(var, "diff.autorefreshindex")) { diff_auto_refresh_index = git_config_bool(var, value); return 0; @@ -234,6 +254,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } + if (git_diff_heuristic_config(var, value, cb) < 0) + return -1; if (git_color_config(var, value, cb) < 0) return -1; @@ -354,7 +376,6 @@ struct emit_callback { const char **label_path; struct diff_words_data *diff_words; struct diff_options *opt; - int *found_changesp; struct strbuf *header; }; @@ -722,7 +743,6 @@ static void emit_rewrite_diff(const char *name_a, 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); ecbdata.opt = o; if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { @@ -951,7 +971,8 @@ static int find_word_boundaries(mmfile_t *buffer, regex_t *word_regex, { if (word_regex && *begin < buffer->size) { regmatch_t match[1]; - if (!regexec(word_regex, buffer->ptr + *begin, 1, match, 0)) { + if (!regexec_buf(word_regex, buffer->ptr + *begin, + buffer->size - *begin, 1, match, 0)) { char *p = memchr(buffer->ptr + *begin + match[0].rm_so, '\n', match[0].rm_eo - match[0].rm_so); *end = p ? p - buffer->ptr : match[0].rm_eo + *begin; @@ -1216,12 +1237,13 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) struct diff_options *o = ecbdata->opt; const char *line_prefix = diff_line_prefix(o); + o->found_changes = 1; + if (ecbdata->header) { - fprintf(ecbdata->opt->file, "%s", ecbdata->header->buf); + fprintf(o->file, "%s", ecbdata->header->buf); strbuf_reset(ecbdata->header); ecbdata->header = NULL; } - *(ecbdata->found_changesp) = 1; if (ecbdata->label_path[0]) { const char *name_a_tab, *name_b_tab; @@ -1229,9 +1251,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : ""; name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : ""; - fprintf(ecbdata->opt->file, "%s%s--- %s%s%s\n", + fprintf(o->file, "%s%s--- %s%s%s\n", line_prefix, meta, ecbdata->label_path[0], reset, name_a_tab); - fprintf(ecbdata->opt->file, "%s%s+++ %s%s%s\n", + fprintf(o->file, "%s%s+++ %s%s%s\n", line_prefix, meta, ecbdata->label_path[1], reset, name_b_tab); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } @@ -1249,15 +1271,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) find_lno(line, ecbdata); emit_hunk_header(ecbdata, line, len); if (line[len-1] != '\n') - putc('\n', ecbdata->opt->file); - return; - } - - if (len < 1) { - emit_line(ecbdata->opt, reset, reset, line, len); - if (ecbdata->diff_words - && ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) - fputs("~\n", ecbdata->opt->file); + putc('\n', o->file); return; } @@ -1282,8 +1296,8 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) } diff_words_flush(ecbdata); if (ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) { - emit_line(ecbdata->opt, context, reset, line, len); - fputs("~\n", ecbdata->opt->file); + emit_line(o, context, reset, line, len); + fputs("~\n", o->file); } else { /* * Skip the prefix character, if any. With @@ -1294,7 +1308,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) line++; len--; } - emit_line(ecbdata->opt, context, reset, line, len); + emit_line(o, context, reset, line, len); } return; } @@ -1316,8 +1330,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) default: /* incomplete line at the end */ ecbdata->lno_in_preimage++; - emit_line(ecbdata->opt, - diff_get_color(ecbdata->color_diff, DIFF_CONTEXT), + emit_line(o, diff_get_color(ecbdata->color_diff, DIFF_CONTEXT), reset, line, len); break; } @@ -1625,7 +1638,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) */ if (options->stat_width == -1) - width = term_columns() - options->output_prefix_length; + width = term_columns() - strlen(line_prefix); else width = options->stat_width ? options->stat_width : 80; number_width = decimal_width(max_change) > number_width ? @@ -2299,17 +2312,37 @@ static void builtin_diff(const char *name_a, struct strbuf header = STRBUF_INIT; const char *line_prefix = diff_line_prefix(o); - if (DIFF_OPT_TST(o, SUBMODULE_LOG) && - (!one->mode || S_ISGITLINK(one->mode)) && - (!two->mode || S_ISGITLINK(two->mode))) { + diff_set_mnemonic_prefix(o, "a/", "b/"); + if (DIFF_OPT_TST(o, REVERSE_DIFF)) { + a_prefix = o->b_prefix; + b_prefix = o->a_prefix; + } else { + a_prefix = o->a_prefix; + b_prefix = o->b_prefix; + } + + if (o->submodule_format == DIFF_SUBMODULE_LOG && + (!one->mode || S_ISGITLINK(one->mode)) && + (!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->path ? one->path : two->path, line_prefix, - one->oid.hash, two->oid.hash, + &one->oid, &two->oid, two->dirty_submodule, meta, del, add, reset); return; + } else if (o->submodule_format == DIFF_SUBMODULE_INLINE_DIFF && + (!one->mode || S_ISGITLINK(one->mode)) && + (!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_inline_diff(o->file, one->path ? one->path : two->path, + line_prefix, + &one->oid, &two->oid, + two->dirty_submodule, + meta, del, add, reset, o); + return; } if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) { @@ -2317,15 +2350,6 @@ static void builtin_diff(const char *name_a, textconv_two = get_textconv(two); } - diff_set_mnemonic_prefix(o, "a/", "b/"); - if (DIFF_OPT_TST(o, REVERSE_DIFF)) { - a_prefix = o->b_prefix; - b_prefix = o->a_prefix; - } else { - a_prefix = o->a_prefix; - b_prefix = o->b_prefix; - } - /* Never use a non-valid filename anywhere if at all possible */ name_a = DIFF_FILE_VALID(one) ? name_a : name_b; name_b = DIFF_FILE_VALID(two) ? name_b : name_a; @@ -2438,7 +2462,6 @@ static void builtin_diff(const char *name_a, memset(&ecbdata, 0, sizeof(ecbdata)); 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); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) check_blank_at_eof(&mf1, &mf2, &ecbdata); @@ -2683,6 +2706,13 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1)) return 0; + /* + * Similarly, if we'd have to convert the file contents anyway, that + * makes the optimization not worthwhile. + */ + if (!want_file && would_convert_to_git(name)) + return 0; + len = strlen(name); pos = cache_name_pos(name, len); if (pos < 0) @@ -2693,7 +2723,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int * This is not the sha1 we are looking for, or * unreusable because it is not a regular file. */ - if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode)) + if (hashcmp(sha1, ce->oid.hash) || !S_ISREG(ce->ce_mode)) return 0; /* @@ -3286,7 +3316,9 @@ void diff_setup(struct diff_options *options) options->use_color = diff_use_color_default; options->detect_rename = diff_detect_rename_default; options->xdl_opts |= diff_algorithm; - if (diff_compaction_heuristic) + if (diff_indent_heuristic) + DIFF_XDL_SET(options, INDENT_HEURISTIC); + else if (diff_compaction_heuristic) DIFF_XDL_SET(options, COMPACTION_HEURISTIC); options->orderfile = diff_order_file_cfg; @@ -3315,7 +3347,7 @@ void diff_setup_done(struct diff_options *options) if (options->output_format & DIFF_FORMAT_NO_OUTPUT) count++; if (count > 1) - die("--name-only, --name-status, --check and -s are mutually exclusive"); + die(_("--name-only, --name-status, --check and -s are mutually exclusive")); /* * Most of the time we can say "there are changes" @@ -3511,7 +3543,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-width' requires a value"); + die_want_option("--stat-width"); else if (!*arg) { width = strtoul(av[1], &end, 10); argcount = 2; @@ -3520,7 +3552,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') name_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-name-width' requires a value"); + die_want_option("--stat-name-width"); else if (!*arg) { name_width = strtoul(av[1], &end, 10); argcount = 2; @@ -3529,7 +3561,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') graph_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-graph-width' requires a value"); + die_want_option("--stat-graph-width"); else if (!*arg) { graph_width = strtoul(av[1], &end, 10); argcount = 2; @@ -3538,7 +3570,7 @@ static int stat_opt(struct diff_options *options, const char **av) if (*arg == '=') count = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) - die("Option '--stat-count' requires a value"); + die_want_option("--stat-count"); else if (!*arg) { count = strtoul(av[1], &end, 10); argcount = 2; @@ -3808,9 +3840,15 @@ int diff_opt_parse(struct diff_options *options, 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, "--compaction-heuristic")) + else if (!strcmp(arg, "--indent-heuristic")) { + DIFF_XDL_SET(options, INDENT_HEURISTIC); + DIFF_XDL_CLR(options, COMPACTION_HEURISTIC); + } else if (!strcmp(arg, "--no-indent-heuristic")) + DIFF_XDL_CLR(options, INDENT_HEURISTIC); + else if (!strcmp(arg, "--compaction-heuristic")) { DIFF_XDL_SET(options, COMPACTION_HEURISTIC); - else if (!strcmp(arg, "--no-compaction-heuristic")) + DIFF_XDL_CLR(options, INDENT_HEURISTIC); + } else if (!strcmp(arg, "--no-compaction-heuristic")) DIFF_XDL_CLR(options, COMPACTION_HEURISTIC); else if (!strcmp(arg, "--patience")) options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); @@ -3908,7 +3946,7 @@ int diff_opt_parse(struct diff_options *options, DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, arg); } else if (!strcmp(arg, "--submodule")) - DIFF_OPT_SET(options, SUBMODULE_LOG); + options->submodule_format = DIFF_SUBMODULE_LOG; else if (skip_prefix(arg, "--submodule=", &arg)) return parse_submodule_opt(options, arg); else if (skip_prefix(arg, "--ws-error-highlight=", &arg)) @@ -3959,6 +3997,12 @@ int diff_opt_parse(struct diff_options *options, options->a_prefix = optarg; return argcount; } + else if ((argcount = parse_long_opt("line-prefix", av, &optarg))) { + options->line_prefix = optarg; + options->line_prefix_length = strlen(options->line_prefix); + graph_setup_line_prefix(options); + return argcount; + } else if ((argcount = parse_long_opt("dst-prefix", av, &optarg))) { options->b_prefix = optarg; return argcount; @@ -4455,7 +4499,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len) } /* returns 0 upon success, and writes result into sha1 */ -static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) +static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only) { struct diff_queue_struct *q = &diff_queued_diff; int i; @@ -4490,9 +4534,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) diff_fill_sha1_info(p->one); diff_fill_sha1_info(p->two); - if (fill_mmfile(&mf1, p->one) < 0 || - fill_mmfile(&mf2, p->two) < 0) - return error("unable to read files to diff"); len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); @@ -4527,6 +4568,13 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) len2, p->two->path); git_SHA1_Update(&ctx, buffer, len1); + if (diff_header_only) + continue; + + if (fill_mmfile(&mf1, p->one) < 0 || + fill_mmfile(&mf2, p->two) < 0) + return error("unable to read files to diff"); + if (diff_filespec_is_binary(p->one) || diff_filespec_is_binary(p->two)) { git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid), @@ -4549,11 +4597,11 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) return 0; } -int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1) +int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only) { struct diff_queue_struct *q = &diff_queued_diff; int i; - int result = diff_get_patch_id(options, sha1); + int result = diff_get_patch_id(options, sha1, diff_header_only); for (i = 0; i < q->nr; i++) diff_free_filepair(q->queue[i]); |