From fc7d407d0bd056534f2407d8532cc035617b08d6 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Thu, 1 Feb 2018 21:58:23 +0100 Subject: [PATCH] Honor CRLF settings when writing merge results Merges are performed using the raw text as stored in the git repository. When we write the merge result, we must apply the correct CRLF settings. Otherwise the line endings in the result will be wrong. Bug: 499615 Change-Id: I37a9b987e9404c97645d2720cd1c7c04c076a96b Signed-off-by: Thomas Wolf Signed-off-by: Matthias Sohn --- .../jgit/junit/RepositoryTestCase.java | 16 +++++----- .../eclipse/jgit/merge/ResolveMergerTest.java | 29 +++++++++++++++++++ org.eclipse.jgit/.settings/.api_filters | 11 +++++++ .../org/eclipse/jgit/merge/ResolveMerger.java | 28 ++++++++++++++---- 4 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 org.eclipse.jgit/.settings/.api_filters diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java index 044f08072..8f44620b8 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java @@ -197,14 +197,14 @@ protected void deleteTrashFile(final String name) throws IOException { */ protected static void checkFile(File f, final String checkData) throws IOException { - Reader r = new InputStreamReader(new FileInputStream(f), "UTF-8"); - try { - char[] data = new char[checkData.length()]; - if (checkData.length() != r.read(data)) - throw new IOException("Internal error reading file data from "+f); - assertEquals(checkData, new String(data)); - } finally { - r.close(); + try (Reader r = new InputStreamReader(new FileInputStream(f), + "UTF-8")) { + if (checkData.length() > 0) { + char[] data = new char[checkData.length()]; + assertEquals(data.length, r.read(data)); + assertEquals(checkData, new String(data)); + } + assertEquals(-1, r.read()); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java index 3272d598b..a88efd175 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java @@ -387,6 +387,35 @@ public void mergeWithCrlfInWT(MergeStrategy strategy) throws IOException, mergeResult.getMergeStatus()); } + @Theory + public void mergeWithCrlfAutoCrlfTrue(MergeStrategy strategy) + throws IOException, GitAPIException { + Git git = Git.wrap(db); + db.getConfig().setString("core", null, "autocrlf", "true"); + db.getConfig().save(); + writeTrashFile("crlf.txt", "a crlf file\r\n"); + git.add().addFilepattern("crlf.txt").call(); + git.commit().setMessage("base").call(); + + git.branchCreate().setName("brancha").call(); + + writeTrashFile("crlf.txt", "a crlf file\r\na second line\r\n"); + git.add().addFilepattern("crlf.txt").call(); + git.commit().setMessage("on master").call(); + + git.checkout().setName("brancha").call(); + File testFile = writeTrashFile("crlf.txt", + "a first line\r\na crlf file\r\n"); + git.add().addFilepattern("crlf.txt").call(); + git.commit().setMessage("on brancha").call(); + + MergeResult mergeResult = git.merge().setStrategy(strategy) + .include(db.resolve("master")).call(); + assertEquals(MergeResult.MergeStatus.MERGED, + mergeResult.getMergeStatus()); + checkFile(testFile, "a first line\r\na crlf file\r\na second line\r\n"); + } + /** * Merging two equal subtrees when the index does not contain any file in * that subtree should lead to a merged state. diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters new file mode 100644 index 000000000..293c60bb0 --- /dev/null +++ b/org.eclipse.jgit/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index 5646529dd..b40c19278 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -87,6 +87,7 @@ import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; @@ -99,10 +100,13 @@ import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.NameConflictTreeWalk; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.TreeWalk.OperationType; import org.eclipse.jgit.treewalk.WorkingTreeIterator; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.TemporaryBuffer; +import org.eclipse.jgit.util.io.EolStreamTypeUtil; /** * A three-way merger performing a content-merge if necessary @@ -277,8 +281,16 @@ public enum MergeFailureReason { protected MergeAlgorithm mergeAlgorithm; /** - * The size limit (bytes) which controls a file to be stored in {@code Heap} or - * {@code LocalFile} during the merge. + * The {@link WorkingTreeOptions} are needed to determine line endings for + * merged files. + * + * @since 4.11 + */ + protected WorkingTreeOptions workingTreeOptions; + + /** + * The size limit (bytes) which controls a file to be stored in {@code Heap} + * or {@code LocalFile} during the merge. */ private int inCoreLimit; @@ -319,6 +331,7 @@ protected ResolveMerger(Repository local, boolean inCore) { dircache = DirCache.newInCore(); } else { implicitDirCache = true; + workingTreeOptions = local.getConfig().get(WorkingTreeOptions.KEY); } } @@ -916,10 +929,15 @@ private File writeMergedFile(MergeResult result) FS fs = nonNullRepo().getFS(); File of = new File(workTree, tw.getPathString()); File parentFolder = of.getParentFile(); - if (!fs.exists(parentFolder)) + if (!fs.exists(parentFolder)) { parentFolder.mkdirs(); - try (OutputStream os = new BufferedOutputStream( - new FileOutputStream(of))) { + } + EolStreamType streamType = EolStreamTypeUtil.detectStreamType( + OperationType.CHECKOUT_OP, workingTreeOptions, + tw.getAttributes()); + try (OutputStream os = EolStreamTypeUtil.wrapOutputStream( + new BufferedOutputStream(new FileOutputStream(of)), + streamType)) { new MergeFormatter().formatMerge(os, result, Arrays.asList(commitNames), CHARACTER_ENCODING); }