Jeff King [off-list ref] writes:
No, I think it's right as-is. We forget about the blocks during the
recovery section of the code. IOW, we just keep reading forward until we
find all of the context lines, or we run out of trimmed content. In the
first case, we are fine (we restored the right number of context lines).
In the latter case, we are also fine, because we end up trimming nothing
(IOW, there _weren't_ enough context lines in the first place).
Kind'a embarrassing that both of us cannot get this right without so
many rounds, isn't it?
-- >8 --
Subject: [PATCH] Re-re-re-fix common tail optimization
We need to be extra careful recovering the removed common section, so
that we do not break context nor the changed incomplete line (i.e. the
last line that does not end with LF).
Signed-off-by: Junio C Hamano <redacted>
---
t/t4024-diff-optimize-common.sh | 69 +++++++++++++++++++++++++++++++++++++++
xdiff-interface.c | 2 +-
2 files changed, 70 insertions(+), 1 deletions(-)
diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh
new file mode 100755
index 0000000..10405f1
--- /dev/null
+++ b/t/t4024-diff-optimize-common.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+test_description='common tail optimization'
+
+. ./test-lib.sh
+
+z=zzzzzzzz ;# 8
+z="$z$z$z$z$z$z$z$z" ;# 64
+z="$z$z$z$z$z$z$z$z" ;# 512
+z="$z$z$z$z" ;# 2048
+z2047=$(expr "$z" : '.\(.*\)') ; #2047
+
+test_expect_success setup '
+
+ echo "a$z2047" >file-a &&
+ echo "b" >file-b &&
+ echo "$z2047" >>file-b &&
+ echo "c$z2047" | tr -d "\012" >file-c &&
+ echo "d" >file-d &&
+ echo "$z2047" | tr -d "\012" >>file-d &&
+
+ git add file-a file-b file-c file-d &&
+
+ echo "A$z2047" >file-a &&
+ echo "B" >file-b &&
+ echo "$z2047" >>file-b &&
+ echo "C$z2047" | tr -d "\012" >file-c &&
+ echo "D" >file-d &&
+ echo "$z2047" | tr -d "\012" >>file-d
+
+'
+
+echo >expect <<\EOF
+diff --git a/file-a b/file-a
+--- a/file-a
++++ b/file-a
+@@ -1 +1 @@
+-aZ
++AZ
+diff --git a/file-b b/file-b
+--- a/file-b
++++ b/file-b
+@@ -1 +1 @@
+-b
++B
+diff --git a/file-c b/file-c
+--- a/file-c
++++ b/file-c
+@@ -1 +1 @@
+-cZ
+\ No newline at end of file
++CZ
+\ No newline at end of file
+diff --git a/file-d b/file-d
+--- a/file-d
++++ b/file-d
+@@ -1 +1 @@
+-d
++D
+EOF
+
+test_expect_success 'diff -U0' '
+
+ git diff -U0 | sed -e "/^index/d" -e "s/$z2047/Z/g" >actual &&
+ diff -u expect actual
+
+'
+
+test_done
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 98b02ed..9ee877c 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -121,7 +121,7 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx)
bp -= blk;
}
- while (recovered < trimmed && ctx)
+ while (recovered < trimmed && 0 <= ctx)
if (ap[recovered++] == '\n')
ctx--;
a->size -= (trimmed - recovered);