summaryrefslogtreecommitdiff
path: root/diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'diff.c')
-rw-r--r--diff.c178
1 files changed, 123 insertions, 55 deletions
diff --git a/diff.c b/diff.c
index f2cfbf2214..d24aaa3047 100644
--- a/diff.c
+++ b/diff.c
@@ -48,6 +48,7 @@ static const char *diff_order_file_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
+static int diff_relative;
static int diff_stat_graph_width;
static int diff_dirstat_permille_default = 30;
static struct diff_options default_diff_options;
@@ -386,6 +387,10 @@ 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.relative")) {
+ diff_relative = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp(var, "diff.statgraphwidth")) {
diff_stat_graph_width = git_config_int(var, value);
return 0;
@@ -573,7 +578,7 @@ static int fill_mmfile(struct repository *r, mmfile_t *mf,
mf->size = 0;
return 0;
}
- else if (diff_populate_filespec(r, one, 0))
+ else if (diff_populate_filespec(r, one, NULL))
return -1;
mf->ptr = one->data;
@@ -585,9 +590,13 @@ static int fill_mmfile(struct repository *r, mmfile_t *mf,
static unsigned long diff_filespec_size(struct repository *r,
struct diff_filespec *one)
{
+ struct diff_populate_filespec_options dpf_options = {
+ .check_size_only = 1,
+ };
+
if (!DIFF_FILE_VALID(one))
return 0;
- diff_populate_filespec(r, one, CHECK_SIZE_ONLY);
+ diff_populate_filespec(r, one, &dpf_options);
return one->size;
}
@@ -3020,6 +3029,9 @@ static void show_dirstat(struct diff_options *options)
struct diff_filepair *p = q->queue[i];
const char *name;
unsigned long copied, added, damage;
+ struct diff_populate_filespec_options dpf_options = {
+ .check_size_only = 1,
+ };
name = p->two->path ? p->two->path : p->one->path;
@@ -3047,19 +3059,19 @@ static void show_dirstat(struct diff_options *options)
}
if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
- diff_populate_filespec(options->repo, p->one, 0);
- diff_populate_filespec(options->repo, p->two, 0);
+ diff_populate_filespec(options->repo, p->one, NULL);
+ diff_populate_filespec(options->repo, p->two, NULL);
diffcore_count_changes(options->repo,
p->one, p->two, NULL, NULL,
&copied, &added);
diff_free_filespec_data(p->one);
diff_free_filespec_data(p->two);
} else if (DIFF_FILE_VALID(p->one)) {
- diff_populate_filespec(options->repo, p->one, CHECK_SIZE_ONLY);
+ diff_populate_filespec(options->repo, p->one, &dpf_options);
copied = added = 0;
diff_free_filespec_data(p->one);
} else if (DIFF_FILE_VALID(p->two)) {
- diff_populate_filespec(options->repo, p->two, CHECK_SIZE_ONLY);
+ diff_populate_filespec(options->repo, p->two, &dpf_options);
copied = 0;
added = p->two->size;
diff_free_filespec_data(p->two);
@@ -3339,13 +3351,17 @@ static void emit_binary_diff(struct diff_options *o,
int diff_filespec_is_binary(struct repository *r,
struct diff_filespec *one)
{
+ struct diff_populate_filespec_options dpf_options = {
+ .check_binary = 1,
+ };
+
if (one->is_binary == -1) {
diff_filespec_load_driver(one, r->index);
if (one->driver->binary != -1)
one->is_binary = one->driver->binary;
else {
if (!one->data && DIFF_FILE_VALID(one))
- diff_populate_filespec(r, one, CHECK_BINARY);
+ diff_populate_filespec(r, one, &dpf_options);
if (one->is_binary == -1 && one->data)
one->is_binary = buffer_is_binary(one->data,
one->size);
@@ -3677,8 +3693,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
}
else if (complete_rewrite) {
- diff_populate_filespec(o->repo, one, 0);
- diff_populate_filespec(o->repo, two, 0);
+ diff_populate_filespec(o->repo, one, NULL);
+ diff_populate_filespec(o->repo, two, NULL);
data->deleted = count_lines(one->data, one->size);
data->added = count_lines(two->data, two->size);
}
@@ -3914,9 +3930,10 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
*/
int diff_populate_filespec(struct repository *r,
struct diff_filespec *s,
- unsigned int flags)
+ const struct diff_populate_filespec_options *options)
{
- int size_only = flags & CHECK_SIZE_ONLY;
+ int size_only = options ? options->check_size_only : 0;
+ int check_binary = options ? options->check_binary : 0;
int err = 0;
int conv_flags = global_conv_flags_eol;
/*
@@ -3986,7 +4003,7 @@ int diff_populate_filespec(struct repository *r,
* opening the file and inspecting the contents, this
* is probably fine.
*/
- if ((flags & CHECK_BINARY) &&
+ if (check_binary &&
s->size > big_file_threshold && s->is_binary == -1) {
s->is_binary = 1;
return 0;
@@ -4011,12 +4028,30 @@ int diff_populate_filespec(struct repository *r,
}
}
else {
- enum object_type type;
- if (size_only || (flags & CHECK_BINARY)) {
- type = oid_object_info(r, &s->oid, &s->size);
- if (type < 0)
- die("unable to read %s",
- oid_to_hex(&s->oid));
+ struct object_info info = {
+ .sizep = &s->size
+ };
+
+ if (!(size_only || check_binary))
+ /*
+ * Set contentp, since there is no chance that merely
+ * the size is sufficient.
+ */
+ info.contentp = &s->data;
+
+ if (options && options->missing_object_cb) {
+ if (!oid_object_info_extended(r, &s->oid, &info,
+ OBJECT_INFO_LOOKUP_REPLACE |
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
+ goto object_read;
+ options->missing_object_cb(options->missing_object_data);
+ }
+ if (oid_object_info_extended(r, &s->oid, &info,
+ OBJECT_INFO_LOOKUP_REPLACE))
+ die("unable to read %s", oid_to_hex(&s->oid));
+
+object_read:
+ if (size_only || check_binary) {
if (size_only)
return 0;
if (s->size > big_file_threshold && s->is_binary == -1) {
@@ -4024,9 +4059,12 @@ int diff_populate_filespec(struct repository *r,
return 0;
}
}
- s->data = repo_read_object_file(r, &s->oid, &type, &s->size);
- if (!s->data)
- die("unable to read %s", oid_to_hex(&s->oid));
+ if (!info.contentp) {
+ info.contentp = &s->data;
+ if (oid_object_info_extended(r, &s->oid, &info,
+ OBJECT_INFO_LOOKUP_REPLACE))
+ die("unable to read %s", oid_to_hex(&s->oid));
+ }
s->should_free = 1;
}
return 0;
@@ -4062,6 +4100,9 @@ static void prep_temp_blob(struct index_state *istate,
struct strbuf tempfile = STRBUF_INIT;
char *path_dup = xstrdup(path);
const char *base = basename(path_dup);
+ struct checkout_metadata meta;
+
+ init_checkout_metadata(&meta, NULL, NULL, oid);
/* Generate "XXXXXX_basename.ext" */
strbuf_addstr(&tempfile, "XXXXXX_");
@@ -4071,7 +4112,7 @@ static void prep_temp_blob(struct index_state *istate,
if (!temp->tempfile)
die_errno("unable to create temp-file");
if (convert_to_working_tree(istate, path,
- (const char *)blob, (size_t)size, &buf)) {
+ (const char *)blob, (size_t)size, &buf, &meta)) {
blob = buf.buf;
size = buf.len;
}
@@ -4141,7 +4182,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r,
return temp;
}
else {
- if (diff_populate_filespec(r, one, 0))
+ if (diff_populate_filespec(r, one, NULL))
die("cannot read data blob for %s", one->path);
prep_temp_blob(r->index, name, temp,
one->data, one->size,
@@ -4502,6 +4543,7 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
options->interhunkcontext = diff_interhunk_context_default;
options->ws_error_highlight = ws_error_highlight_default;
options->flags.rename_empty = 1;
+ options->flags.relative_name = diff_relative;
options->objfind = NULL;
/* pathchange left =NULL by default */
@@ -5159,8 +5201,7 @@ static int diff_opt_relative(const struct option *opt,
{
struct diff_options *options = opt->value;
- BUG_ON_OPT_NEG(unset);
- options->flags.relative_name = 1;
+ options->flags.relative_name = !unset;
if (arg)
options->prefix = arg;
return 0;
@@ -5456,7 +5497,7 @@ static void prep_parse_options(struct diff_options *options)
OPT_GROUP(N_("Other diff options")),
OPT_CALLBACK_F(0, "relative", options, N_("<prefix>"),
N_("when run from subdir, exclude changes outside and show relative paths"),
- PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
+ PARSE_OPT_OPTARG,
diff_opt_relative),
OPT_BOOL('a', "text", &options->flags.text,
N_("treat all files as text")),
@@ -6407,9 +6448,9 @@ static int diff_filespec_is_identical(struct repository *r,
{
if (S_ISGITLINK(one->mode))
return 0;
- if (diff_populate_filespec(r, one, 0))
+ if (diff_populate_filespec(r, one, NULL))
return 0;
- if (diff_populate_filespec(r, two, 0))
+ if (diff_populate_filespec(r, two, NULL))
return 0;
return !memcmp(one->data, two->data, one->size);
}
@@ -6417,6 +6458,12 @@ static int diff_filespec_is_identical(struct repository *r,
static int diff_filespec_check_stat_unmatch(struct repository *r,
struct diff_filepair *p)
{
+ struct diff_populate_filespec_options dpf_options = {
+ .check_size_only = 1,
+ .missing_object_cb = diff_queued_diff_prefetch,
+ .missing_object_data = r,
+ };
+
if (p->done_skip_stat_unmatch)
return p->skip_stat_unmatch_result;
@@ -6439,8 +6486,8 @@ static int diff_filespec_check_stat_unmatch(struct repository *r,
!DIFF_FILE_VALID(p->two) ||
(p->one->oid_valid && p->two->oid_valid) ||
(p->one->mode != p->two->mode) ||
- diff_populate_filespec(r, p->one, CHECK_SIZE_ONLY) ||
- diff_populate_filespec(r, p->two, CHECK_SIZE_ONLY) ||
+ diff_populate_filespec(r, p->one, &dpf_options) ||
+ diff_populate_filespec(r, p->two, &dpf_options) ||
(p->one->size != p->two->size) ||
!diff_filespec_is_identical(r, p->one, p->two)) /* (2) */
p->skip_stat_unmatch_result = 1;
@@ -6491,9 +6538,9 @@ void diffcore_fix_diff_index(void)
QSORT(q->queue, q->nr, diffnamecmp);
}
-static void add_if_missing(struct repository *r,
- struct oid_array *to_fetch,
- const struct diff_filespec *filespec)
+void diff_add_if_missing(struct repository *r,
+ struct oid_array *to_fetch,
+ const struct diff_filespec *filespec)
{
if (filespec && filespec->oid_valid &&
!S_ISGITLINK(filespec->mode) &&
@@ -6502,30 +6549,48 @@ static void add_if_missing(struct repository *r,
oid_array_append(to_fetch, &filespec->oid);
}
-void diffcore_std(struct diff_options *options)
+void diff_queued_diff_prefetch(void *repository)
{
- if (options->repo == the_repository && has_promisor_remote()) {
- /*
- * Prefetch the diff pairs that are about to be flushed.
- */
- int i;
- struct diff_queue_struct *q = &diff_queued_diff;
- struct oid_array to_fetch = OID_ARRAY_INIT;
+ struct repository *repo = repository;
+ int i;
+ struct diff_queue_struct *q = &diff_queued_diff;
+ struct oid_array to_fetch = OID_ARRAY_INIT;
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- add_if_missing(options->repo, &to_fetch, p->one);
- add_if_missing(options->repo, &to_fetch, p->two);
- }
- if (to_fetch.nr)
- /*
- * NEEDSWORK: Consider deduplicating the OIDs sent.
- */
- promisor_remote_get_direct(options->repo,
- to_fetch.oid, to_fetch.nr);
- oid_array_clear(&to_fetch);
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ diff_add_if_missing(repo, &to_fetch, p->one);
+ diff_add_if_missing(repo, &to_fetch, p->two);
}
+ /*
+ * NEEDSWORK: Consider deduplicating the OIDs sent.
+ */
+ promisor_remote_get_direct(repo, to_fetch.oid, to_fetch.nr);
+
+ oid_array_clear(&to_fetch);
+}
+
+void diffcore_std(struct diff_options *options)
+{
+ int output_formats_to_prefetch = DIFF_FORMAT_DIFFSTAT |
+ DIFF_FORMAT_NUMSTAT |
+ DIFF_FORMAT_PATCH |
+ DIFF_FORMAT_SHORTSTAT |
+ DIFF_FORMAT_DIRSTAT;
+
+ /*
+ * Check if the user requested a blob-data-requiring diff output and/or
+ * break-rewrite detection (which requires blob data). If yes, prefetch
+ * the diff pairs.
+ *
+ * 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() &&
+ (options->output_format & output_formats_to_prefetch ||
+ options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK))
+ diff_queued_diff_prefetch(options->repo);
+
/* NOTE please keep the following in sync with diff_tree_combined() */
if (options->skip_stat_unmatch)
diffcore_skip_stat_unmatch(options);
@@ -6698,8 +6763,11 @@ void diff_change(struct diff_options *options,
return;
if (options->flags.quick && options->skip_stat_unmatch &&
- !diff_filespec_check_stat_unmatch(options->repo, p))
+ !diff_filespec_check_stat_unmatch(options->repo, p)) {
+ diff_free_filespec_data(p->one);
+ diff_free_filespec_data(p->two);
return;
+ }
options->flags.has_changes = 1;
}
@@ -6771,7 +6839,7 @@ size_t fill_textconv(struct repository *r,
*outbuf = "";
return 0;
}
- if (diff_populate_filespec(r, df, 0))
+ if (diff_populate_filespec(r, df, NULL))
die("unable to read files to diff");
*outbuf = df->data;
return df->size;