#include "packfile.h"
#include "parse-options.h"
#include "help.h"
-#include "fetch-object.h"
+#include "promisor-remote.h"
#ifdef NO_FAST_WORKING_DIRECTORY
#define FAST_WORKING_DIRECTORY 0
return 0;
}
- if (!strcmp(var, "diff.wserrorhighlight")) {
- int val = parse_ws_error_highlight(value);
- if (val < 0)
- return -1;
- ws_error_highlight_default = val;
- return 0;
- }
-
if (git_color_config(var, value, cb) < 0)
return -1;
return color_parse(value, diff_colors[slot]);
}
+ if (!strcmp(var, "diff.wserrorhighlight")) {
+ int val = parse_ws_error_highlight(value);
+ if (val < 0)
+ return -1;
+ ws_error_highlight_default = val;
+ return 0;
+ }
+
/* like GNU diff's --suppress-blank-empty option */
if (!strcmp(var, "diff.suppressblankempty") ||
/* for backwards compatibility */
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;
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;
}
}
static int moved_entry_cmp(const void *hashmap_cmp_fn_data,
- const void *entry,
- const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
const struct diff_options *diffopt = hashmap_cmp_fn_data;
- const struct moved_entry *a = entry;
- const struct moved_entry *b = entry_or_key;
+ const struct moved_entry *a, *b;
unsigned flags = diffopt->color_moved_ws_handling
& XDF_WHITESPACE_FLAGS;
+ a = container_of(eptr, const struct moved_entry, ent);
+ b = container_of(entry_or_key, const struct moved_entry, ent);
+
if (diffopt->color_moved_ws_handling &
COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
/*
struct moved_entry *ret = xmalloc(sizeof(*ret));
struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
unsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;
+ unsigned int hash = xdiff_hash_string(l->line, l->len, flags);
- ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
+ hashmap_entry_init(&ret->ent, hash);
ret->es = l;
ret->next_line = NULL;
if (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s)
prev_line->next_line = key;
- hashmap_add(hm, key);
+ hashmap_add(hm, &key->ent);
prev_line = key;
}
}
struct moved_entry *prev = pmb[i].match;
struct moved_entry *cur = (prev && prev->next_line) ?
prev->next_line : NULL;
- if (cur && !hm->cmpfn(o, cur, match, NULL)) {
+ if (cur && !hm->cmpfn(o, &cur->ent, &match->ent, NULL)) {
pmb[i].match = cur;
} else {
pmb[i].match = NULL;
int i;
char *got_match = xcalloc(1, pmb_nr);
- for (; match; match = hashmap_get_next(hm, match)) {
+ hashmap_for_each_entry_from(hm, match, ent) {
for (i = 0; i < pmb_nr; i++) {
struct moved_entry *prev = pmb[i].match;
struct moved_entry *cur = (prev && prev->next_line) ?
case DIFF_SYMBOL_PLUS:
hm = del_lines;
key = prepare_entry(o, n);
- match = hashmap_get(hm, key, NULL);
+ match = hashmap_get_entry(hm, key, ent, NULL);
free(key);
break;
case DIFF_SYMBOL_MINUS:
hm = add_lines;
key = prepare_entry(o, n);
- match = hashmap_get(hm, key, NULL);
+ match = hashmap_get_entry(hm, key, ent, NULL);
free(key);
break;
default:
* The current line is the start of a new block.
* Setup the set of potential blocks.
*/
- for (; match; match = hashmap_get_next(hm, match)) {
+ hashmap_for_each_entry_from(hm, match, ent) {
ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
if (o->color_moved_ws_handling &
COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
}
}
-struct diffstat_t {
- int nr;
- int alloc;
- struct diffstat_file {
- char *from_name;
- char *name;
- char *print_name;
- const char *comments;
- unsigned is_unmerged:1;
- unsigned is_binary:1;
- unsigned is_renamed:1;
- unsigned is_interesting:1;
- uintmax_t added, deleted;
- } **files;
-};
-
static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
const char *name_a,
const char *name_b)
/*
* make sure that at least one '-' or '+' is printed if
* there is any change to this path. The easiest way is to
- * scale linearly as if the alloted width is one column shorter
+ * scale linearly as if the allotted width is one column shorter
* than it is, and then add 1 to the result.
*/
return 1 + (it * (width - 1) / max_change);
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;
}
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);
gather_dirstat(options, &dir, changed, "", 0);
}
-static void free_diffstat_info(struct diffstat_t *diffstat)
+void free_diffstat_info(struct diffstat_t *diffstat)
{
int i;
for (i = 0; i < diffstat->nr; i++) {
for (cnt = 1; cnt < marker_size; cnt++)
if (line[cnt] != firstchar)
return 0;
- /* line[1] thru line[marker_size-1] are same as firstchar */
+ /* line[1] through line[marker_size-1] are same as firstchar */
if (len < marker_size + 1 || !isspace(line[marker_size]))
return 0;
return 1;
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);
}
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);
}
*/
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;
/*
* 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;
}
}
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) {
return 0;
}
}
- s->data = read_object_file(&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;
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_");
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;
}
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,
}
struct patch_id_t {
- git_SHA_CTX *ctx;
+ git_hash_ctx *ctx;
int patchlen;
};
return dst - line;
}
-void flush_one_hunk(struct object_id *result, git_SHA_CTX *ctx)
+void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx)
{
unsigned char hash[GIT_MAX_RAWSZ];
unsigned short carry = 0;
int i;
- git_SHA1_Final(hash, ctx);
- git_SHA1_Init(ctx);
+ the_hash_algo->final_fn(hash, ctx);
+ the_hash_algo->init_fn(ctx);
/* 20-byte sum, with carry */
- for (i = 0; i < GIT_SHA1_RAWSZ; ++i) {
+ for (i = 0; i < the_hash_algo->rawsz; ++i) {
carry += result->hash[i] + hash[i];
result->hash[i] = carry;
carry >>= 8;
new_len = remove_space(line, len);
- git_SHA1_Update(data->ctx, line, new_len);
+ the_hash_algo->update_fn(data->ctx, line, new_len);
data->patchlen += new_len;
}
-static void patch_id_add_string(git_SHA_CTX *ctx, const char *str)
+static void patch_id_add_string(git_hash_ctx *ctx, const char *str)
{
- git_SHA1_Update(ctx, str, strlen(str));
+ the_hash_algo->update_fn(ctx, str, strlen(str));
}
-static void patch_id_add_mode(git_SHA_CTX *ctx, unsigned mode)
+static void patch_id_add_mode(git_hash_ctx *ctx, unsigned mode)
{
/* large enough for 2^32 in octal */
char buf[12];
int len = xsnprintf(buf, sizeof(buf), "%06o", mode);
- git_SHA1_Update(ctx, buf, len);
+ the_hash_algo->update_fn(ctx, buf, len);
}
/* returns 0 upon success, and writes result into oid */
{
struct diff_queue_struct *q = &diff_queued_diff;
int i;
- git_SHA_CTX ctx;
+ git_hash_ctx ctx;
struct patch_id_t data;
- git_SHA1_Init(&ctx);
+ the_hash_algo->init_fn(&ctx);
memset(&data, 0, sizeof(struct patch_id_t));
data.ctx = &ctx;
oidclr(oid);
len2 = remove_space(p->two->path, strlen(p->two->path));
patch_id_add_string(&ctx, "diff--git");
patch_id_add_string(&ctx, "a/");
- git_SHA1_Update(&ctx, p->one->path, len1);
+ the_hash_algo->update_fn(&ctx, p->one->path, len1);
patch_id_add_string(&ctx, "b/");
- git_SHA1_Update(&ctx, p->two->path, len2);
+ the_hash_algo->update_fn(&ctx, p->two->path, len2);
if (p->one->mode == 0) {
patch_id_add_string(&ctx, "newfilemode");
patch_id_add_mode(&ctx, p->two->mode);
patch_id_add_string(&ctx, "---/dev/null");
patch_id_add_string(&ctx, "+++b/");
- git_SHA1_Update(&ctx, p->two->path, len2);
+ the_hash_algo->update_fn(&ctx, p->two->path, len2);
} else if (p->two->mode == 0) {
patch_id_add_string(&ctx, "deletedfilemode");
patch_id_add_mode(&ctx, p->one->mode);
patch_id_add_string(&ctx, "---a/");
- git_SHA1_Update(&ctx, p->one->path, len1);
+ the_hash_algo->update_fn(&ctx, p->one->path, len1);
patch_id_add_string(&ctx, "+++/dev/null");
} else {
patch_id_add_string(&ctx, "---a/");
- git_SHA1_Update(&ctx, p->one->path, len1);
+ the_hash_algo->update_fn(&ctx, p->one->path, len1);
patch_id_add_string(&ctx, "+++b/");
- git_SHA1_Update(&ctx, p->two->path, len2);
+ the_hash_algo->update_fn(&ctx, p->two->path, len2);
}
if (diff_header_only)
if (diff_filespec_is_binary(options->repo, p->one) ||
diff_filespec_is_binary(options->repo, p->two)) {
- git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid),
- GIT_SHA1_HEXSZ);
- git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid),
- GIT_SHA1_HEXSZ);
+ the_hash_algo->update_fn(&ctx, oid_to_hex(&p->one->oid),
+ the_hash_algo->hexsz);
+ the_hash_algo->update_fn(&ctx, oid_to_hex(&p->two->oid),
+ the_hash_algo->hexsz);
continue;
}
}
if (!stable)
- git_SHA1_Final(oid->hash, &ctx);
+ the_hash_algo->final_fn(oid->hash, &ctx);
return 0;
}
if (o->color_moved == COLOR_MOVED_ZEBRA_DIM)
dim_moved_lines(o);
- hashmap_free(&add_lines, 1);
- hashmap_free(&del_lines, 1);
+ hashmap_free_entries(&add_lines, struct moved_entry,
+ ent);
+ hashmap_free_entries(&del_lines, struct moved_entry,
+ ent);
}
for (i = 0; i < esm.nr; i++)
dirstat_by_line) {
struct diffstat_t diffstat;
- memset(&diffstat, 0, sizeof(struct diffstat_t));
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- if (check_pair_status(p))
- diff_flush_stat(p, options, &diffstat);
- }
+ compute_diffstat(options, &diffstat, q);
if (output_format & DIFF_FORMAT_NUMSTAT)
show_numstat(&diffstat, options);
if (output_format & DIFF_FORMAT_DIFFSTAT)
{
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);
}
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;
!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;
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) &&
oid_object_info_extended(r, &filespec->oid, NULL,
OBJECT_INFO_FOR_PREFETCH))
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 &&
- repository_format_partial_clone) {
- /*
- * 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.
- */
- fetch_objects(repository_format_partial_clone,
- 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);
return ignored;
}
+void compute_diffstat(struct diff_options *options,
+ struct diffstat_t *diffstat,
+ struct diff_queue_struct *q)
+{
+ int i;
+
+ memset(diffstat, 0, sizeof(struct diffstat_t));
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ if (check_pair_status(p))
+ diff_flush_stat(p, options, diffstat);
+ }
+}
+
void diff_addremove(struct diff_options *options,
int addremove, unsigned mode,
const struct object_id *oid,
*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;