Skip to content

Commit

Permalink
Allow combined diff to ignore white-spaces
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Antoine Pelisse authored and Junio C Hamano committed Mar 14, 2013
1 parent 239222f commit fa04ae0
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 7 deletions.
57 changes: 50 additions & 7 deletions combine-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "diffcore.h"
#include "quote.h"
#include "xdiff-interface.h"
#include "xdiff/xmacros.h"
#include "log-tree.h"
#include "refs.h"
#include "userdiff.h"
Expand Down Expand Up @@ -122,7 +123,47 @@ static char *grab_blob(const unsigned char *sha1, unsigned int mode,
return blob;
}

static void append_lost(struct sline *sline, int n, const char *line, int len)
static int match_string_spaces(const char *line1, int len1,
const char *line2, int len2,
long flags)
{
if (flags & XDF_WHITESPACE_FLAGS) {
for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
}

if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
return (len1 == len2 && !memcmp(line1, line2, len1));

while (len1 > 0 && len2 > 0) {
len1--;
len2--;
if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
(!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
return 0;

for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
}
if (line1[len1] != line2[len2])
return 0;
}

if (flags & XDF_IGNORE_WHITESPACE) {
/* Consume remaining spaces */
for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
}

/* We matched full line1 and line2 */
if (!len1 && !len2)
return 1;

return 0;
}

static void append_lost(struct sline *sline, int n, const char *line, int len, long flags)
{
struct lline *lline;
unsigned long this_mask = (1UL<<n);
Expand All @@ -133,8 +174,8 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
if (sline->lost_head) {
lline = sline->next_lost;
while (lline) {
if (lline->len == len &&
!memcmp(lline->line, line, len)) {
if (match_string_spaces(lline->line, lline->len,
line, len, flags)) {
lline->parent_map |= this_mask;
sline->next_lost = lline->next;
return;
Expand Down Expand Up @@ -162,6 +203,7 @@ struct combine_diff_state {
int n;
struct sline *sline;
struct sline *lost_bucket;
long flags;
};

static void consume_line(void *state_, char *line, unsigned long len)
Expand Down Expand Up @@ -201,7 +243,7 @@ static void consume_line(void *state_, char *line, unsigned long len)
return; /* not in any hunk yet */
switch (line[0]) {
case '-':
append_lost(state->lost_bucket, state->n, line+1, len-1);
append_lost(state->lost_bucket, state->n, line+1, len-1, state->flags);
break;
case '+':
state->sline[state->lno-1].flag |= state->nmask;
Expand All @@ -215,7 +257,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
struct sline *sline, unsigned int cnt, int n,
int num_parent, int result_deleted,
struct userdiff_driver *textconv,
const char *path)
const char *path, long flags)
{
unsigned int p_lno, lno;
unsigned long nmask = (1UL << n);
Expand All @@ -231,9 +273,10 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path);
parent_file.size = sz;
memset(&xpp, 0, sizeof(xpp));
xpp.flags = 0;
xpp.flags = flags;
memset(&xecfg, 0, sizeof(xecfg));
memset(&state, 0, sizeof(state));
state.flags = flags;
state.nmask = nmask;
state.sline = sline;
state.lno = 1;
Expand Down Expand Up @@ -962,7 +1005,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
elem->parent[i].mode,
&result_file, sline,
cnt, i, num_parent, result_deleted,
textconv, elem->path);
textconv, elem->path, opt->xdl_opts);
}

show_hunks = make_hunks(sline, cnt, num_parent, dense);
Expand Down
111 changes: 111 additions & 0 deletions t/t4038-diff-combined.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
test_description='combined diff'

. ./test-lib.sh
. "$TEST_DIRECTORY"/diff-lib.sh

setup_helper () {
one=$1 branch=$2 side=$3 &&
Expand Down Expand Up @@ -113,4 +114,114 @@ test_expect_success 'check --cc --raw with forty trees' '
grep "^::::::::::::::::::::::::::::::::::::::::[^:]" out
'

test_expect_success 'setup combined ignore spaces' '
git checkout master &&
>test &&
git add test &&
git commit -m initial &&
tr -d Q <<-\EOF >test &&
always coalesce
eol space coalesce Q
space change coalesce
all spa ces coalesce
eol spaces Q
space change
all spa ces
EOF
git commit -m "test space change" -a &&
git checkout -b side HEAD^ &&
tr -d Q <<-\EOF >test &&
always coalesce
eol space coalesce
space change coalesce
all spaces coalesce
eol spaces
space change
all spaces
EOF
git commit -m "test other space changes" -a &&
test_must_fail git merge master &&
tr -d Q <<-\EOF >test &&
eol spaces Q
space change
all spa ces
EOF
git commit -m merged -a
'

test_expect_success 'check combined output (no ignore space)' '
git show >actual.tmp &&
sed -e "1,/^@@@/d" < actual.tmp >actual &&
tr -d Q <<-\EOF >expected &&
--always coalesce
- eol space coalesce
- space change coalesce
- all spaces coalesce
- eol spaces
- space change
- all spaces
-eol space coalesce Q
-space change coalesce
-all spa ces coalesce
+ eol spaces Q
+ space change
+ all spa ces
EOF
compare_diff_patch expected actual
'

test_expect_success 'check combined output (ignore space at eol)' '
git show --ignore-space-at-eol >actual.tmp &&
sed -e "1,/^@@@/d" < actual.tmp >actual &&
tr -d Q <<-\EOF >expected &&
--always coalesce
--eol space coalesce
- space change coalesce
- all spaces coalesce
-space change coalesce
-all spa ces coalesce
eol spaces Q
- space change
- all spaces
+ space change
+ all spa ces
EOF
compare_diff_patch expected actual
'

test_expect_success 'check combined output (ignore space change)' '
git show -b >actual.tmp &&
sed -e "1,/^@@@/d" < actual.tmp >actual &&
tr -d Q <<-\EOF >expected &&
--always coalesce
--eol space coalesce
--space change coalesce
- all spaces coalesce
-all spa ces coalesce
eol spaces Q
space change
- all spaces
+ all spa ces
EOF
compare_diff_patch expected actual
'

test_expect_success 'check combined output (ignore all spaces)' '
git show -w >actual.tmp &&
sed -e "1,/^@@@/d" < actual.tmp >actual &&
tr -d Q <<-\EOF >expected &&
--always coalesce
--eol space coalesce
--space change coalesce
--all spaces coalesce
eol spaces Q
space change
all spa ces
EOF
compare_diff_patch expected actual
'

test_done

0 comments on commit fa04ae0

Please sign in to comment.