blame: honor the diff heuristic options and config

Teach "git blame" and "git annotate" the --compaction-heuristic and --indent-heuristic options that are now supported by "git diff". Also teach them to honor the `diff.compactionHeuristic` and `diff.indentHeuristic` configuration options. It would be conceivable to introduce separate configuration options for "blame" and "annotate"; for example `blame.compactionHeuristic` and `blame.indentHeuristic`. But it would be confusing to users if blame output is inconsistent with diff output, so it makes more sense for them to respect the same configuration. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Sep 5, 2016 at 11:44 UTC 5b162879e93dab3b4bcd66afdbea3a96660abd7d
8 files changed +70 -19
Documentation/diff-heuristic-options.txt new
+7
@@ -0,0 +1,7 @@
1 +--indent-heuristic::
2 +--no-indent-heuristic::
3 +--compaction-heuristic::
4 +--no-compaction-heuristic::
5 + These are to help debugging and tuning experimental heuristics
6 + (which are off by default) that shift diff hunk boundaries to
7 + make patches easier to read.
Documentation/diff-options.txt
+1 -7
@@ -63,13 +63,7 @@ ifndef::git-format-patch[]
63 Synonym for `-p --raw`.
64 endif::git-format-patch[]
65
66 ---indent-heuristic::
67 ---no-indent-heuristic::
68 ---compaction-heuristic::
69 ---no-compaction-heuristic::
70 - These are to help debugging and tuning experimental heuristics
71 - (which are off by default) that shift diff hunk boundaries to
72 - make patches easier to read.
66 +include::diff-heuristic-options.txt[]
67
68 --minimal::
69 Spend extra time to make sure the smallest possible
Documentation/git-annotate.txt
+1
@@ -23,6 +23,7 @@ familiar command name for people coming from other SCM systems.
23 OPTIONS
24 -------
25 include::blame-options.txt[]
26 +include::diff-heuristic-options.txt[]
27
28 SEE ALSO
29 --------
Documentation/git-blame.txt
+2
@@ -89,6 +89,8 @@ include::blame-options.txt[]
89 abbreviated object name, use <n>+1 digits. Note that 1 column
90 is used for a caret to mark the boundary commit.
91
92 +include::diff-heuristic-options.txt[]
93 +
94
95 THE PORCELAIN FORMAT
96 --------------------
builtin/blame.c
+12
@@ -2221,6 +2221,8 @@ static int git_blame_config(const char *var, const char *value, void *cb)
2221 return 0;
2222 }
2223
2224 + if (git_diff_heuristic_config(var, value, cb) < 0)
2225 + return -1;
2226 if (userdiff_config(var, value) < 0)
2227 return -1;
2228
@@ -2542,6 +2544,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2544 OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
2545 OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
2546 OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
2547 +
2548 + /*
2549 + * The following two options are parsed by parse_revision_opt()
2550 + * and are only included here to get included in the "-h"
2551 + * output:
2552 + */
2553 + { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental indent-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb },
2554 + { OPTION_LOWLEVEL_CALLBACK, 0, "compaction-heuristic", NULL, NULL, N_("Use an experimental blank-line-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb },
2555 +
2556 OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
2557 OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
2558 OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
@@ -2588,6 +2599,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2599 }
2600 parse_done:
2601 no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES);
2602 + xdl_opts |= revs.diffopt.xdl_opts & (XDF_COMPACTION_HEURISTIC | XDF_INDENT_HEURISTIC);
2603 DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
2604 argc = parse_options_end(&ctx);
2605
diff.c
+17 -12
@@ -175,6 +175,21 @@ void init_diff_ui_defaults(void)
175 diff_detect_rename_default = 1;
176 }
177
178 +int git_diff_heuristic_config(const char *var, const char *value, void *cb)
179 +{
180 + if (!strcmp(var, "diff.indentheuristic")) {
181 + diff_indent_heuristic = git_config_bool(var, value);
182 + if (diff_indent_heuristic)
183 + diff_compaction_heuristic = 0;
184 + }
185 + if (!strcmp(var, "diff.compactionheuristic")) {
186 + diff_compaction_heuristic = git_config_bool(var, value);
187 + if (diff_compaction_heuristic)
188 + diff_indent_heuristic = 0;
189 + }
190 + return 0;
191 +}
192 +
193 int git_diff_ui_config(const char *var, const char *value, void *cb)
194 {
195 if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
@@ -191,18 +206,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
206 diff_detect_rename_default = git_config_rename(var, value);
207 return 0;
208 }
194 - if (!strcmp(var, "diff.indentheuristic")) {
195 - diff_indent_heuristic = git_config_bool(var, value);
196 - if (diff_indent_heuristic)
197 - diff_compaction_heuristic = 0;
198 - return 0;
199 - }
200 - if (!strcmp(var, "diff.compactionheuristic")) {
201 - diff_compaction_heuristic = git_config_bool(var, value);
202 - if (diff_compaction_heuristic)
203 - diff_indent_heuristic = 0;
204 - return 0;
205 - }
209 if (!strcmp(var, "diff.autorefreshindex")) {
210 diff_auto_refresh_index = git_config_bool(var, value);
211 return 0;
@@ -243,6 +246,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
246 return 0;
247 }
248
249 + if (git_diff_heuristic_config(var, value, cb) < 0)
250 + return -1;
251 if (git_color_config(var, value, cb) < 0)
252 return -1;
253
diff.h
+1
@@ -266,6 +266,7 @@ extern int parse_long_opt(const char *opt, const char **argv,
266 const char **optarg);
267
268 extern int git_diff_basic_config(const char *var, const char *value, void *cb);
269 +extern int git_diff_heuristic_config(const char *var, const char *value, void *cb);
270 extern void init_diff_ui_defaults(void);
271 extern int git_diff_ui_config(const char *var, const char *value, void *cb);
272 extern void diff_setup(struct diff_options *);
t/t4061-diff-indent.sh
+29
@@ -14,6 +14,14 @@ compare_diff () {
14 test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
15 }
16
17 +# Compare blame output using the expectation for a diff as reference.
18 +# Only look for the lines coming from non-boundary commits.
19 +compare_blame () {
20 + sed -n -e "1,4d" -e "s/^\+//p" <"$1" >.tmp-1
21 + sed -ne "s/^[^^][^)]*) *//p" <"$2" >.tmp-2
22 + test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
23 +}
24 +
25 test_expect_success 'prepare' '
26 cat <<-\EOF >spaces.txt &&
27 1
@@ -184,4 +192,25 @@ test_expect_success 'diff: nice functions with --indent-heuristic' '
192 compare_diff functions-compacted-expect out-compacted
193 '
194
195 +test_expect_success 'blame: ugly spaces' '
196 + git blame old..new -- spaces.txt >out-blame &&
197 + compare_blame spaces-expect out-blame
198 +'
199 +
200 +test_expect_success 'blame: nice spaces with --indent-heuristic' '
201 + git blame --indent-heuristic old..new -- spaces.txt >out-blame-compacted &&
202 + compare_blame spaces-compacted-expect out-blame-compacted
203 +'
204 +
205 +test_expect_success 'blame: nice spaces with diff.indentHeuristic' '
206 + git -c diff.indentHeuristic=true blame old..new -- spaces.txt >out-blame-compacted2 &&
207 + compare_blame spaces-compacted-expect out-blame-compacted2
208 +'
209 +
210 +test_expect_success 'blame: --no-indent-heuristic overrides config' '
211 + git -c diff.indentHeuristic=true blame --no-indent-heuristic old..new -- spaces.txt >out-blame2 &&
212 + git blame old..new -- spaces.txt >out-blame &&
213 + compare_blame spaces-expect out-blame2
214 +'
215 +
216 test_done