diff: --ignore-cr-at-eol
A new option --ignore-cr-at-eol tells the diff machinery to treat a carriage-return at the end of a (complete) line as if it does not exist. Just like other "--ignore-*" options to ignore various kinds of whitespace differences, this will help reviewing the real changes you made without getting distracted by spurious CRLF<->LF conversion made by your editor program. Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> [jch: squashed in command line completion by Dscho] Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Oct 26, 2017 at 15:32 UTC
e9282f02b2f21118f3383608718e38efc3d967e1
8 files changed
+78
-6
Documentation/diff-options.txt
+3
@@ -519,6 +519,9 @@ endif::git-format-patch[]
519
--text::
520
Treat all files as text.
521
522
+--ignore-cr-at-eol::
523
+ Ignore carrige-return at the end of line when doing a comparison.
524
+
525
--ignore-space-at-eol::
526
Ignore changes in whitespace at EOL.
527
Documentation/merge-strategies.txt
+3
-2
@@ -57,11 +57,12 @@ diff-algorithm=[patience|minimal|histogram|myers];;
57
ignore-space-change;;
58
ignore-all-space;;
59
ignore-space-at-eol;;
60
+ignore-cr-at-eol;;
61
Treats lines with the indicated type of whitespace change as
62
unchanged for the sake of a three-way merge. Whitespace
63
changes mixed with other changes to a line are not ignored.
63
- See also linkgit:git-diff[1] `-b`, `-w`, and
64
- `--ignore-space-at-eol`.
64
+ See also linkgit:git-diff[1] `-b`, `-w`,
65
+ `--ignore-space-at-eol`, and `--ignore-cr-at-eol`.
66
+
67
* If 'their' version only introduces whitespace changes to a line,
68
'our' version is used;
contrib/completion/git-completion.bash
+1
-1
@@ -1399,7 +1399,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
1399
--patch-with-stat --name-only --name-status --color
1400
--no-color --color-words --no-renames --check
1401
--full-index --binary --abbrev --diff-filter=
1402
- --find-copies-harder
1402
+ --find-copies-harder --ignore-cr-at-eol
1403
--text --ignore-space-at-eol --ignore-space-change
1404
--ignore-all-space --ignore-blank-lines --exit-code
1405
--quiet --ext-diff --no-ext-diff
diff.c
+2
@@ -3888,6 +3888,8 @@ int diff_opt_parse(struct diff_options *options,
3888
DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE);
3889
else if (!strcmp(arg, "--ignore-space-at-eol"))
3890
DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
3891
+ else if (!strcmp(arg, "--ignore-cr-at-eol"))
3892
+ DIFF_XDL_SET(options, IGNORE_CR_AT_EOL);
3893
else if (!strcmp(arg, "--ignore-blank-lines"))
3894
DIFF_XDL_SET(options, IGNORE_BLANK_LINES);
3895
else if (!strcmp(arg, "--indent-heuristic"))
merge-recursive.c
+2
@@ -2214,6 +2214,8 @@ int parse_merge_opt(struct merge_options *o, const char *s)
2214
DIFF_XDL_SET(o, IGNORE_WHITESPACE);
2215
else if (!strcmp(s, "ignore-space-at-eol"))
2216
DIFF_XDL_SET(o, IGNORE_WHITESPACE_AT_EOL);
2217
+ else if (!strcmp(s, "ignore-cr-at-eol"))
2218
+ DIFF_XDL_SET(o, IGNORE_CR_AT_EOL);
2219
else if (!strcmp(s, "renormalize"))
2220
o->renormalize = 1;
2221
else if (!strcmp(s, "no-renormalize"))
t/t4015-diff-whitespace.sh
+28
@@ -106,6 +106,8 @@ test_expect_success 'another test, without options' '
106
git diff -w -b --ignore-space-at-eol >out &&
107
test_cmp expect out &&
108
109
+ git diff -w --ignore-cr-at-eol >out &&
110
+ test_cmp expect out &&
111
112
tr "Q_" "\015 " <<-\EOF >expect &&
113
diff --git a/x b/x
@@ -128,6 +130,9 @@ test_expect_success 'another test, without options' '
130
git diff -b --ignore-space-at-eol >out &&
131
test_cmp expect out &&
132
133
+ git diff -b --ignore-cr-at-eol >out &&
134
+ test_cmp expect out &&
135
+
136
tr "Q_" "\015 " <<-\EOF >expect &&
137
diff --git a/x b/x
138
index d99af23..22d9f73 100644
@@ -145,6 +150,29 @@ test_expect_success 'another test, without options' '
150
CR at end
151
EOF
152
git diff --ignore-space-at-eol >out &&
153
+ test_cmp expect out &&
154
+
155
+ git diff --ignore-space-at-eol --ignore-cr-at-eol >out &&
156
+ test_cmp expect out &&
157
+
158
+ tr "Q_" "\015 " <<-\EOF >expect &&
159
+ diff --git a/x b/x
160
+ index_d99af23..22d9f73 100644
161
+ --- a/x
162
+ +++ b/x
163
+ @@ -1,6 +1,6 @@
164
+ -whitespace at beginning
165
+ -whitespace change
166
+ -whitespace in the middle
167
+ -whitespace at end
168
+ +_ whitespace at beginning
169
+ +whitespace_ _change
170
+ +white space in the middle
171
+ +whitespace at end__
172
+ unchanged line
173
+ CR at end
174
+ EOF
175
+ git diff --ignore-cr-at-eol >out &&
176
test_cmp expect out
177
'
178
xdiff/xdiff.h
+3
-1
@@ -33,9 +33,11 @@ extern "C" {
33
#define XDF_IGNORE_WHITESPACE (1 << 1)
34
#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 2)
35
#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 3)
36
+#define XDF_IGNORE_CR_AT_EOL (1 << 4)
37
#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | \
38
XDF_IGNORE_WHITESPACE_CHANGE | \
38
- XDF_IGNORE_WHITESPACE_AT_EOL)
39
+ XDF_IGNORE_WHITESPACE_AT_EOL | \
40
+ XDF_IGNORE_CR_AT_EOL)
41
42
#define XDF_IGNORE_BLANK_LINES (1 << 7)
43
xdiff/xutils.c
+36
-2
@@ -156,6 +156,24 @@ int xdl_blankline(const char *line, long size, long flags)
156
return (i == size);
157
}
158
159
+/*
160
+ * Have we eaten everything on the line, except for an optional
161
+ * CR at the very end?
162
+ */
163
+static int ends_with_optional_cr(const char *l, long s, long i)
164
+{
165
+ int complete = s && l[s-1] == '\n';
166
+
167
+ if (complete)
168
+ s--;
169
+ if (s == i)
170
+ return 1;
171
+ /* do not ignore CR at the end of an incomplete line */
172
+ if (complete && s == i + 1 && l[i] == '\r')
173
+ return 1;
174
+ return 0;
175
+}
176
+
177
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
178
{
179
int i1, i2;
@@ -170,7 +188,8 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
188
189
/*
190
* -w matches everything that matches with -b, and -b in turn
173
- * matches everything that matches with --ignore-space-at-eol.
191
+ * matches everything that matches with --ignore-space-at-eol,
192
+ * which in turn matches everything that matches with --ignore-cr-at-eol.
193
*
194
* Each flavor of ignoring needs different logic to skip whitespaces
195
* 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)
223
i1++;
224
i2++;
225
}
226
+ } else if (flags & XDF_IGNORE_CR_AT_EOL) {
227
+ /* Find the first difference and see how the line ends */
228
+ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
229
+ i1++;
230
+ i2++;
231
+ }
232
+ return (ends_with_optional_cr(l1, s1, i1) &&
233
+ ends_with_optional_cr(l2, s2, i2));
234
}
235
236
/*
@@ -230,9 +257,16 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
257
char const *top, long flags) {
258
unsigned long ha = 5381;
259
char const *ptr = *data;
260
+ int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS) == XDF_IGNORE_CR_AT_EOL;
261
262
for (; ptr < top && *ptr != '\n'; ptr++) {
235
- if (XDL_ISSPACE(*ptr)) {
263
+ if (cr_at_eol_only) {
264
+ /* do not ignore CR at the end of an incomplete line */
265
+ if (*ptr == '\r' &&
266
+ (ptr + 1 < top && ptr[1] == '\n'))
267
+ continue;
268
+ }
269
+ else if (XDL_ISSPACE(*ptr)) {
270
const char *ptr2 = ptr;
271
int at_eol;
272
while (ptr + 1 < top && XDL_ISSPACE(ptr[1])