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 <thomas.wolf@paranor.ch>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Thomas Wolf 2018-02-01 21:58:23 +01:00 committed by Matthias Sohn
parent 4e0e1b4e86
commit fc7d407d0b
4 changed files with 71 additions and 13 deletions

View File

@ -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());
}
}

View File

@ -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.

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit" version="2">
<resource path="src/org/eclipse/jgit/merge/ResolveMerger.java" type="org.eclipse.jgit.merge.ResolveMerger">
<filter id="336658481">
<message_arguments>
<message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
<message_argument value="workingTreeOptions"/>
</message_arguments>
</filter>
</resource>
</component>

View File

@ -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<RawText> 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);
}