diff: Introduce --diff-algorithm command line option
authorMichal Privoznik <mprivozn@redhat.com>
Wed, 16 Jan 2013 07:51:58 +0000 (08:51 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Jan 2013 17:41:18 +0000 (09:41 -0800)
Since command line options have higher priority than config file
variables and taking previous commit into account, we need a way
how to specify myers algorithm on command line. However,
inventing `--myers` is not the right answer. We need far more
general option, and that is `--diff-algorithm`.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/diff-options.txt
contrib/completion/git-completion.bash
diff.c
diff.h
merge-recursive.c

index 39f2c5074c1ac370976bce36cbceb1a676064cfe..81e5be13da27175c3392320b37dd189c7f8d7003 100644 (file)
@@ -55,6 +55,26 @@ endif::git-format-patch[]
 --histogram::
        Generate a diff using the "histogram diff" algorithm.
 
+--diff-algorithm={patience|minimal|histogram|myers}::
+       Choose a diff algorithm. The variants are as follows:
++
+--
+`default`, `myers`;;
+       The basic greedy diff algorithm. Currently, this is the default.
+`minimal`;;
+       Spend extra time to make sure the smallest possible diff is
+       produced.
+`patience`;;
+       Use "patience diff" algorithm when generating patches.
+`histogram`;;
+       This algorithm extends the patience algorithm to "support
+       low-occurrence common elements".
+--
++
+For instance, if you configured diff.algorithm variable to a
+non-default value and want to use the default one, then you
+have to use `--diff-algorithm=default` option.
+
 --stat[=<width>[,<name-width>[,<count>]]]::
        Generate a diffstat. By default, as much space as necessary
        will be used for the filename part, and the rest for the graph
index 33e25dc08cfe11df2b5eb04beec33bac167be462..d592cf9be95c35dd7df64bd21214d1f24afc242e 100644 (file)
@@ -1021,6 +1021,8 @@ _git_describe ()
        __gitcomp_nl "$(__git_refs)"
 }
 
+__git_diff_algorithms="myers minimal patience histogram"
+
 __git_diff_common_options="--stat --numstat --shortstat --summary
                        --patch-with-stat --name-only --name-status --color
                        --no-color --color-words --no-renames --check
@@ -1035,6 +1037,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
                        --raw
                        --dirstat --dirstat= --dirstat-by-file
                        --dirstat-by-file= --cumulative
+                       --diff-algorithm=
 "
 
 _git_diff ()
@@ -1042,6 +1045,10 @@ _git_diff ()
        __git_has_doubledash && return
 
        case "$cur" in
+       --diff-algorithm=*)
+               __gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
+               return
+               ;;
        --*)
                __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
                        --base --ours --theirs --no-index
@@ -2114,6 +2121,10 @@ _git_show ()
                        " "" "${cur#*=}"
                return
                ;;
+       --diff-algorithm=*)
+               __gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
+               return
+               ;;
        --*)
                __gitcomp "--pretty= --format= --abbrev-commit --oneline
                        $__git_diff_common_options
diff --git a/diff.c b/diff.c
index d2be7777930eee055ad317cbb24a0d65f4ce441b..0724fa6ff6c4312733e520d59f88ea12740d408d 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -144,7 +144,7 @@ static int git_config_rename(const char *var, const char *value)
        return git_config_bool(var,value) ? DIFF_DETECT_RENAME : 0;
 }
 
-static long parse_algorithm_value(const char *value)
+long parse_algorithm_value(const char *value)
 {
        if (!value)
                return -1;
@@ -3634,6 +3634,16 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                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 (!prefixcmp(arg, "--diff-algorithm=")) {
+               long value = parse_algorithm_value(arg+17);
+               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;
+       }
 
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
diff --git a/diff.h b/diff.h
index a47bae48d5d14a321108aac3b3de3892587b264f..54c2590b4f81ed2cc370f1b8b16db8cd07ea9f64 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -333,6 +333,8 @@ extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
 
 extern int parse_rename_score(const char **cp_p);
 
+extern long parse_algorithm_value(const char *value);
+
 extern int print_stat_summary(FILE *fp, int files,
                              int insertions, int deletions);
 extern void setup_diff_pager(struct diff_options *);
index 33ba5dc07c86a81f0989927b9a6167833815533f..ea9dbd307c60a16f290b44964c386e566b6bc7e3 100644 (file)
@@ -2068,6 +2068,15 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
        else if (!strcmp(s, "histogram"))
                o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
+       else if (!strcmp(s, "diff-algorithm=")) {
+               long value = parse_algorithm_value(s+15);
+               if (value < 0)
+                       return -1;
+               /* clear out previous settings */
+               DIFF_XDL_CLR(o, NEED_MINIMAL);
+               o->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
+               o->xdl_opts |= value;
+       }
        else if (!strcmp(s, "ignore-space-change"))
                o->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(s, "ignore-all-space"))