Allow combined diff to ignore white-spaces
The combined diff --cc output does not honor options to ignore whitespace changes (-b, -w, and --ignore-space-at-eol). Correct this by passing diff flags to diff engine, so that combined diff behaves as normal diff does with spaces, and by coalescing lines that are removed from both (or more) parents, honoring the same rule to ignore whitespace changes. With this change, a conflict-less merge done using a ignore-* strategy option will not show any conflict if shown in combined-diff using the same option. Signed-off-by: Antoine Pelisse <apelisse@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Antoine Pelisse committed
Mar 14, 2013 at 22:03 UTC
fa04ae0be8cca1291a60bc8a393f9c52d2582089
2 files changed
+161
-7
combine-diff.c
+50
-7
@@ -5,6 +5,7 @@
5
#include "diffcore.h"
6
#include "quote.h"
7
#include "xdiff-interface.h"
8
+#include "xdiff/xmacros.h"
9
#include "log-tree.h"
10
#include "refs.h"
11
#include "userdiff.h"
@@ -122,7 +123,47 @@ static char *grab_blob(const unsigned char *sha1, unsigned int mode,
123
return blob;
124
}
125
125
-static void append_lost(struct sline *sline, int n, const char *line, int len)
126
+static int match_string_spaces(const char *line1, int len1,
127
+ const char *line2, int len2,
128
+ long flags)
129
+{
130
+ if (flags & XDF_WHITESPACE_FLAGS) {
131
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
132
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
133
+ }
134
+
135
+ if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
136
+ return (len1 == len2 && !memcmp(line1, line2, len1));
137
+
138
+ while (len1 > 0 && len2 > 0) {
139
+ len1--;
140
+ len2--;
141
+ if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
142
+ if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
143
+ (!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
144
+ return 0;
145
+
146
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
147
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
148
+ }
149
+ if (line1[len1] != line2[len2])
150
+ return 0;
151
+ }
152
+
153
+ if (flags & XDF_IGNORE_WHITESPACE) {
154
+ /* Consume remaining spaces */
155
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
156
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
157
+ }
158
+
159
+ /* We matched full line1 and line2 */
160
+ if (!len1 && !len2)
161
+ return 1;
162
+
163
+ return 0;
164
+}
165
+
166
+static void append_lost(struct sline *sline, int n, const char *line, int len, long flags)
167
{
168
struct lline *lline;
169
unsigned long this_mask = (1UL<<n);
@@ -133,8 +174,8 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
174
if (sline->lost_head) {
175
lline = sline->next_lost;
176
while (lline) {
136
- if (lline->len == len &&
137
- !memcmp(lline->line, line, len)) {
177
+ if (match_string_spaces(lline->line, lline->len,
178
+ line, len, flags)) {
179
lline->parent_map |= this_mask;
180
sline->next_lost = lline->next;
181
return;
@@ -162,6 +203,7 @@ struct combine_diff_state {
203
int n;
204
struct sline *sline;
205
struct sline *lost_bucket;
206
+ long flags;
207
};
208
209
static void consume_line(void *state_, char *line, unsigned long len)
@@ -201,7 +243,7 @@ static void consume_line(void *state_, char *line, unsigned long len)
243
return; /* not in any hunk yet */
244
switch (line[0]) {
245
case '-':
204
- append_lost(state->lost_bucket, state->n, line+1, len-1);
246
+ append_lost(state->lost_bucket, state->n, line+1, len-1, state->flags);
247
break;
248
case '+':
249
state->sline[state->lno-1].flag |= state->nmask;
@@ -215,7 +257,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
257
struct sline *sline, unsigned int cnt, int n,
258
int num_parent, int result_deleted,
259
struct userdiff_driver *textconv,
218
- const char *path)
260
+ const char *path, long flags)
261
{
262
unsigned int p_lno, lno;
263
unsigned long nmask = (1UL << n);
@@ -231,9 +273,10 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
273
parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path);
274
parent_file.size = sz;
275
memset(&xpp, 0, sizeof(xpp));
234
- xpp.flags = 0;
276
+ xpp.flags = flags;
277
memset(&xecfg, 0, sizeof(xecfg));
278
memset(&state, 0, sizeof(state));
279
+ state.flags = flags;
280
state.nmask = nmask;
281
state.sline = sline;
282
state.lno = 1;
@@ -962,7 +1005,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
1005
elem->parent[i].mode,
1006
&result_file, sline,
1007
cnt, i, num_parent, result_deleted,
965
- textconv, elem->path);
1008
+ textconv, elem->path, opt->xdl_opts);
1009
}
1010
1011
show_hunks = make_hunks(sline, cnt, num_parent, dense);
t/t4038-diff-combined.sh
+111
@@ -3,6 +3,7 @@
3
test_description='combined diff'
4
5
. ./test-lib.sh
6
+. "$TEST_DIRECTORY"/diff-lib.sh
7
8
setup_helper () {
9
one=$1 branch=$2 side=$3 &&
@@ -113,4 +114,114 @@ test_expect_success 'check --cc --raw with forty trees' '
114
grep "^::::::::::::::::::::::::::::::::::::::::[^:]" out
115
'
116
117
+test_expect_success 'setup combined ignore spaces' '
118
+ git checkout master &&
119
+ >test &&
120
+ git add test &&
121
+ git commit -m initial &&
122
+
123
+ tr -d Q <<-\EOF >test &&
124
+ always coalesce
125
+ eol space coalesce Q
126
+ space change coalesce
127
+ all spa ces coalesce
128
+ eol spaces Q
129
+ space change
130
+ all spa ces
131
+ EOF
132
+ git commit -m "test space change" -a &&
133
+
134
+ git checkout -b side HEAD^ &&
135
+ tr -d Q <<-\EOF >test &&
136
+ always coalesce
137
+ eol space coalesce
138
+ space change coalesce
139
+ all spaces coalesce
140
+ eol spaces
141
+ space change
142
+ all spaces
143
+ EOF
144
+ git commit -m "test other space changes" -a &&
145
+
146
+ test_must_fail git merge master &&
147
+ tr -d Q <<-\EOF >test &&
148
+ eol spaces Q
149
+ space change
150
+ all spa ces
151
+ EOF
152
+ git commit -m merged -a
153
+'
154
+
155
+test_expect_success 'check combined output (no ignore space)' '
156
+ git show >actual.tmp &&
157
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
158
+ tr -d Q <<-\EOF >expected &&
159
+ --always coalesce
160
+ - eol space coalesce
161
+ - space change coalesce
162
+ - all spaces coalesce
163
+ - eol spaces
164
+ - space change
165
+ - all spaces
166
+ -eol space coalesce Q
167
+ -space change coalesce
168
+ -all spa ces coalesce
169
+ + eol spaces Q
170
+ + space change
171
+ + all spa ces
172
+ EOF
173
+ compare_diff_patch expected actual
174
+'
175
+
176
+test_expect_success 'check combined output (ignore space at eol)' '
177
+ git show --ignore-space-at-eol >actual.tmp &&
178
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
179
+ tr -d Q <<-\EOF >expected &&
180
+ --always coalesce
181
+ --eol space coalesce
182
+ - space change coalesce
183
+ - all spaces coalesce
184
+ -space change coalesce
185
+ -all spa ces coalesce
186
+ eol spaces Q
187
+ - space change
188
+ - all spaces
189
+ + space change
190
+ + all spa ces
191
+ EOF
192
+ compare_diff_patch expected actual
193
+'
194
+
195
+test_expect_success 'check combined output (ignore space change)' '
196
+ git show -b >actual.tmp &&
197
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
198
+ tr -d Q <<-\EOF >expected &&
199
+ --always coalesce
200
+ --eol space coalesce
201
+ --space change coalesce
202
+ - all spaces coalesce
203
+ -all spa ces coalesce
204
+ eol spaces Q
205
+ space change
206
+ - all spaces
207
+ + all spa ces
208
+ EOF
209
+ compare_diff_patch expected actual
210
+'
211
+
212
+test_expect_success 'check combined output (ignore all spaces)' '
213
+ git show -w >actual.tmp &&
214
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
215
+ tr -d Q <<-\EOF >expected &&
216
+ --always coalesce
217
+ --eol space coalesce
218
+ --space change coalesce
219
+ --all spaces coalesce
220
+ eol spaces Q
221
+ space change
222
+ all spa ces
223
+ EOF
224
+ compare_diff_patch expected actual
225
+'
226
+
227
test_done