diff options
Diffstat (limited to 'diff.c')
-rw-r--r-- | diff.c | 170 |
1 files changed, 123 insertions, 47 deletions
@@ -1,34 +1,47 @@ /* * Copyright (C) 2005 Junio C Hamano */ -#include "cache.h" +#include "git-compat-util.h" +#include "abspath.h" +#include "base85.h" #include "config.h" +#include "convert.h" +#include "environment.h" +#include "gettext.h" #include "tempfile.h" #include "quote.h" #include "diff.h" #include "diffcore.h" #include "delta.h" +#include "hex.h" #include "xdiff-interface.h" #include "color.h" #include "attr.h" #include "run-command.h" #include "utf8.h" -#include "object-store.h" +#include "object-store-ll.h" #include "userdiff.h" #include "submodule-config.h" #include "submodule.h" #include "hashmap.h" #include "mem-pool.h" -#include "ll-merge.h" +#include "merge-ll.h" #include "string-list.h" #include "strvec.h" #include "graph.h" +#include "oid-array.h" #include "packfile.h" +#include "pager.h" #include "parse-options.h" #include "help.h" #include "promisor-remote.h" #include "dir.h" +#include "object-file.h" +#include "object-name.h" +#include "read-cache-ll.h" +#include "setup.h" #include "strmap.h" +#include "ws.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -127,7 +140,7 @@ static int parse_dirstat_params(struct diff_options *options, const char *params int i; if (*params_copy) - string_list_split_in_place(¶ms, params_copy, ',', -1); + string_list_split_in_place(¶ms, params_copy, ",", -1); for (i = 0; i < params.nr; i++) { const char *p = params.items[i].string; if (!strcmp(p, "changes")) { @@ -343,7 +356,8 @@ static unsigned parse_color_moved_ws(const char *arg) return ret; } -int git_diff_ui_config(const char *var, const char *value, void *cb) +int git_diff_ui_config(const char *var, const char *value, + const struct config_context *ctx, void *cb) { if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { diff_use_color_default = git_config_colorbool(var, value); @@ -364,13 +378,14 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } if (!strcmp(var, "diff.context")) { - diff_context_default = git_config_int(var, value); + diff_context_default = git_config_int(var, value, ctx->kvi); if (diff_context_default < 0) return -1; return 0; } if (!strcmp(var, "diff.interhunkcontext")) { - diff_interhunk_context_default = git_config_int(var, value); + diff_interhunk_context_default = git_config_int(var, value, + ctx->kvi); if (diff_interhunk_context_default < 0) return -1; return 0; @@ -396,7 +411,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } if (!strcmp(var, "diff.statgraphwidth")) { - diff_stat_graph_width = git_config_int(var, value); + diff_stat_graph_width = git_config_int(var, value, ctx->kvi); return 0; } if (!strcmp(var, "diff.external")) @@ -426,15 +441,16 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (git_color_config(var, value, cb) < 0) return -1; - return git_diff_basic_config(var, value, cb); + return git_diff_basic_config(var, value, ctx, cb); } -int git_diff_basic_config(const char *var, const char *value, void *cb) +int git_diff_basic_config(const char *var, const char *value, + const struct config_context *ctx, void *cb) { const char *name; if (!strcmp(var, "diff.renamelimit")) { - diff_rename_limit_default = git_config_int(var, value); + diff_rename_limit_default = git_config_int(var, value, ctx->kvi); return 0; } @@ -481,7 +497,7 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) if (git_diff_heuristic_config(var, value, cb) < 0) return -1; - return git_default_config(var, value, cb); + return git_default_config(var, value, ctx, cb); } static char *quote_two(const char *one, const char *two) @@ -2993,6 +3009,24 @@ static int dirstat_compare(const void *_a, const void *_b) return strcmp(a->name, b->name); } +static void conclude_dirstat(struct diff_options *options, + struct dirstat_dir *dir, + unsigned long changed) +{ + struct dirstat_file *to_free = dir->files; + + if (!changed) { + /* This can happen even with many files, if everything was renames */ + ; + } else { + /* Show all directories with more than x% of the changes */ + QSORT(dir->files, dir->nr, dirstat_compare); + gather_dirstat(options, dir, changed, "", 0); + } + + free(to_free); +} + static void show_dirstat(struct diff_options *options) { int i; @@ -3082,13 +3116,7 @@ found_damage: dir.nr++; } - /* This can happen even with many files, if everything was renames */ - if (!changed) - return; - - /* Show all directories with more than x% of the changes */ - QSORT(dir.files, dir.nr, dirstat_compare); - gather_dirstat(options, &dir, changed, "", 0); + conclude_dirstat(options, &dir, changed); } static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *options) @@ -3126,13 +3154,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o dir.nr++; } - /* This can happen even with many files, if everything was renames */ - if (!changed) - return; - - /* Show all directories with more than x% of the changes */ - QSORT(dir.files, dir.nr, dirstat_compare); - gather_dirstat(options, &dir, changed, "", 0); + conclude_dirstat(options, &dir, changed); } static void free_diffstat_file(struct diffstat_file *f) @@ -3374,6 +3396,17 @@ void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const options->b_prefix = b; } +void diff_set_noprefix(struct diff_options *options) +{ + options->a_prefix = options->b_prefix = ""; +} + +void diff_set_default_prefix(struct diff_options *options) +{ + options->a_prefix = "a/"; + options->b_prefix = "b/"; +} + struct userdiff_driver *get_textconv(struct repository *r, struct diff_filespec *one) { @@ -4351,7 +4384,7 @@ static int similarity_index(struct diff_filepair *p) static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev) { if (startup_info->have_repository) - return find_unique_abbrev(oid, abbrev); + return repo_find_unique_abbrev(the_repository, oid, abbrev); else { char *hex = oid_to_hex(oid); if (abbrev < 0) @@ -4674,10 +4707,9 @@ void repo_diff_setup(struct repository *r, struct diff_options *options) options->flags.ignore_untracked_in_submodules = 1; if (diff_no_prefix) { - options->a_prefix = options->b_prefix = ""; + diff_set_noprefix(options); } else if (!diff_mnemonic_prefix) { - options->a_prefix = "a/"; - options->b_prefix = "b/"; + diff_set_default_prefix(options); } options->color_moved = diff_color_moved_default; @@ -4721,6 +4753,31 @@ unsigned diff_filter_bit(char status) return filter_bit[(int) status]; } +int diff_check_follow_pathspec(struct pathspec *ps, int die_on_error) +{ + unsigned forbidden_magic; + + if (ps->nr != 1) { + if (die_on_error) + die(_("--follow requires exactly one pathspec")); + return 0; + } + + forbidden_magic = ps->items[0].magic & ~(PATHSPEC_FROMTOP | + PATHSPEC_LITERAL); + if (forbidden_magic) { + if (die_on_error) { + struct strbuf sb = STRBUF_INIT; + pathspec_magic_names(forbidden_magic, &sb); + die(_("pathspec magic not supported by --follow: %s"), + sb.buf); + } + return 0; + } + + return 1; +} + void diff_setup_done(struct diff_options *options) { unsigned check_mask = DIFF_FORMAT_NAME | @@ -4828,8 +4885,8 @@ void diff_setup_done(struct diff_options *options) options->diff_path_counter = 0; - if (options->flags.follow_renames && options->pathspec.nr != 1) - die(_("--follow requires exactly one pathspec")); + if (options->flags.follow_renames) + diff_check_follow_pathspec(&options->pathspec, 1); if (!options->use_color || external_diff()) options->color_moved = 0; @@ -4906,6 +4963,7 @@ static int diff_opt_stat(const struct option *opt, const char *value, int unset) } else BUG("%s should not get here", opt->long_name); + options->output_format &= ~DIFF_FORMAT_NO_OUTPUT; options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; options->stat_graph_width = graph_width; @@ -4925,6 +4983,7 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params) * The caller knows a dirstat-related option is given from the command * line; allow it to say "return this_function();" */ + options->output_format &= ~DIFF_FORMAT_NO_OUTPUT; options->output_format |= DIFF_FORMAT_DIRSTAT; return 1; } @@ -4988,7 +5047,7 @@ static int diff_opt_find_object(const struct option *option, struct object_id oid; BUG_ON_OPT_NEG(unset); - if (get_oid(arg, &oid)) + if (repo_get_oid(the_repository, arg, &oid)) return error(_("unable to resolve '%s'"), arg); if (!opt->objfind) @@ -5124,6 +5183,7 @@ static int diff_opt_compact_summary(const struct option *opt, options->flags.stat_with_summary = 0; } else { options->flags.stat_with_summary = 1; + options->output_format &= ~DIFF_FORMAT_NO_OUTPUT; options->output_format |= DIFF_FORMAT_DIFFSTAT; } return 0; @@ -5261,8 +5321,18 @@ static int diff_opt_no_prefix(const struct option *opt, BUG_ON_OPT_NEG(unset); BUG_ON_OPT_ARG(optarg); - options->a_prefix = ""; - options->b_prefix = ""; + diff_set_noprefix(options); + return 0; +} + +static int diff_opt_default_prefix(const struct option *opt, + const char *optarg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(optarg); + diff_set_default_prefix(options); return 0; } @@ -5451,6 +5521,10 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns return 0; } +/* + * Consider adding new flags to __git_diff_common_options + * in contrib/completion/git-completion.bash + */ struct option *add_diff_options(const struct option *opts, struct diff_options *options) { @@ -5459,9 +5533,8 @@ struct option *add_diff_options(const struct option *opts, OPT_BITOP('p', "patch", &options->output_format, N_("generate patch"), DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT), - OPT_BIT_F('s', "no-patch", &options->output_format, - N_("suppress diff output"), - DIFF_FORMAT_NO_OUTPUT, PARSE_OPT_NONEG), + OPT_SET_INT('s', "no-patch", &options->output_format, + N_("suppress diff output"), DIFF_FORMAT_NO_OUTPUT), OPT_BITOP('u', NULL, &options->output_format, N_("generate patch"), DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT), @@ -5470,9 +5543,9 @@ struct option *add_diff_options(const struct option *opts, PARSE_OPT_NONEG | PARSE_OPT_OPTARG, diff_opt_unified), OPT_BOOL('W', "function-context", &options->flags.funccontext, N_("generate diffs with <n> lines context")), - OPT_BIT_F(0, "raw", &options->output_format, + OPT_BITOP(0, "raw", &options->output_format, N_("generate the diff in raw format"), - DIFF_FORMAT_RAW, PARSE_OPT_NONEG), + DIFF_FORMAT_RAW, DIFF_FORMAT_NO_OUTPUT), OPT_BITOP(0, "patch-with-raw", &options->output_format, N_("synonym for '-p --raw'"), DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW, @@ -5481,12 +5554,12 @@ struct option *add_diff_options(const struct option *opts, N_("synonym for '-p --stat'"), DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT, DIFF_FORMAT_NO_OUTPUT), - OPT_BIT_F(0, "numstat", &options->output_format, + OPT_BITOP(0, "numstat", &options->output_format, N_("machine friendly --stat"), - DIFF_FORMAT_NUMSTAT, PARSE_OPT_NONEG), - OPT_BIT_F(0, "shortstat", &options->output_format, + DIFF_FORMAT_NUMSTAT, DIFF_FORMAT_NO_OUTPUT), + OPT_BITOP(0, "shortstat", &options->output_format, N_("output only the last line of --stat"), - DIFF_FORMAT_SHORTSTAT, PARSE_OPT_NONEG), + DIFF_FORMAT_SHORTSTAT, DIFF_FORMAT_NO_OUTPUT), OPT_CALLBACK_F('X', "dirstat", options, N_("<param1,param2>..."), N_("output the distribution of relative amount of changes for each sub-directory"), PARSE_OPT_NONEG | PARSE_OPT_OPTARG, @@ -5502,9 +5575,9 @@ struct option *add_diff_options(const struct option *opts, OPT_BIT_F(0, "check", &options->output_format, N_("warn if changes introduce conflict markers or whitespace errors"), DIFF_FORMAT_CHECKDIFF, PARSE_OPT_NONEG), - OPT_BIT_F(0, "summary", &options->output_format, + OPT_BITOP(0, "summary", &options->output_format, N_("condensed summary such as creations, renames and mode changes"), - DIFF_FORMAT_SUMMARY, PARSE_OPT_NONEG), + DIFF_FORMAT_SUMMARY, DIFF_FORMAT_NO_OUTPUT), OPT_BIT_F(0, "name-only", &options->output_format, N_("show only names of changed files"), DIFF_FORMAT_NAME, PARSE_OPT_NONEG), @@ -5555,6 +5628,9 @@ struct option *add_diff_options(const struct option *opts, OPT_CALLBACK_F(0, "no-prefix", options, NULL, N_("do not show any source or destination prefix"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_no_prefix), + OPT_CALLBACK_F(0, "default-prefix", options, NULL, + N_("use default prefixes a/ and b/"), + PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_default_prefix), OPT_INTEGER_F(0, "inter-hunk-context", &options->interhunkcontext, N_("show context between diff hunks up to the specified number of lines"), PARSE_OPT_NONEG), @@ -6860,7 +6936,7 @@ void diffcore_std(struct diff_options *options) * If no prefetching occurs, diffcore_rename() will prefetch if it * decides that it needs inexact rename detection. */ - if (options->repo == the_repository && has_promisor_remote() && + if (options->repo == the_repository && repo_has_promisor_remote(the_repository) && (options->output_format & output_formats_to_prefetch || options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK)) diff_queued_diff_prefetch(options->repo); |