diff options
Diffstat (limited to 'diff.c')
| -rw-r--r-- | diff.c | 229 |
1 files changed, 160 insertions, 69 deletions
@@ -23,7 +23,7 @@ #include "color.h" #include "run-command.h" #include "utf8.h" -#include "object-store-ll.h" +#include "odb.h" #include "userdiff.h" #include "submodule.h" #include "hashmap.h" @@ -327,29 +327,23 @@ static unsigned parse_color_moved_ws(const char *arg) struct string_list l = STRING_LIST_INIT_DUP; struct string_list_item *i; - string_list_split(&l, arg, ',', -1); + string_list_split_f(&l, arg, ",", -1, STRING_LIST_SPLIT_TRIM); for_each_string_list_item(i, &l) { - struct strbuf sb = STRBUF_INIT; - strbuf_addstr(&sb, i->string); - strbuf_trim(&sb); - - if (!strcmp(sb.buf, "no")) + if (!strcmp(i->string, "no")) ret = 0; - else if (!strcmp(sb.buf, "ignore-space-change")) + else if (!strcmp(i->string, "ignore-space-change")) ret |= XDF_IGNORE_WHITESPACE_CHANGE; - else if (!strcmp(sb.buf, "ignore-space-at-eol")) + else if (!strcmp(i->string, "ignore-space-at-eol")) ret |= XDF_IGNORE_WHITESPACE_AT_EOL; - else if (!strcmp(sb.buf, "ignore-all-space")) + else if (!strcmp(i->string, "ignore-all-space")) ret |= XDF_IGNORE_WHITESPACE; - else if (!strcmp(sb.buf, "allow-indentation-change")) + else if (!strcmp(i->string, "allow-indentation-change")) ret |= COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE; else { ret |= COLOR_MOVED_WS_ERROR; - error(_("unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', 'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"), sb.buf); + error(_("unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', 'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"), i->string); } - - strbuf_release(&sb); } if ((ret & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) && @@ -892,7 +886,7 @@ static void fill_es_indent_data(struct emitted_diff_symbol *es) /* skip any \v \f \r at start of indentation */ while (s[off] == '\f' || s[off] == '\v' || - (s[off] == '\r' && off < len - 1)) + (off < len - 1 && s[off] == '\r')) off++; /* calculate the visual width of indentation */ @@ -2444,6 +2438,15 @@ static int fn_out_consume(void *priv, char *line, unsigned long len) return 0; } +static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED) +{ + struct emit_callback *ecbdata = priv; + struct diff_options *o = ecbdata->opt; + + o->found_changes = 1; + return 1; +} + static void pprint_rename(struct strbuf *name, const char *a, const char *b) { const char *old_name = a; @@ -3759,8 +3762,21 @@ static void builtin_diff(const char *name_a, if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); - if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume, - &ecbdata, &xpp, &xecfg)) + if (o->dry_run) { + /* + * Unlike the !dry_run case, we need to ignore the + * return value from xdi_diff_outf() here, because + * xdi_diff_outf() takes non-zero return from its + * callback function as a sign of error and returns + * early (which is why we return non-zero from our + * callback, quick_consume()). Unfortunately, + * xdi_diff_outf() signals an error by returning + * non-zero. + */ + xdi_diff_outf(&mf1, &mf2, NULL, quick_consume, + &ecbdata, &xpp, &xecfg); + } else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume, + &ecbdata, &xpp, &xecfg)) die("unable to generate diff for %s", one->path); if (o->word_diff) free_diff_words_data(&ecbdata); @@ -4193,7 +4209,8 @@ int diff_populate_filespec(struct repository *r, * is probably fine. */ if (check_binary && - s->size > big_file_threshold && s->is_binary == -1) { + s->size > repo_settings_get_big_file_threshold(the_repository) && + s->is_binary == -1) { s->is_binary = 1; return 0; } @@ -4229,29 +4246,30 @@ int diff_populate_filespec(struct repository *r, 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)) + if (!odb_read_object_info_extended(r->objects, &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)) + if (odb_read_object_info_extended(r->objects, &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) { + if (s->size > repo_settings_get_big_file_threshold(the_repository) && + s->is_binary == -1) { s->is_binary = 1; return 0; } } if (!info.contentp) { info.contentp = &s->data; - if (oid_object_info_extended(r, &s->oid, &info, - OBJECT_INFO_LOOKUP_REPLACE)) + if (odb_read_object_info_extended(r->objects, &s->oid, &info, + OBJECT_INFO_LOOKUP_REPLACE)) die("unable to read %s", oid_to_hex(&s->oid)); } s->should_free = 1; @@ -4344,7 +4362,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r, die_errno("readlink(%s)", one->path); prep_temp_blob(r->index, one->path, temp, sb.buf, sb.len, (one->oid_valid ? - &one->oid : null_oid()), + &one->oid : null_oid(the_hash_algo)), (one->oid_valid ? one->mode : S_IFLNK)); strbuf_release(&sb); @@ -4353,7 +4371,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r, /* we can borrow from the file in the work tree */ temp->name = one->path; if (!one->oid_valid) - oid_to_hex_r(temp->hex, null_oid()); + oid_to_hex_r(temp->hex, null_oid(the_hash_algo)); else oid_to_hex_r(temp->hex, &one->oid); /* Even though we may sometimes borrow the @@ -4986,6 +5004,9 @@ void diff_setup_done(struct diff_options *options) options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON]; options->filter &= ~options->filter_not; } + + if (options->pathspec.has_wildcard && options->max_depth_valid) + die("max-depth cannot be used with wildcard pathspecs"); } int parse_long_opt(const char *opt, const char **argv, @@ -5620,6 +5641,23 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns return 0; } +static int diff_opt_max_depth(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + + if (!git_parse_int(arg, &options->max_depth)) + return error(_("invalid value for '%s': '%s'"), + "--max-depth", arg); + + options->flags.recursive = 1; + options->max_depth_valid = options->max_depth >= 0; + + return 0; +} + /* * Consider adding new flags to __git_diff_common_options * in contrib/completion/git-completion.bash @@ -5892,10 +5930,19 @@ struct option *add_diff_options(const struct option *opts, OPT_CALLBACK_F(0, "diff-filter", options, N_("[(A|C|D|M|R|T|U|X|B)...[*]]"), N_("select files by diff type"), PARSE_OPT_NONEG, diff_opt_diff_filter), - { OPTION_CALLBACK, 0, "output", options, N_("<file>"), - N_("output to a specific file"), - PARSE_OPT_NONEG, NULL, 0, diff_opt_output }, - + OPT_CALLBACK_F(0, "max-depth", options, N_("<depth>"), + N_("maximum tree depth to recurse"), + PARSE_OPT_NONEG, diff_opt_max_depth), + + { + .type = OPTION_CALLBACK, + .long_name = "output", + .value = options, + .argh = N_("<file>"), + .help = N_("output to a specific file"), + .flags = PARSE_OPT_NONEG, + .ll_callback = diff_opt_output, + }, OPT_END() }; @@ -6143,6 +6190,22 @@ static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o) run_diff(p, o); } +/* return 1 if any change is found; otherwise, return 0 */ +static int diff_flush_patch_quietly(struct diff_filepair *p, struct diff_options *o) +{ + int saved_dry_run = o->dry_run; + int saved_found_changes = o->found_changes; + int ret; + + o->dry_run = 1; + o->found_changes = 0; + diff_flush_patch(p, o); + ret = o->found_changes; + o->dry_run = saved_dry_run; + o->found_changes |= saved_found_changes; + return ret; +} + static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, struct diffstat_t *diffstat) { @@ -6647,8 +6710,8 @@ static void create_filepairs_for_header_only_notifications(struct diff_options * one = alloc_filespec(e->key); two = alloc_filespec(e->key); - fill_filespec(one, null_oid(), 0, 0); - fill_filespec(two, null_oid(), 0, 0); + fill_filespec(one, null_oid(the_hash_algo), 0, 0); + fill_filespec(two, null_oid(the_hash_algo), 0, 0); p = diff_queue(q, one, two); p->status = DIFF_STATUS_MODIFIED; } @@ -6771,8 +6834,15 @@ void diff_flush(struct diff_options *options) DIFF_FORMAT_CHECKDIFF)) { for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (check_pair_status(p)) - flush_one_pair(p, options); + + if (!check_pair_status(p)) + continue; + + if (options->flags.diff_from_contents && + !diff_flush_patch_quietly(p, options)) + continue; + + flush_one_pair(p, options); } separator++; } @@ -6824,19 +6894,10 @@ void diff_flush(struct diff_options *options) if (output_format & DIFF_FORMAT_NO_OUTPUT && options->flags.exit_with_status && options->flags.diff_from_contents) { - /* - * run diff_flush_patch for the exit status. setting - * options->file to /dev/null should be safe, because we - * aren't supposed to produce any output anyway. - */ - diff_free_file(options); - options->file = xfopen("/dev/null", "w"); - options->close_file = 1; - options->color_moved = 0; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (check_pair_status(p)) - diff_flush_patch(p, options); + diff_flush_patch_quietly(p, options); if (options->found_changes) break; } @@ -7012,8 +7073,8 @@ void diff_add_if_missing(struct repository *r, { if (filespec && filespec->oid_valid && !S_ISGITLINK(filespec->mode) && - oid_object_info_extended(r, &filespec->oid, NULL, - OBJECT_INFO_FOR_PREFETCH)) + odb_read_object_info_extended(r->objects, &filespec->oid, NULL, + OBJECT_INFO_FOR_PREFETCH)) oid_array_append(to_fetch, &filespec->oid); } @@ -7085,7 +7146,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); @@ -7161,16 +7222,19 @@ void compute_diffstat(struct diff_options *options, 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 @@ -7190,7 +7254,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); @@ -7202,25 +7266,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); @@ -7231,7 +7299,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); @@ -7239,19 +7307,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) |
