diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 7c70c2a2feca88a2c1247794e2ee0fbed767bb4a..ac770502553d9b4d3d1176f63ad01791736602a8 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -156,3 +156,20 @@ diff.tool:: that a corresponding difftool..cmd variable is defined. include::mergetools-diff.txt[] + +diff.algorithm:: + 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". +-- ++ diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 7a8747352622b511e1edcb00919b2fb298dcba08..869d965a3b93e25c71fd4c81a7f7742ff2222cfe 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -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[=[,[,]]]:: Generate a diffstat. By default, as much space as necessary will be used for the filename part, and the rest for the graph diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 059ba9d3e482c08434fb6860667179a6b73808cd..b62bec027963edc8607067e990509b694cdbc9db 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1232,6 +1232,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 @@ -1242,10 +1244,11 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --no-ext-diff --no-prefix --src-prefix= --dst-prefix= --inter-hunk-context= - --patience + --patience --histogram --minimal --raw --dirstat --dirstat= --dirstat-by-file --dirstat-by-file= --cumulative + --diff-algorithm= " _git_diff () @@ -1253,6 +1256,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 @@ -2058,6 +2065,7 @@ _git_config () diff.suppressBlankEmpty diff.tool diff.wordRegex + diff.algorithm difftool. difftool.prompt fetch.recurseSubmodules @@ -2331,6 +2339,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 f441f6c7f8790a9601163a7e3280239e63036755..156fec447061f83855edf27d578f055bb606cacf 100644 --- 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; @@ -3163,6 +3186,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 = ""; @@ -3560,6 +3584,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 76830e28b42ab623ef9dc1d23c4b82b952fadd3a..78b4091dd5b59fe4442262cd79cf71f8a4a2b98f 100644 --- a/diff.h +++ b/diff.h @@ -336,6 +336,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 *); diff --git a/merge-recursive.c b/merge-recursive.c index 33ba5dc07c86a81f0989927b9a6167833815533f..ea9dbd307c60a16f290b44964c386e566b6bc7e3 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -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"))