From 2a0295ccfd1cf8dcb1067575f38c86f430285cda Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Wed, 10 Mar 2021 18:04:25 +0100 Subject: [PATCH] ApplyCommand: handle completely empty context lines in text patches C git treats completely empty lines as empty context lines (which traditionally have a single blank). Apparently newer GNU diff may produce such lines; see [1]. ("Newer" meaning "since 2006"...) [1] https://github.com/git/git/commit/b507b465f7831 Change-Id: I80c1f030edb17a46289b1dabf11a2648d2660d38 Signed-off-by: Thomas Wolf --- .../org/eclipse/jgit/diff/emptyLine.patch | Bin 0 -> 134 bytes .../org/eclipse/jgit/diff/emptyLine_PostImage | Bin 0 -> 13 bytes .../org/eclipse/jgit/diff/emptyLine_PreImage | Bin 0 -> 13 bytes .../org/eclipse/jgit/api/ApplyCommandTest.java | 8 ++++++++ .../src/org/eclipse/jgit/api/ApplyCommand.java | 16 ++++++++++++++-- 5 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine.patch create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PostImage create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PreImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine.patch new file mode 100644 index 0000000000000000000000000000000000000000..18c80c4feb7b01d874e59d5fa7419798978da2df GIT binary patch literal 134 zcmY+5I}U>|3_y3E!ng6WS literal 0 HcmV?d00001 diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PostImage new file mode 100644 index 0000000000000000000000000000000000000000..45c2c9ba5bdb50a19c59911e40e6463d6e14dff2 GIT binary patch literal 13 UcmYex&*$PwN-W|^E6wEs032ci>Hq)$ literal 0 HcmV?d00001 diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PreImage new file mode 100644 index 0000000000000000000000000000000000000000..1fd3fa23b0597045ca6507f6059fce4778e7f5e9 GIT binary patch literal 13 UcmYex&*$Pw%S`1;E6wEs032)s=>Px# literal 0 HcmV?d00001 diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java index b997ac009..807b96130 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java @@ -295,6 +295,14 @@ public void testEncodingChange() throws Exception { checkBinary("umlaut", true); } + @Test + public void testEmptyLine() throws Exception { + // C git accepts completely empty lines as empty context lines. + // According to comments in the C git sources (apply.c), newer GNU diff + // may produce such diffs. + checkBinary("emptyLine", true); + } + @Test public void testAddA1() throws Exception { ApplyResult result = init("A1", false, true); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java index ec53412fc..f649c5fde 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java @@ -640,6 +640,11 @@ && canApplyAt(hunkLines, newLines, 0)) { int sz = hunkLines.size(); for (int j = 1; j < sz; j++) { ByteBuffer hunkLine = hunkLines.get(j); + if (!hunkLine.hasRemaining()) { + // Completely empty line; accept as empty context line + applyAt++; + continue; + } switch (hunkLine.array()[hunkLine.position()]) { case ' ': applyAt++; @@ -676,8 +681,7 @@ && canApplyAt(hunkLines, newLines, 0)) { // Must be the marker for the final newline break; } - out.write(line.array(), line.position(), - line.limit() - line.position()); + out.write(line.array(), line.position(), line.remaining()); if (l.hasNext()) { out.write('\n'); } @@ -703,6 +707,14 @@ private boolean canApplyAt(List hunkLines, int pos = line; for (int j = 1; j < sz; j++) { ByteBuffer hunkLine = hunkLines.get(j); + if (!hunkLine.hasRemaining()) { + // Empty line. Accept as empty context line. + if (pos >= limit || newLines.get(pos).hasRemaining()) { + return false; + } + pos++; + continue; + } switch (hunkLine.array()[hunkLine.position()]) { case ' ': case '-':