diff options
Diffstat (limited to 'diff.c')
| -rw-r--r-- | diff.c | 429 |
1 files changed, 297 insertions, 132 deletions
@@ -1,15 +1,19 @@ /* * Copyright (C) 2005 Junio C Hamano */ + +#define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "abspath.h" -#include "alloc.h" #include "base85.h" #include "config.h" #include "convert.h" #include "environment.h" #include "gettext.h" #include "tempfile.h" +#include "revision.h" #include "quote.h" #include "diff.h" #include "diffcore.h" @@ -17,18 +21,17 @@ #include "hex.h" #include "xdiff-interface.h" #include "color.h" -#include "attr.h" #include "run-command.h" #include "utf8.h" #include "object-store-ll.h" #include "userdiff.h" -#include "submodule-config.h" #include "submodule.h" #include "hashmap.h" #include "mem-pool.h" #include "merge-ll.h" #include "string-list.h" #include "strvec.h" +#include "tmp-objdir.h" #include "graph.h" #include "oid-array.h" #include "packfile.h" @@ -43,7 +46,6 @@ #include "setup.h" #include "strmap.h" #include "ws.h" -#include "wrapper.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -60,13 +62,16 @@ static int diff_color_moved_default; static int diff_color_moved_ws_default; 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; +static char *diff_word_regex_cfg; +static struct external_diff external_diff_cfg; +static char *diff_order_file_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static char *diff_src_prefix; +static char *diff_dst_prefix; static int diff_relative; +static int diff_stat_name_width; static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; @@ -358,7 +363,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); @@ -372,20 +378,24 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } if (!strcmp(var, "diff.colormovedws")) { - unsigned cm = parse_color_moved_ws(value); + unsigned cm; + if (!value) + return config_error_nonbool(var); + cm = parse_color_moved_ws(value); if (cm & COLOR_MOVED_WS_ERROR) return -1; diff_color_moved_ws_default = cm; 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; @@ -406,25 +416,48 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_no_prefix = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.srcprefix")) { + FREE_AND_NULL(diff_src_prefix); + return git_config_string(&diff_src_prefix, var, value); + } + if (!strcmp(var, "diff.dstprefix")) { + FREE_AND_NULL(diff_dst_prefix); + return git_config_string(&diff_dst_prefix, var, value); + } if (!strcmp(var, "diff.relative")) { diff_relative = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.statnamewidth")) { + diff_stat_name_width = git_config_int(var, value, ctx->kvi); + 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")) - return git_config_string(&external_diff_cmd_cfg, var, value); + return git_config_string(&external_diff_cfg.cmd, var, value); + if (!strcmp(var, "diff.trustexitcode")) { + external_diff_cfg.trust_exit_code = git_config_bool(var, value); + return 0; + } if (!strcmp(var, "diff.wordregex")) return git_config_string(&diff_word_regex_cfg, var, value); - if (!strcmp(var, "diff.orderfile")) + if (!strcmp(var, "diff.orderfile")) { + FREE_AND_NULL(diff_order_file_cfg); return git_config_pathname(&diff_order_file_cfg, var, value); + } - if (!strcmp(var, "diff.ignoresubmodules")) + if (!strcmp(var, "diff.ignoresubmodules")) { + if (!value) + return config_error_nonbool(var); handle_ignore_submodules_arg(&default_diff_options, value); + } if (!strcmp(var, "diff.submodule")) { + if (!value) + return config_error_nonbool(var); if (parse_submodule_params(&default_diff_options, value)) warning(_("Unknown value for 'diff.submodule' config variable: '%s'"), value); @@ -432,24 +465,28 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "diff.algorithm")) { + if (!value) + return config_error_nonbool(var); diff_algorithm = parse_algorithm_value(value); if (diff_algorithm < 0) - return -1; + return error(_("unknown value for config '%s': %s"), + var, value); return 0; } 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; } @@ -467,9 +504,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "diff.wserrorhighlight")) { - int val = parse_ws_error_highlight(value); + int val; + if (!value) + return config_error_nonbool(var); + val = parse_ws_error_highlight(value); if (val < 0) - return -1; + return error(_("unknown value for config '%s': %s"), + var, value); ws_error_highlight_default = val; return 0; } @@ -484,6 +525,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) if (!strcmp(var, "diff.dirstat")) { struct strbuf errmsg = STRBUF_INIT; + if (!value) + return config_error_nonbool(var); default_diff_options.dirstat_permille = diff_dirstat_permille_default; if (parse_dirstat_params(&default_diff_options, value, &errmsg)) warning(_("Found errors in 'diff.dirstat' config variable:\n%s"), @@ -496,7 +539,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) @@ -517,18 +560,22 @@ static char *quote_two(const char *one, const char *two) return strbuf_detach(&res, NULL); } -static const char *external_diff(void) +static const struct external_diff *external_diff(void) { - static const char *external_diff_cmd = NULL; + static struct external_diff external_diff_env, *external_diff_ptr; static int done_preparing = 0; if (done_preparing) - return external_diff_cmd; - external_diff_cmd = xstrdup_or_null(getenv("GIT_EXTERNAL_DIFF")); - if (!external_diff_cmd) - external_diff_cmd = external_diff_cmd_cfg; + return external_diff_ptr; + external_diff_env.cmd = xstrdup_or_null(getenv("GIT_EXTERNAL_DIFF")); + if (git_env_bool("GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE", 0)) + external_diff_env.trust_exit_code = 1; + if (external_diff_env.cmd) + external_diff_ptr = &external_diff_env; + else if (external_diff_cfg.cmd) + external_diff_ptr = &external_diff_cfg; done_preparing = 1; - return external_diff_cmd; + return external_diff_ptr; } /* @@ -2271,12 +2318,9 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) const char *diff_line_prefix(struct diff_options *opt) { - struct strbuf *msgbuf; - if (!opt->output_prefix) - return ""; - - msgbuf = opt->output_prefix(opt, opt->output_prefix_data); - return msgbuf->buf; + return opt->output_prefix ? + opt->output_prefix(opt, opt->output_prefix_data) : + ""; } static unsigned long sane_truncate_line(char *line, unsigned long len) @@ -2703,12 +2747,14 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) number_width = decimal_width(max_change) > number_width ? decimal_width(max_change) : number_width; + if (options->stat_name_width == -1) + options->stat_name_width = diff_stat_name_width; if (options->stat_graph_width == -1) options->stat_graph_width = diff_stat_graph_width; /* - * Guarantee 3/8*16==6 for the graph part - * and 5/8*16==10 for the filename part + * Guarantee 3/8*16 == 6 for the graph part + * and 5/8*16 == 10 for the filename part */ if (width < 16 + 6 + number_width) width = 16 + 6 + number_width; @@ -3402,8 +3448,8 @@ void diff_set_noprefix(struct diff_options *options) void diff_set_default_prefix(struct diff_options *options) { - options->a_prefix = "a/"; - options->b_prefix = "b/"; + options->a_prefix = diff_src_prefix ? diff_src_prefix : "a/"; + options->b_prefix = diff_dst_prefix ? diff_dst_prefix : "b/"; } struct userdiff_driver *get_textconv(struct repository *r, @@ -3521,6 +3567,7 @@ static void builtin_diff(const char *name_a, show_submodule_diff_summary(o, one->path ? one->path : two->path, &one->oid, &two->oid, two->dirty_submodule); + o->found_changes = 1; return; } else if (o->submodule_format == DIFF_SUBMODULE_INLINE_DIFF && (!one->mode || S_ISGITLINK(one->mode)) && @@ -3529,6 +3576,7 @@ static void builtin_diff(const char *name_a, show_submodule_inline_diff(o, one->path ? one->path : two->path, &one->oid, &two->oid, two->dirty_submodule); + o->found_changes = 1; return; } @@ -3562,18 +3610,21 @@ static void builtin_diff(const char *name_a, strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, meta, two->mode, reset); if (xfrm_msg) strbuf_addstr(&header, xfrm_msg); + o->found_changes = 1; must_show_header = 1; } else if (lbl[1][0] == '/') { strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, meta, one->mode, reset); if (xfrm_msg) strbuf_addstr(&header, xfrm_msg); + o->found_changes = 1; must_show_header = 1; } else { if (one->mode != two->mode) { strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, meta, one->mode, reset); strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, meta, two->mode, reset); + o->found_changes = 1; must_show_header = 1; } if (xfrm_msg) @@ -3624,6 +3675,7 @@ static void builtin_diff(const char *name_a, emit_diff_symbol(o, DIFF_SYMBOL_BINARY_FILES, sb.buf, sb.len, 0); strbuf_release(&sb); + o->found_changes = 1; goto free_ab_and_return; } if (fill_mmfile(o->repo, &mf1, one) < 0 || @@ -3728,7 +3780,7 @@ static void builtin_diff(const char *name_a, return; } -static char *get_compact_summary(const struct diff_filepair *p, int is_renamed) +static const char *get_compact_summary(const struct diff_filepair *p, int is_renamed) { if (!is_renamed) { if (p->status == DIFF_STATUS_ADDED) { @@ -3990,7 +4042,8 @@ static int reuse_worktree_file(struct index_state *istate, * objects however would tend to be slower as they need * to be individually opened and inflated. */ - if (!FAST_WORKING_DIRECTORY && !want_file && has_object_pack(oid)) + if (!FAST_WORKING_DIRECTORY && !want_file && + has_object_pack(istate->repo, oid)) return 0; /* @@ -4040,7 +4093,7 @@ static int reuse_worktree_file(struct index_state *istate, static int diff_populate_gitlink(struct diff_filespec *s, int size_only) { struct strbuf buf = STRBUF_INIT; - char *dirty = ""; + const char *dirty = ""; /* Are we looking at the work tree? */ if (s->dirty_submodule) @@ -4339,7 +4392,7 @@ static void add_external_diff_name(struct repository *r, * infile2 infile2-sha1 infile2-mode [ rename-to ] * */ -static void run_external_diff(const char *pgm, +static void run_external_diff(const struct external_diff *pgm, const char *name, const char *other, struct diff_filespec *one, @@ -4349,8 +4402,21 @@ static void run_external_diff(const char *pgm, { struct child_process cmd = CHILD_PROCESS_INIT; struct diff_queue_struct *q = &diff_queued_diff; + int quiet = !(o->output_format & DIFF_FORMAT_PATCH); + int rc; + + /* + * Trivial equality is handled by diff_unmodified_pair() before + * we get here. If we don't need to show the diff and the + * external diff program lacks the ability to tell us whether + * it's empty then we consider it non-empty without even asking. + */ + if (!pgm->trust_exit_code && quiet) { + o->found_changes = 1; + return; + } - strvec_push(&cmd.args, pgm); + strvec_push(&cmd.args, pgm->cmd); strvec_push(&cmd.args, name); if (one && two) { @@ -4358,7 +4424,8 @@ static void run_external_diff(const char *pgm, add_external_diff_name(o->repo, &cmd.args, two); if (other) { strvec_push(&cmd.args, other); - strvec_push(&cmd.args, xfrm_msg); + if (xfrm_msg) + strvec_push(&cmd.args, xfrm_msg); } } @@ -4369,7 +4436,15 @@ static void run_external_diff(const char *pgm, diff_free_filespec_data(one); diff_free_filespec_data(two); cmd.use_shell = 1; - if (run_command(&cmd)) + cmd.no_stdout = quiet; + rc = run_command(&cmd); + if (!pgm->trust_exit_code && rc == 0) + o->found_changes = 1; + else if (pgm->trust_exit_code && rc == 0) + ; /* nothing */ + else if (pgm->trust_exit_code && rc == 1) + o->found_changes = 1; + else die(_("external diff died, stopping at %s"), name); remove_tempfile(); @@ -4475,7 +4550,7 @@ static void fill_metainfo(struct strbuf *msg, } } -static void run_diff_cmd(const char *pgm, +static void run_diff_cmd(const struct external_diff *pgm, const char *name, const char *other, const char *attr_path, @@ -4493,8 +4568,8 @@ static void run_diff_cmd(const char *pgm, if (o->flags.allow_external || !o->ignore_driver_algorithm) drv = userdiff_find_by_path(o->repo->index, attr_path); - if (o->flags.allow_external && drv && drv->external) - pgm = drv->external; + if (o->flags.allow_external && drv && drv->external.cmd) + pgm = &drv->external; if (msg) { /* @@ -4518,8 +4593,12 @@ static void run_diff_cmd(const char *pgm, builtin_diff(name, other ? other : name, one, two, xfrm_msg, must_show_header, o, complete_rewrite); + if (p->status == DIFF_STATUS_COPIED || + p->status == DIFF_STATUS_RENAMED) + o->found_changes = 1; } else { fprintf(o->file, "* Unmerged path %s\n", name); + o->found_changes = 1; } } @@ -4529,7 +4608,7 @@ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *is if (!one->oid_valid) { struct stat st; if (one->is_stdin) { - oidclr(&one->oid); + oidclr(&one->oid, the_repository->hash_algo); return; } if (lstat(one->path, &st) < 0) @@ -4539,7 +4618,7 @@ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *is } } else - oidclr(&one->oid); + oidclr(&one->oid, the_repository->hash_algo); } static void strip_prefix(int prefix_length, const char **namep, const char **otherp) @@ -4559,7 +4638,7 @@ static void strip_prefix(int prefix_length, const char **namep, const char **oth static void run_diff(struct diff_filepair *p, struct diff_options *o) { - const char *pgm = external_diff(); + const struct external_diff *pgm = external_diff(); struct strbuf msg; struct diff_filespec *one = p->one; struct diff_filespec *two = p->two; @@ -4700,7 +4779,7 @@ void repo_diff_setup(struct repository *r, struct diff_options *options) if (diff_indent_heuristic) DIFF_XDL_SET(options, INDENT_HEURISTIC); - options->orderfile = diff_order_file_cfg; + options->orderfile = xstrdup_or_null(diff_order_file_cfg); if (!options->flags.ignore_submodule_set) options->flags.ignore_untracked_in_submodules = 1; @@ -4831,6 +4910,10 @@ void diff_setup_done(struct diff_options *options) else options->prefix_length = 0; + /* + * --name-only, --name-status, --checkdiff, and -s + * turn other output format off. + */ if (options->output_format & (DIFF_FORMAT_NAME | DIFF_FORMAT_NAME_STATUS | DIFF_FORMAT_CHECKDIFF | @@ -4882,12 +4965,20 @@ void diff_setup_done(struct diff_options *options) options->flags.exit_with_status = 1; } + /* + * External diffs could declare non-identical contents equal + * (think diff --ignore-space-change). + */ + if (options->flags.allow_external && options->flags.exit_with_status) + options->flags.diff_from_contents = 1; + options->diff_path_counter = 0; if (options->flags.follow_renames) diff_check_follow_pathspec(&options->pathspec, 1); - if (!options->use_color || external_diff()) + if (!options->use_color || + (options->flags.allow_external && external_diff())) options->color_moved = 0; if (options->filter_not) { @@ -5308,7 +5399,6 @@ static int diff_opt_line_prefix(const struct option *opt, BUG_ON_OPT_NEG(unset); options->line_prefix = optarg; - options->line_prefix_length = strlen(options->line_prefix); graph_setup_line_prefix(options); return 0; } @@ -5331,6 +5421,8 @@ static int diff_opt_default_prefix(const struct option *opt, BUG_ON_OPT_NEG(unset); BUG_ON_OPT_ARG(optarg); + FREE_AND_NULL(diff_src_prefix); + FREE_AND_NULL(diff_dst_prefix); diff_set_default_prefix(options); return 0; } @@ -5380,9 +5472,13 @@ static int diff_opt_ignore_regex(const struct option *opt, regex_t *regex; BUG_ON_OPT_NEG(unset); + regex = xmalloc(sizeof(*regex)); - if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE)) + if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE)) { + free(regex); return error(_("invalid regex given to -I: '%s'"), arg); + } + ALLOC_GROW(options->ignore_regex, options->ignore_regex_nr + 1, options->ignore_regex_alloc); options->ignore_regex[options->ignore_regex_nr++] = regex; @@ -5397,6 +5493,8 @@ static int diff_opt_pickaxe_regex(const struct option *opt, BUG_ON_OPT_NEG(unset); options->pickaxe = arg; options->pickaxe_opts |= DIFF_PICKAXE_KIND_G; + if (arg && !*arg) + return error(_("-G requires a non-empty argument")); return 0; } @@ -5408,6 +5506,8 @@ static int diff_opt_pickaxe_string(const struct option *opt, BUG_ON_OPT_NEG(unset); options->pickaxe = arg; options->pickaxe_opts |= DIFF_PICKAXE_KIND_S; + if (arg && !*arg) + return error(_("-S requires a non-empty argument")); return 0; } @@ -5520,6 +5620,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) { @@ -5555,7 +5659,7 @@ struct option *add_diff_options(const struct option *opts, OPT_BITOP(0, "shortstat", &options->output_format, N_("output only the last line of --stat"), DIFF_FORMAT_SHORTSTAT, DIFF_FORMAT_NO_OUTPUT), - OPT_CALLBACK_F('X', "dirstat", options, N_("<param1,param2>..."), + 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, diff_opt_dirstat), @@ -5563,8 +5667,8 @@ struct option *add_diff_options(const struct option *opts, N_("synonym for --dirstat=cumulative"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_dirstat), - OPT_CALLBACK_F(0, "dirstat-by-file", options, N_("<param1,param2>..."), - N_("synonym for --dirstat=files,param1,param2..."), + OPT_CALLBACK_F(0, "dirstat-by-file", options, N_("<param1>,<param2>..."), + N_("synonym for --dirstat=files,<param1>,<param2>..."), PARSE_OPT_NONEG | PARSE_OPT_OPTARG, diff_opt_dirstat), OPT_BIT_F(0, "check", &options->output_format, @@ -5881,11 +5985,18 @@ void diff_free_filepair(struct diff_filepair *p) free(p); } -void diff_free_queue(struct diff_queue_struct *q) +void diff_queue_init(struct diff_queue_struct *q) +{ + struct diff_queue_struct blank = DIFF_QUEUE_INIT; + memcpy(q, &blank, sizeof(*q)); +} + +void diff_queue_clear(struct diff_queue_struct *q) { for (int i = 0; i < q->nr; i++) diff_free_filepair(q->queue[i]); free(q->queue); + diff_queue_init(q); } const char *diff_aligned_abbrev(const struct object_id *oid, int len) @@ -6201,6 +6312,8 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt) fprintf(opt->file, "%s", diff_line_prefix(opt)); write_name_quoted(name_a, opt->file, opt->line_termination); } + + opt->found_changes = 1; } static void show_file_mode_name(struct diff_options *opt, const char *newdelete, struct diff_filespec *fs) @@ -6283,7 +6396,7 @@ static void diff_summary(struct diff_options *opt, struct diff_filepair *p) } struct patch_id_t { - git_hash_ctx *ctx; + struct git_hash_ctx *ctx; int patchlen; }; @@ -6300,13 +6413,13 @@ static int remove_space(char *line, int len) return dst - line; } -void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx) +void flush_one_hunk(struct object_id *result, struct git_hash_ctx *ctx) { unsigned char hash[GIT_MAX_RAWSZ]; unsigned short carry = 0; int i; - the_hash_algo->final_fn(hash, ctx); + git_hash_final(hash, ctx); the_hash_algo->init_fn(ctx); /* 20-byte sum, with carry */ for (i = 0; i < the_hash_algo->rawsz; ++i) { @@ -6325,22 +6438,22 @@ static int patch_id_consume(void *priv, char *line, unsigned long len) return 0; new_len = remove_space(line, len); - the_hash_algo->update_fn(data->ctx, line, new_len); + git_hash_update(data->ctx, line, new_len); data->patchlen += new_len; return 0; } -static void patch_id_add_string(git_hash_ctx *ctx, const char *str) +static void patch_id_add_string(struct git_hash_ctx *ctx, const char *str) { - the_hash_algo->update_fn(ctx, str, strlen(str)); + git_hash_update(ctx, str, strlen(str)); } -static void patch_id_add_mode(git_hash_ctx *ctx, unsigned mode) +static void patch_id_add_mode(struct git_hash_ctx *ctx, unsigned mode) { /* large enough for 2^32 in octal */ char buf[12]; int len = xsnprintf(buf, sizeof(buf), "%06o", mode); - the_hash_algo->update_fn(ctx, buf, len); + git_hash_update(ctx, buf, len); } /* returns 0 upon success, and writes result into oid */ @@ -6348,13 +6461,13 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid { struct diff_queue_struct *q = &diff_queued_diff; int i; - git_hash_ctx ctx; + struct git_hash_ctx ctx; struct patch_id_t data; the_hash_algo->init_fn(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); data.ctx = &ctx; - oidclr(oid); + oidclr(oid, the_repository->hash_algo); for (i = 0; i < q->nr; i++) { xpparam_t xpp; @@ -6384,9 +6497,9 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid len2 = remove_space(p->two->path, strlen(p->two->path)); patch_id_add_string(&ctx, "diff--git"); patch_id_add_string(&ctx, "a/"); - the_hash_algo->update_fn(&ctx, p->one->path, len1); + git_hash_update(&ctx, p->one->path, len1); patch_id_add_string(&ctx, "b/"); - the_hash_algo->update_fn(&ctx, p->two->path, len2); + git_hash_update(&ctx, p->two->path, len2); if (p->one->mode == 0) { patch_id_add_string(&ctx, "newfilemode"); @@ -6405,24 +6518,24 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid /* don't do anything since we're only populating header info */ } else if (diff_filespec_is_binary(options->repo, p->one) || diff_filespec_is_binary(options->repo, p->two)) { - the_hash_algo->update_fn(&ctx, oid_to_hex(&p->one->oid), + git_hash_update(&ctx, oid_to_hex(&p->one->oid), the_hash_algo->hexsz); - the_hash_algo->update_fn(&ctx, oid_to_hex(&p->two->oid), + git_hash_update(&ctx, oid_to_hex(&p->two->oid), the_hash_algo->hexsz); } else { if (p->one->mode == 0) { patch_id_add_string(&ctx, "---/dev/null"); patch_id_add_string(&ctx, "+++b/"); - the_hash_algo->update_fn(&ctx, p->two->path, len2); + git_hash_update(&ctx, p->two->path, len2); } else if (p->two->mode == 0) { patch_id_add_string(&ctx, "---a/"); - the_hash_algo->update_fn(&ctx, p->one->path, len1); + git_hash_update(&ctx, p->one->path, len1); patch_id_add_string(&ctx, "+++/dev/null"); } else { patch_id_add_string(&ctx, "---a/"); - the_hash_algo->update_fn(&ctx, p->one->path, len1); + git_hash_update(&ctx, p->one->path, len1); patch_id_add_string(&ctx, "+++b/"); - the_hash_algo->update_fn(&ctx, p->two->path, len2); + git_hash_update(&ctx, p->two->path, len2); } if (fill_mmfile(options->repo, &mf1, p->one) < 0 || @@ -6447,8 +6560,7 @@ int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int struct diff_queue_struct *q = &diff_queued_diff; int result = diff_get_patch_id(options, oid, diff_header_only); - diff_free_queue(q); - DIFF_QUEUE_CLEAR(q); + diff_queue_clear(q); return result; } @@ -6599,8 +6711,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) static void diff_free_file(struct diff_options *options) { - if (options->close_file) + if (options->close_file && options->file) { fclose(options->file); + options->file = NULL; + } } static void diff_free_ignore_regex(struct diff_options *options) @@ -6611,7 +6725,9 @@ static void diff_free_ignore_regex(struct diff_options *options) regfree(options->ignore_regex[i]); free(options->ignore_regex[i]); } - free(options->ignore_regex); + + FREE_AND_NULL(options->ignore_regex); + options->ignore_regex_nr = 0; } void diff_free(struct diff_options *options) @@ -6619,6 +6735,17 @@ void diff_free(struct diff_options *options) if (options->no_free) return; + if (options->objfind) { + oidset_clear(options->objfind); + FREE_AND_NULL(options->objfind); + } + + FREE_AND_NULL(options->orderfile); + for (size_t i = 0; i < options->anchors_nr; i++) + free(options->anchors[i]); + FREE_AND_NULL(options->anchors); + options->anchors_nr = options->anchors_alloc = 0; + diff_free_file(options); diff_free_ignore_regex(options); clear_pathspec(&options->pathspec); @@ -6679,6 +6806,21 @@ void diff_flush(struct diff_options *options) separator++; } + if (output_format & DIFF_FORMAT_PATCH) { + if (separator) { + emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0); + if (options->stat_sep) + /* attach patch instead of inline */ + emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP, + NULL, 0, 0); + } + + diff_flush_patch_all_file_pairs(options); + } + + if (output_format & DIFF_FORMAT_CALLBACK) + options->format_callback(q, options, options->format_callback_data); + if (output_format & DIFF_FORMAT_NO_OUTPUT && options->flags.exit_with_status && options->flags.diff_from_contents) { @@ -6700,24 +6842,8 @@ void diff_flush(struct diff_options *options) } } - if (output_format & DIFF_FORMAT_PATCH) { - if (separator) { - emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0); - if (options->stat_sep) - /* attach patch instead of inline */ - emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP, - NULL, 0, 0); - } - - diff_flush_patch_all_file_pairs(options); - } - - if (output_format & DIFF_FORMAT_CALLBACK) - options->format_callback(q, options, options->format_callback_data); - free_queue: - diff_free_queue(q); - DIFF_QUEUE_CLEAR(q); + diff_queue_clear(q); diff_free(options); /* @@ -6748,9 +6874,7 @@ static void diffcore_apply_filter(struct diff_options *options) { int i; struct diff_queue_struct *q = &diff_queued_diff; - struct diff_queue_struct outq; - - DIFF_QUEUE_CLEAR(&outq); + struct diff_queue_struct outq = DIFF_QUEUE_INIT; if (!options->filter) return; @@ -6843,8 +6967,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) { int i; struct diff_queue_struct *q = &diff_queued_diff; - struct diff_queue_struct outq; - DIFF_QUEUE_CLEAR(&outq); + struct diff_queue_struct outq = DIFF_QUEUE_INIT; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@ -6915,6 +7038,13 @@ void diff_queued_diff_prefetch(void *repository) oid_array_clear(&to_fetch); } +void init_diffstat_widths(struct diff_options *options) +{ + options->stat_width = -1; /* use full terminal width */ + options->stat_name_width = -1; /* respect diff.statNameWidth config */ + options->stat_graph_width = -1; /* respect diff.statGraphWidth config */ +} + void diffcore_std(struct diff_options *options) { int output_formats_to_prefetch = DIFF_FORMAT_DIFFSTAT | @@ -6955,7 +7085,7 @@ void diffcore_std(struct diff_options *options) diffcore_order(options->orderfile); if (options->rotate_to) diffcore_rotate(options); - if (!options->found_follow) + if (!options->found_follow && !options->skip_resolving_statuses) /* See try_to_follow_renames() in tree-diff.c */ diff_resolve_rename_copy(); diffcore_apply_filter(options); @@ -6968,16 +7098,20 @@ void diffcore_std(struct diff_options *options) options->found_follow = 0; } -int diff_result_code(struct diff_options *opt, int status) +int diff_result_code(struct rev_info *revs) { + struct diff_options *opt = &revs->diffopt; int result = 0; + if (revs->remerge_diff) { + tmp_objdir_destroy(revs->remerge_objdir); + revs->remerge_objdir = NULL; + } + diff_warn_rename_limit("diff.renameLimit", opt->needed_rename_limit, opt->degraded_cc_to_c); - if (!opt->flags.exit_with_status && - !(opt->output_format & DIFF_FORMAT_CHECKDIFF)) - return status; + if (opt->flags.exit_with_status && opt->flags.has_changes) result |= 01; @@ -7024,18 +7158,22 @@ void compute_diffstat(struct diff_options *options, if (check_pair_status(p)) diff_flush_stat(p, options, diffstat); } + options->found_changes = !!diffstat->nr; } -void diff_addremove(struct diff_options *options, - int addremove, unsigned mode, - const struct object_id *oid, - int oid_valid, - const char *concatpath, unsigned dirty_submodule) +struct diff_filepair *diff_queue_addremove(struct diff_queue_struct *queue, + struct diff_options *options, + int addremove, unsigned mode, + const struct object_id *oid, + int oid_valid, + const char *concatpath, + unsigned dirty_submodule) { struct diff_filespec *one, *two; + struct diff_filepair *pair; if (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options)) - return; + return NULL; /* This may look odd, but it is a preparation for * feeding "there are unchanged files which should @@ -7055,7 +7193,7 @@ void diff_addremove(struct diff_options *options, if (options->prefix && strncmp(concatpath, options->prefix, options->prefix_length)) - return; + return NULL; one = alloc_filespec(concatpath); two = alloc_filespec(concatpath); @@ -7067,25 +7205,29 @@ void diff_addremove(struct diff_options *options, two->dirty_submodule = dirty_submodule; } - diff_queue(&diff_queued_diff, one, two); + pair = diff_queue(queue, one, two); if (!options->flags.diff_from_contents) options->flags.has_changes = 1; + + return pair; } -void diff_change(struct diff_options *options, - unsigned old_mode, unsigned new_mode, - const struct object_id *old_oid, - const struct object_id *new_oid, - int old_oid_valid, int new_oid_valid, - const char *concatpath, - unsigned old_dirty_submodule, unsigned new_dirty_submodule) +struct diff_filepair *diff_queue_change(struct diff_queue_struct *queue, + struct diff_options *options, + unsigned old_mode, unsigned new_mode, + const struct object_id *old_oid, + const struct object_id *new_oid, + int old_oid_valid, int new_oid_valid, + const char *concatpath, + unsigned old_dirty_submodule, + unsigned new_dirty_submodule) { struct diff_filespec *one, *two; struct diff_filepair *p; if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) && is_submodule_ignored(concatpath, options)) - return; + return NULL; if (options->flags.reverse_diff) { SWAP(old_mode, new_mode); @@ -7096,7 +7238,7 @@ void diff_change(struct diff_options *options, if (options->prefix && strncmp(concatpath, options->prefix, options->prefix_length)) - return; + return NULL; one = alloc_filespec(concatpath); two = alloc_filespec(concatpath); @@ -7104,19 +7246,42 @@ void diff_change(struct diff_options *options, fill_filespec(two, new_oid, new_oid_valid, new_mode); one->dirty_submodule = old_dirty_submodule; two->dirty_submodule = new_dirty_submodule; - p = diff_queue(&diff_queued_diff, one, two); + p = diff_queue(queue, one, two); if (options->flags.diff_from_contents) - return; + return p; if (options->flags.quick && options->skip_stat_unmatch && !diff_filespec_check_stat_unmatch(options->repo, p)) { diff_free_filespec_data(p->one); diff_free_filespec_data(p->two); - return; + return p; } options->flags.has_changes = 1; + + return p; +} + +void diff_addremove(struct diff_options *options, int addremove, unsigned mode, + const struct object_id *oid, int oid_valid, + const char *concatpath, unsigned dirty_submodule) +{ + diff_queue_addremove(&diff_queued_diff, options, addremove, mode, oid, + oid_valid, concatpath, dirty_submodule); +} + +void diff_change(struct diff_options *options, + unsigned old_mode, unsigned new_mode, + const struct object_id *old_oid, + const struct object_id *new_oid, + int old_oid_valid, int new_oid_valid, + const char *concatpath, + unsigned old_dirty_submodule, unsigned new_dirty_submodule) +{ + diff_queue_change(&diff_queued_diff, options, old_mode, new_mode, + old_oid, new_oid, old_oid_valid, new_oid_valid, + concatpath, old_dirty_submodule, new_dirty_submodule); } struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path) @@ -7179,7 +7344,7 @@ size_t fill_textconv(struct repository *r, if (!driver) { if (!DIFF_FILE_VALID(df)) { - *outbuf = ""; + *outbuf = (char *) ""; return 0; } if (diff_populate_filespec(r, df, NULL)) @@ -7255,6 +7420,6 @@ void setup_diff_pager(struct diff_options *opt) * --exit-code" in hooks and other scripts, we do not do so. */ if (!opt->flags.exit_with_status && - check_pager_config("diff") != 0) - setup_pager(); + check_pager_config(the_repository, "diff") != 0) + setup_pager(the_repository); } |
