Currently, it's not possible to use the space-ignoring options (-b, -w,
--ignore-space-at-eol) with combined diff. It makes it pretty impossible
to read a merge between a branch that changed all tabs to spaces, and a
branch with functional changes.
Pass diff flags to diff engine, so that combined diff behaves as normal
diff does with spaces.
Also coalesce lines that are removed from both (or more) parents.
It also means that 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 apeli...@gmail.com
---
Changes:
- Fixed comments
- Fixed tests (following Johannes suggestions)
combine-diff.c | 57 +---
t/t4038-diff-combined.sh | 111 ++
2 files changed, 161 insertions(+), 7 deletions(-)
diff --git a/combine-diff.c b/combine-diff.c
index 35d41cd..6288485 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -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
@@ -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 = (1ULn);
@@ -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;
@@ -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)
@@ -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;
@@ -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);
@@ -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,