Merge branch 'jc/ignore-cr-at-eol'

The "diff" family of commands learned to ignore differences in
carriage return at the end of line.

* jc/ignore-cr-at-eol:
  diff: --ignore-cr-at-eol
  xdiff: reassign xpparm_t.flags bits
This commit is contained in:
Junio C Hamano 2017-11-27 11:06:31 +09:00
commit 10f65c239a
8 changed files with 93 additions and 19 deletions

View file

@ -557,6 +557,9 @@ endif::git-format-patch[]
--text:: --text::
Treat all files as text. Treat all files as text.
--ignore-cr-at-eol::
Ignore carrige-return at the end of line when doing a comparison.
--ignore-space-at-eol:: --ignore-space-at-eol::
Ignore changes in whitespace at EOL. Ignore changes in whitespace at EOL.

View file

@ -58,11 +58,12 @@ diff-algorithm=[patience|minimal|histogram|myers];;
ignore-space-change;; ignore-space-change;;
ignore-all-space;; ignore-all-space;;
ignore-space-at-eol;; ignore-space-at-eol;;
ignore-cr-at-eol;;
Treats lines with the indicated type of whitespace change as Treats lines with the indicated type of whitespace change as
unchanged for the sake of a three-way merge. Whitespace unchanged for the sake of a three-way merge. Whitespace
changes mixed with other changes to a line are not ignored. changes mixed with other changes to a line are not ignored.
See also linkgit:git-diff[1] `-b`, `-w`, and See also linkgit:git-diff[1] `-b`, `-w`,
`--ignore-space-at-eol`. `--ignore-space-at-eol`, and `--ignore-cr-at-eol`.
+ +
* If 'their' version only introduces whitespace changes to a line, * If 'their' version only introduces whitespace changes to a line,
'our' version is used; 'our' version is used;

View file

@ -1400,7 +1400,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
--patch-with-stat --name-only --name-status --color --patch-with-stat --name-only --name-status --color
--no-color --color-words --no-renames --check --no-color --color-words --no-renames --check
--full-index --binary --abbrev --diff-filter= --full-index --binary --abbrev --diff-filter=
--find-copies-harder --find-copies-harder --ignore-cr-at-eol
--text --ignore-space-at-eol --ignore-space-change --text --ignore-space-at-eol --ignore-space-change
--ignore-all-space --ignore-blank-lines --exit-code --ignore-all-space --ignore-blank-lines --exit-code
--quiet --ext-diff --no-ext-diff --quiet --ext-diff --no-ext-diff

6
diff.c
View file

@ -4129,9 +4129,7 @@ void diff_setup_done(struct diff_options *options)
* inside contents. * inside contents.
*/ */
if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) || if ((options->xdl_opts & XDF_WHITESPACE_FLAGS))
DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
options->flags.diff_from_contents = 1; options->flags.diff_from_contents = 1;
else else
options->flags.diff_from_contents = 0; options->flags.diff_from_contents = 0;
@ -4588,6 +4586,8 @@ int diff_opt_parse(struct diff_options *options,
DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE); DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE);
else if (!strcmp(arg, "--ignore-space-at-eol")) else if (!strcmp(arg, "--ignore-space-at-eol"))
DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
else if (!strcmp(arg, "--ignore-cr-at-eol"))
DIFF_XDL_SET(options, IGNORE_CR_AT_EOL);
else if (!strcmp(arg, "--ignore-blank-lines")) else if (!strcmp(arg, "--ignore-blank-lines"))
DIFF_XDL_SET(options, IGNORE_BLANK_LINES); DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
else if (!strcmp(arg, "--indent-heuristic")) else if (!strcmp(arg, "--indent-heuristic"))

View file

@ -2252,6 +2252,8 @@ int parse_merge_opt(struct merge_options *o, const char *s)
DIFF_XDL_SET(o, IGNORE_WHITESPACE); DIFF_XDL_SET(o, IGNORE_WHITESPACE);
else if (!strcmp(s, "ignore-space-at-eol")) else if (!strcmp(s, "ignore-space-at-eol"))
DIFF_XDL_SET(o, IGNORE_WHITESPACE_AT_EOL); DIFF_XDL_SET(o, IGNORE_WHITESPACE_AT_EOL);
else if (!strcmp(s, "ignore-cr-at-eol"))
DIFF_XDL_SET(o, IGNORE_CR_AT_EOL);
else if (!strcmp(s, "renormalize")) else if (!strcmp(s, "renormalize"))
o->renormalize = 1; o->renormalize = 1;
else if (!strcmp(s, "no-renormalize")) else if (!strcmp(s, "no-renormalize"))

View file

@ -106,6 +106,8 @@ test_expect_success 'another test, without options' '
git diff -w -b --ignore-space-at-eol >out && git diff -w -b --ignore-space-at-eol >out &&
test_cmp expect out && test_cmp expect out &&
git diff -w --ignore-cr-at-eol >out &&
test_cmp expect out &&
tr "Q_" "\015 " <<-\EOF >expect && tr "Q_" "\015 " <<-\EOF >expect &&
diff --git a/x b/x diff --git a/x b/x
@ -128,6 +130,9 @@ test_expect_success 'another test, without options' '
git diff -b --ignore-space-at-eol >out && git diff -b --ignore-space-at-eol >out &&
test_cmp expect out && test_cmp expect out &&
git diff -b --ignore-cr-at-eol >out &&
test_cmp expect out &&
tr "Q_" "\015 " <<-\EOF >expect && tr "Q_" "\015 " <<-\EOF >expect &&
diff --git a/x b/x diff --git a/x b/x
index d99af23..22d9f73 100644 index d99af23..22d9f73 100644
@ -145,6 +150,29 @@ test_expect_success 'another test, without options' '
CR at end CR at end
EOF EOF
git diff --ignore-space-at-eol >out && git diff --ignore-space-at-eol >out &&
test_cmp expect out &&
git diff --ignore-space-at-eol --ignore-cr-at-eol >out &&
test_cmp expect out &&
tr "Q_" "\015 " <<-\EOF >expect &&
diff --git a/x b/x
index_d99af23..22d9f73 100644
--- a/x
+++ b/x
@@ -1,6 +1,6 @@
-whitespace at beginning
-whitespace change
-whitespace in the middle
-whitespace at end
+_ whitespace at beginning
+whitespace_ _change
+white space in the middle
+whitespace at end__
unchanged line
CR at end
EOF
git diff --ignore-cr-at-eol >out &&
test_cmp expect out test_cmp expect out
' '

View file

@ -27,22 +27,28 @@
extern "C" { extern "C" {
#endif /* #ifdef __cplusplus */ #endif /* #ifdef __cplusplus */
/* xpparm_t.flags */
#define XDF_NEED_MINIMAL (1 << 0)
#define XDF_NEED_MINIMAL (1 << 1) #define XDF_IGNORE_WHITESPACE (1 << 1)
#define XDF_IGNORE_WHITESPACE (1 << 2) #define XDF_IGNORE_WHITESPACE_CHANGE (1 << 2)
#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3) #define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 3)
#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 4) #define XDF_IGNORE_CR_AT_EOL (1 << 4)
#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE | XDF_IGNORE_WHITESPACE_AT_EOL) #define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | \
XDF_IGNORE_WHITESPACE_CHANGE | \
#define XDF_PATIENCE_DIFF (1 << 5) XDF_IGNORE_WHITESPACE_AT_EOL | \
#define XDF_HISTOGRAM_DIFF (1 << 6) XDF_IGNORE_CR_AT_EOL)
#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
#define XDF_IGNORE_BLANK_LINES (1 << 7) #define XDF_IGNORE_BLANK_LINES (1 << 7)
#define XDF_INDENT_HEURISTIC (1 << 8) #define XDF_PATIENCE_DIFF (1 << 14)
#define XDF_HISTOGRAM_DIFF (1 << 15)
#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
#define XDF_INDENT_HEURISTIC (1 << 23)
/* xdemitconf_t.flags */
#define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCNAMES (1 << 0)
#define XDL_EMIT_FUNCCONTEXT (1 << 2) #define XDL_EMIT_FUNCCONTEXT (1 << 2)

View file

@ -156,6 +156,24 @@ int xdl_blankline(const char *line, long size, long flags)
return (i == size); return (i == size);
} }
/*
* Have we eaten everything on the line, except for an optional
* CR at the very end?
*/
static int ends_with_optional_cr(const char *l, long s, long i)
{
int complete = s && l[s-1] == '\n';
if (complete)
s--;
if (s == i)
return 1;
/* do not ignore CR at the end of an incomplete line */
if (complete && s == i + 1 && l[i] == '\r')
return 1;
return 0;
}
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
{ {
int i1, i2; int i1, i2;
@ -170,7 +188,8 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
/* /*
* -w matches everything that matches with -b, and -b in turn * -w matches everything that matches with -b, and -b in turn
* matches everything that matches with --ignore-space-at-eol. * matches everything that matches with --ignore-space-at-eol,
* which in turn matches everything that matches with --ignore-cr-at-eol.
* *
* Each flavor of ignoring needs different logic to skip whitespaces * Each flavor of ignoring needs different logic to skip whitespaces
* while we have both sides to compare. * while we have both sides to compare.
@ -204,6 +223,14 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
i1++; i1++;
i2++; i2++;
} }
} else if (flags & XDF_IGNORE_CR_AT_EOL) {
/* Find the first difference and see how the line ends */
while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
i1++;
i2++;
}
return (ends_with_optional_cr(l1, s1, i1) &&
ends_with_optional_cr(l2, s2, i2));
} }
/* /*
@ -230,9 +257,16 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
char const *top, long flags) { char const *top, long flags) {
unsigned long ha = 5381; unsigned long ha = 5381;
char const *ptr = *data; char const *ptr = *data;
int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS) == XDF_IGNORE_CR_AT_EOL;
for (; ptr < top && *ptr != '\n'; ptr++) { for (; ptr < top && *ptr != '\n'; ptr++) {
if (XDL_ISSPACE(*ptr)) { if (cr_at_eol_only) {
/* do not ignore CR at the end of an incomplete line */
if (*ptr == '\r' &&
(ptr + 1 < top && ptr[1] == '\n'))
continue;
}
else if (XDL_ISSPACE(*ptr)) {
const char *ptr2 = ptr; const char *ptr2 = ptr;
int at_eol; int at_eol;
while (ptr + 1 < top && XDL_ISSPACE(ptr[1]) while (ptr + 1 < top && XDL_ISSPACE(ptr[1])