diff options
Diffstat (limited to 'diff.c')
-rw-r--r-- | diff.c | 285 |
1 files changed, 181 insertions, 104 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,11 +27,12 @@ #endif static int diff_detect_rename_default; -static int diff_compaction_heuristic; /* experimental */ +static int diff_indent_heuristic; /* experimental */ static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; static int diff_use_color_default = -1; static int diff_context_default = 3; +static int diff_interhunk_context_default; static const char *diff_word_regex_cfg; static const char *external_diff_cmd_cfg; static const char *diff_order_file_cfg; @@ -41,6 +43,7 @@ static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; static long diff_algorithm; +static unsigned ws_error_highlight_default = WSEH_NEW; static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, @@ -54,6 +57,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 +139,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; @@ -163,6 +173,43 @@ long parse_algorithm_value(const char *value) return -1; } +static int parse_one_token(const char **arg, const char *token) +{ + const char *rest; + if (skip_prefix(*arg, token, &rest) && (!*rest || *rest == ',')) { + *arg = rest; + return 1; + } + return 0; +} + +static int parse_ws_error_highlight(const char *arg) +{ + const char *orig_arg = arg; + unsigned val = 0; + + while (*arg) { + if (parse_one_token(&arg, "none")) + val = 0; + else if (parse_one_token(&arg, "default")) + val = WSEH_NEW; + else if (parse_one_token(&arg, "all")) + val = WSEH_NEW | WSEH_OLD | WSEH_CONTEXT; + else if (parse_one_token(&arg, "new")) + val |= WSEH_NEW; + else if (parse_one_token(&arg, "old")) + val |= WSEH_OLD; + else if (parse_one_token(&arg, "context")) + val |= WSEH_CONTEXT; + else { + return -1 - (int)(arg - orig_arg); + } + if (*arg) + arg++; + } + return val; +} + /* * These are to give UI layer defaults. * The core-level commands such as git-diff-files should @@ -174,6 +221,13 @@ 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); + return 0; +} + int git_diff_ui_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { @@ -186,12 +240,14 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return -1; return 0; } - if (!strcmp(var, "diff.renames")) { - diff_detect_rename_default = git_config_rename(var, value); + if (!strcmp(var, "diff.interhunkcontext")) { + diff_interhunk_context_default = git_config_int(var, value); + if (diff_interhunk_context_default < 0) + return -1; return 0; } - if (!strcmp(var, "diff.compactionheuristic")) { - diff_compaction_heuristic = git_config_bool(var, value); + if (!strcmp(var, "diff.renames")) { + diff_detect_rename_default = git_config_rename(var, value); return 0; } if (!strcmp(var, "diff.autorefreshindex")) { @@ -234,6 +290,17 @@ 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 (!strcmp(var, "diff.wserrorhighlight")) { + int val = parse_ws_error_highlight(value); + if (val < 0) + return -1; + ws_error_highlight_default = val; + return 0; + } + if (git_color_config(var, value, cb) < 0) return -1; @@ -1616,7 +1683,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 ? @@ -1997,7 +2064,7 @@ found_damage: return; /* Show all directories with more than x% of the changes */ - qsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare); + QSORT(dir.files, dir.nr, dirstat_compare); gather_dirstat(options, &dir, changed, "", 0); } @@ -2041,7 +2108,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o return; /* Show all directories with more than x% of the changes */ - qsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare); + QSORT(dir.files, dir.nr, dirstat_compare); gather_dirstat(options, &dir, changed, "", 0); } @@ -2290,17 +2357,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)) { @@ -2308,15 +2395,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; @@ -2690,7 +2768,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; /* @@ -2937,7 +3015,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, if (!one->oid_valid) sha1_to_hex_r(temp->hex, null_sha1); else - sha1_to_hex_r(temp->hex, one->oid.hash); + oid_to_hex_r(temp->hex, &one->oid); /* Even though we may sometimes borrow the * contents from the work tree, we always want * one->mode. mode is trustworthy even when @@ -3016,6 +3094,22 @@ static int similarity_index(struct diff_filepair *p) return p->score * 100 / MAX_SCORE; } +static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev) +{ + if (startup_info->have_repository) + return find_unique_abbrev(oid->hash, abbrev); + else { + char *hex = oid_to_hex(oid); + if (abbrev < 0) + abbrev = FALLBACK_DEFAULT_ABBREV; + if (abbrev > GIT_SHA1_HEXSZ) + die("BUG: oid abbreviation out of range: %d", abbrev); + if (abbrev) + hex[abbrev] = '\0'; + return hex; + } +} + static void fill_metainfo(struct strbuf *msg, const char *name, const char *other, @@ -3074,9 +3168,9 @@ static void fill_metainfo(struct strbuf *msg, (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) abbrev = 40; } - strbuf_addf(msg, "%s%sindex %s..", line_prefix, set, - find_unique_abbrev(one->oid.hash, abbrev)); - strbuf_add_unique_abbrev(msg, two->oid.hash, abbrev); + strbuf_addf(msg, "%s%sindex %s..%s", line_prefix, set, + diff_abbrev_oid(&one->oid, abbrev), + diff_abbrev_oid(&two->oid, abbrev)); if (one->mode == two->mode) strbuf_addf(msg, " %06o", one->mode); strbuf_addf(msg, "%s\n", reset); @@ -3269,12 +3363,14 @@ void diff_setup(struct diff_options *options) options->file = stdout; + options->abbrev = DEFAULT_ABBREV; options->line_termination = '\n'; options->break_opt = -1; options->rename_limit = -1; options->dirstat_permille = diff_dirstat_permille_default; options->context = diff_context_default; - options->ws_error_highlight = WSEH_NEW; + options->interhunkcontext = diff_interhunk_context_default; + options->ws_error_highlight = ws_error_highlight_default; DIFF_OPT_SET(options, RENAME_EMPTY); /* pathchange left =NULL by default */ @@ -3283,8 +3379,8 @@ 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) - DIFF_XDL_SET(options, COMPACTION_HEURISTIC); + if (diff_indent_heuristic) + DIFF_XDL_SET(options, INDENT_HEURISTIC); options->orderfile = diff_order_file_cfg; @@ -3312,7 +3408,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" @@ -3386,7 +3482,7 @@ void diff_setup_done(struct diff_options *options) */ read_cache(); } - if (options->abbrev <= 0 || 40 < options->abbrev) + if (40 < options->abbrev) options->abbrev = 40; /* full */ /* @@ -3508,7 +3604,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; @@ -3517,7 +3613,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; @@ -3526,7 +3622,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; @@ -3535,7 +3631,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; @@ -3663,40 +3759,14 @@ static void enable_patch_output(int *fmt) { *fmt |= DIFF_FORMAT_PATCH; } -static int parse_one_token(const char **arg, const char *token) +static int parse_ws_error_highlight_opt(struct diff_options *opt, const char *arg) { - const char *rest; - if (skip_prefix(*arg, token, &rest) && (!*rest || *rest == ',')) { - *arg = rest; - return 1; - } - return 0; -} + int val = parse_ws_error_highlight(arg); -static int parse_ws_error_highlight(struct diff_options *opt, const char *arg) -{ - const char *orig_arg = arg; - unsigned val = 0; - while (*arg) { - if (parse_one_token(&arg, "none")) - val = 0; - else if (parse_one_token(&arg, "default")) - val = WSEH_NEW; - else if (parse_one_token(&arg, "all")) - val = WSEH_NEW | WSEH_OLD | WSEH_CONTEXT; - else if (parse_one_token(&arg, "new")) - val |= WSEH_NEW; - else if (parse_one_token(&arg, "old")) - val |= WSEH_OLD; - else if (parse_one_token(&arg, "context")) - val |= WSEH_CONTEXT; - else { - error("unknown value after ws-error-highlight=%.*s", - (int)(arg - orig_arg), orig_arg); - return 0; - } - if (*arg) - arg++; + if (val < 0) { + error("unknown value after ws-error-highlight=%.*s", + -1 - val, arg); + return 0; } opt->ws_error_highlight = val; return 1; @@ -3805,10 +3875,10 @@ 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")) - DIFF_XDL_SET(options, COMPACTION_HEURISTIC); - else if (!strcmp(arg, "--no-compaction-heuristic")) - DIFF_XDL_CLR(options, COMPACTION_HEURISTIC); + else if (!strcmp(arg, "--indent-heuristic")) + DIFF_XDL_SET(options, INDENT_HEURISTIC); + else if (!strcmp(arg, "--no-indent-heuristic")) + DIFF_XDL_CLR(options, INDENT_HEURISTIC); else if (!strcmp(arg, "--patience")) options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); else if (!strcmp(arg, "--histogram")) @@ -3905,11 +3975,15 @@ 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)) - return parse_ws_error_highlight(options, arg); + return parse_ws_error_highlight_opt(options, arg); + else if (!strcmp(arg, "--ita-invisible-in-index")) + options->ita_invisible_in_index = 1; + else if (!strcmp(arg, "--ita-visible-in-index")) + options->ita_invisible_in_index = 0; /* misc options */ else if (!strcmp(arg, "-z")) @@ -3943,6 +4017,8 @@ int diff_opt_parse(struct diff_options *options, offending, optarg); return argcount; } + else if (!strcmp(arg, "--no-abbrev")) + options->abbrev = 0; else if (!strcmp(arg, "--abbrev")) options->abbrev = DEFAULT_ABBREV; else if (skip_prefix(arg, "--abbrev=", &arg)) { @@ -3956,6 +4032,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; @@ -4089,18 +4171,15 @@ void diff_free_filepair(struct diff_filepair *p) free(p); } -/* - * This is different from find_unique_abbrev() in that - * it stuffs the result with dots for alignment. - */ -const char *diff_unique_abbrev(const unsigned char *sha1, int len) +const char *diff_aligned_abbrev(const struct object_id *oid, int len) { int abblen; const char *abbrev; - if (len == 40) - return sha1_to_hex(sha1); - abbrev = find_unique_abbrev(sha1, len); + if (len == GIT_SHA1_HEXSZ) + return oid_to_hex(oid); + + abbrev = diff_abbrev_oid(oid, len); abblen = strlen(abbrev); /* @@ -4122,15 +4201,16 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len) * the automatic sizing is supposed to give abblen that ensures * uniqueness across all objects (statistically speaking). */ - if (abblen < 37) { - static char hex[41]; + if (abblen < GIT_SHA1_HEXSZ - 3) { + static char hex[GIT_SHA1_HEXSZ + 1]; if (len < abblen && abblen <= len + 2) xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, ".."); else xsnprintf(hex, sizeof(hex), "%s...", abbrev); return hex; } - return sha1_to_hex(sha1); + + return oid_to_hex(oid); } static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt) @@ -4141,9 +4221,9 @@ static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt) fprintf(opt->file, "%s", diff_line_prefix(opt)); if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) { fprintf(opt->file, ":%06o %06o %s ", p->one->mode, p->two->mode, - diff_unique_abbrev(p->one->oid.hash, opt->abbrev)); + diff_aligned_abbrev(&p->one->oid, opt->abbrev)); fprintf(opt->file, "%s ", - diff_unique_abbrev(p->two->oid.hash, opt->abbrev)); + diff_aligned_abbrev(&p->two->oid, opt->abbrev)); } if (p->score) { fprintf(opt->file, "%c%03d%c", p->status, similarity_index(p), @@ -4370,6 +4450,7 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt) name_a = p->two->path; name_b = NULL; strip_prefix(opt->prefix_length, &name_a, &name_b); + fprintf(opt->file, "%s", diff_line_prefix(opt)); write_name_quoted(name_a, opt->file, opt->line_termination); } } @@ -4612,25 +4693,25 @@ static int is_summary_empty(const struct diff_queue_struct *q) } static const char rename_limit_warning[] = -"inexact rename detection was skipped due to too many files."; +N_("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."; +N_("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."; +N_("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); + warning(_(degrade_cc_to_c_warning)); else if (needed) - warning(rename_limit_warning); + warning(_(rename_limit_warning)); else return; if (0 < needed && needed < 32767) - warning(rename_limit_advice, varname, needed); + warning(_(rename_limit_advice), varname, needed); } void diff_flush(struct diff_options *options) @@ -4897,7 +4978,7 @@ static int diffnamecmp(const void *a_, const void *b_) void diffcore_fix_diff_index(struct diff_options *options) { struct diff_queue_struct *q = &diff_queued_diff; - qsort(q->queue, q->nr, sizeof(q->queue[0]), diffnamecmp); + QSORT(q->queue, q->nr, diffnamecmp); } void diffcore_std(struct diff_options *options) @@ -5037,14 +5118,10 @@ void diff_change(struct diff_options *options, return; if (DIFF_OPT_TST(options, REVERSE_DIFF)) { - unsigned tmp; - const unsigned char *tmp_c; - tmp = old_mode; old_mode = new_mode; new_mode = tmp; - tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c; - tmp = old_sha1_valid; old_sha1_valid = new_sha1_valid; - new_sha1_valid = tmp; - tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule; - new_dirty_submodule = tmp; + SWAP(old_mode, new_mode); + SWAP(old_sha1, new_sha1); + SWAP(old_sha1_valid, new_sha1_valid); + SWAP(old_dirty_submodule, new_dirty_submodule); } if (options->prefix && |