aboutsummaryrefslogtreecommitdiffstats
path: root/diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'diff.c')
-rw-r--r--diff.c429
1 files changed, 297 insertions, 132 deletions
diff --git a/diff.c b/diff.c
index 6fb2946a64..08f5e00a2c 100644
--- a/diff.c
+++ b/diff.c
@@ -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);
}