upload-pack: delegate rev walking in shallow fetch to pack-objects
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 170ada5c3cc3f81f7e0e4e41b0a7a983cfeba28e..266112ca6104450497fb9be504c2404cced595f0 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -36,6 +36,7 @@ static int diff_no_prefix;
 static int diff_stat_graph_width;
 static int diff_dirstat_permille_default = 30;
 static struct diff_options default_diff_options;
+static long diff_algorithm;
 
 static char diff_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RESET,
@@ -143,6 +144,21 @@ static int git_config_rename(const char *var, const char *value)
        return git_config_bool(var,value) ? DIFF_DETECT_RENAME : 0;
 }
 
+long parse_algorithm_value(const char *value)
+{
+       if (!value)
+               return -1;
+       else if (!strcasecmp(value, "myers") || !strcasecmp(value, "default"))
+               return 0;
+       else if (!strcasecmp(value, "minimal"))
+               return XDF_NEED_MINIMAL;
+       else if (!strcasecmp(value, "patience"))
+               return XDF_PATIENCE_DIFF;
+       else if (!strcasecmp(value, "histogram"))
+               return XDF_HISTOGRAM_DIFF;
+       return -1;
+}
+
 /*
  * These are to give UI layer defaults.
  * The core-level commands such as git-diff-files should
@@ -196,6 +212,13 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (!strcmp(var, "diff.algorithm")) {
+               diff_algorithm = parse_algorithm_value(value);
+               if (diff_algorithm < 0)
+                       return -1;
+               return 0;
+       }
+
        if (git_color_config(var, value, cb) < 0)
                return -1;
 
@@ -1241,6 +1264,7 @@ static char *pprint_rename(const char *a, const char *b)
        const char *new = b;
        struct strbuf name = STRBUF_INIT;
        int pfx_length, sfx_length;
+       int pfx_adjust_for_slash;
        int len_a = strlen(a);
        int len_b = strlen(b);
        int a_midlen, b_midlen;
@@ -1267,7 +1291,18 @@ static char *pprint_rename(const char *a, const char *b)
        old = a + len_a;
        new = b + len_b;
        sfx_length = 0;
-       while (a <= old && b <= new && *old == *new) {
+       /*
+        * If there is a common prefix, it must end in a slash.  In
+        * that case we let this loop run 1 into the prefix to see the
+        * same slash.
+        *
+        * If there is no common prefix, we cannot do this as it would
+        * underrun the input strings.
+        */
+       pfx_adjust_for_slash = (pfx_length ? 1 : 0);
+       while (a + pfx_length - pfx_adjust_for_slash <= old &&
+              b + pfx_length - pfx_adjust_for_slash <= new &&
+              *old == *new) {
                if (*old == '/')
                        sfx_length = len_a - (old - a);
                old--;
@@ -1530,7 +1565,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
         * Binary files are displayed with "Bin XXX -> YYY bytes"
         * instead of the change count and graph. This part is treated
         * similarly to the graph part, except that it is not
-        * "scaled". If total width is too small to accomodate the
+        * "scaled". If total width is too small to accommodate the
         * guaranteed minimum width of the filename part and the
         * separators and this message, this message will "overflow"
         * making the line longer than the maximum width.
@@ -1648,9 +1683,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                del = deleted;
 
                if (graph_width <= max_change) {
-                       int total = add + del;
-
-                       total = scale_linear(add + del, graph_width, max_change);
+                       int total = scale_linear(add + del, graph_width, max_change);
                        if (total < 2 && add && del)
                                /* width >= 2 due to the sanity check */
                                total = 2;
@@ -2220,6 +2253,7 @@ static void builtin_diff(const char *name_a,
                const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
                const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
                show_submodule_summary(o->file, one ? one->path : two->path,
+                               line_prefix,
                                one->sha1, two->sha1, two->dirty_submodule,
                                meta, del, add, reset);
                return;
@@ -2550,7 +2584,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
  */
 static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
 {
-       struct cache_entry *ce;
+       const struct cache_entry *ce;
        struct stat st;
        int pos, len;
 
@@ -2641,6 +2675,14 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
 int diff_populate_filespec(struct diff_filespec *s, int size_only)
 {
        int err = 0;
+       /*
+        * demote FAIL to WARN to allow inspecting the situation
+        * instead of refusing.
+        */
+       enum safe_crlf crlf_warn = (safe_crlf == SAFE_CRLF_FAIL
+                                   ? SAFE_CRLF_WARN
+                                   : safe_crlf);
+
        if (!DIFF_FILE_VALID(s))
                die("internal error: asking to populate invalid file.");
        if (S_ISDIR(s->mode))
@@ -2696,7 +2738,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                /*
                 * Convert from working tree format to canonical git format
                 */
-               if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
+               if (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {
                        size_t size = 0;
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
@@ -3163,6 +3205,7 @@ void diff_setup(struct diff_options *options)
        options->add_remove = diff_addremove;
        options->use_color = diff_use_color_default;
        options->detect_rename = diff_detect_rename_default;
+       options->xdl_opts |= diff_algorithm;
 
        if (diff_no_prefix) {
                options->a_prefix = options->b_prefix = "";
@@ -3460,6 +3503,11 @@ static int parse_submodule_opt(struct diff_options *options, const char *value)
        return 1;
 }
 
+static void enable_patch_output(int *fmt) {
+       *fmt &= ~DIFF_FORMAT_NO_OUTPUT;
+       *fmt |= DIFF_FORMAT_PATCH;
+}
+
 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 {
        const char *arg = av[0];
@@ -3467,15 +3515,15 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        int argcount;
 
        /* Output format options */
-       if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch"))
-               options->output_format |= DIFF_FORMAT_PATCH;
-       else if (opt_arg(arg, 'U', "unified", &options->context))
-               options->output_format |= DIFF_FORMAT_PATCH;
+       if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch")
+           || opt_arg(arg, 'U', "unified", &options->context))
+               enable_patch_output(&options->output_format);
        else if (!strcmp(arg, "--raw"))
                options->output_format |= DIFF_FORMAT_RAW;
-       else if (!strcmp(arg, "--patch-with-raw"))
-               options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
-       else if (!strcmp(arg, "--numstat"))
+       else if (!strcmp(arg, "--patch-with-raw")) {
+               enable_patch_output(&options->output_format);
+               options->output_format |= DIFF_FORMAT_RAW;
+       } else if (!strcmp(arg, "--numstat"))
                options->output_format |= DIFF_FORMAT_NUMSTAT;
        else if (!strcmp(arg, "--shortstat"))
                options->output_format |= DIFF_FORMAT_SHORTSTAT;
@@ -3497,13 +3545,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->output_format |= DIFF_FORMAT_CHECKDIFF;
        else if (!strcmp(arg, "--summary"))
                options->output_format |= DIFF_FORMAT_SUMMARY;
-       else if (!strcmp(arg, "--patch-with-stat"))
-               options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
-       else if (!strcmp(arg, "--name-only"))
+       else if (!strcmp(arg, "--patch-with-stat")) {
+               enable_patch_output(&options->output_format);
+               options->output_format |= DIFF_FORMAT_DIFFSTAT;
+       } else if (!strcmp(arg, "--name-only"))
                options->output_format |= DIFF_FORMAT_NAME;
        else if (!strcmp(arg, "--name-status"))
                options->output_format |= DIFF_FORMAT_NAME_STATUS;
-       else if (!strcmp(arg, "-s"))
+       else if (!strcmp(arg, "-s") || !strcmp(arg, "--no-patch"))
                options->output_format |= DIFF_FORMAT_NO_OUTPUT;
        else if (!prefixcmp(arg, "--stat"))
                /* --stat, --stat-width, --stat-name-width, or --stat-count */
@@ -3556,14 +3605,27 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE);
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
+       else if (!strcmp(arg, "--ignore-blank-lines"))
+               DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
        else if (!strcmp(arg, "--patience"))
                options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
        else if (!strcmp(arg, "--histogram"))
                options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
+       else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) {
+               long value = parse_algorithm_value(optarg);
+               if (value < 0)
+                       return error("option diff-algorithm accepts \"myers\", "
+                                    "\"minimal\", \"patience\" and \"histogram\"");
+               /* clear out previous settings */
+               DIFF_XDL_CLR(options, NEED_MINIMAL);
+               options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
+               options->xdl_opts |= value;
+               return argcount;
+       }
 
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
-               options->output_format |= DIFF_FORMAT_PATCH;
+               enable_patch_output(&options->output_format);
                DIFF_OPT_SET(options, BINARY);
        }
        else if (!strcmp(arg, "--full-index"))
@@ -3576,6 +3638,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                DIFF_OPT_SET(options, FIND_COPIES_HARDER);
        else if (!strcmp(arg, "--follow"))
                DIFF_OPT_SET(options, FOLLOW_RENAMES);
+       else if (!strcmp(arg, "--no-follow"))
+               DIFF_OPT_CLR(options, FOLLOW_RENAMES);
        else if (!strcmp(arg, "--color"))
                options->use_color = 1;
        else if (!prefixcmp(arg, "--color=")) {
@@ -4400,7 +4464,7 @@ void diff_flush(struct diff_options *options)
            DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
                /*
                 * run diff_flush_patch for the exit status. setting
-                * options->file to /dev/null should be safe, becaue we
+                * options->file to /dev/null should be safe, because we
                 * aren't supposed to produce any output anyway.
                 */
                if (options->close_file)
@@ -4626,7 +4690,7 @@ int diff_result_code(struct diff_options *opt, int status)
 {
        int result = 0;
 
-       diff_warn_rename_limit("diff.renamelimit",
+       diff_warn_rename_limit("diff.renameLimit",
                               opt->needed_rename_limit,
                               opt->degraded_cc_to_c);
        if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&