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 d18e31aef..f8ad490c7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -44,6 +44,9 @@ */ package org.eclipse.jgit.merge; +import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -76,7 +79,6 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.ConfigConstants; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; @@ -89,6 +91,7 @@ import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.TemporaryBuffer; /** * A three-way merger performing a content-merge if necessary @@ -756,90 +759,92 @@ public class ResolveMerger extends ThreeWayMerger { CanonicalTreeParser ours, CanonicalTreeParser theirs, MergeResult result) throws FileNotFoundException, IOException { - File of = writeMergedFile(result); + File mergedFile = !inCore ? writeMergedFile(result) : null; if (result.containsConflicts()) { - // a conflict occurred, the file will contain conflict markers - // the index will be populated with the three stages and only the - // workdir (if used) contains the halfways merged content + // A conflict occurred, the file will contain conflict markers + // the index will be populated with the three stages and the + // workdir (if used) contains the halfway merged content. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0); add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0); add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0); mergeResults.put(tw.getPathString(), result); - } else { - // no conflict occurred, the file will contain fully merged content. - // the index will be populated with the new merged version - DirCacheEntry dce = new DirCacheEntry(tw.getPathString()); - int newMode = mergeFileModes(tw.getRawMode(0), tw.getRawMode(1), - tw.getRawMode(2)); - // set the mode for the new content. Fall back to REGULAR_FILE if - // you can't merge modes of OURS and THEIRS - dce.setFileMode((newMode == FileMode.MISSING.getBits()) ? FileMode.REGULAR_FILE - : FileMode.fromBits(newMode)); - dce.setLastModified(of.lastModified()); - dce.setLength((int) of.length()); - InputStream is = new FileInputStream(of); + return; + } + + // No conflict occurred, the file will contain fully merged content. + // The index will be populated with the new merged version. + DirCacheEntry dce = new DirCacheEntry(tw.getPathString()); + + // Set the mode for the new content. Fall back to REGULAR_FILE if + // we can't merge modes of OURS and THEIRS. + int newMode = mergeFileModes( + tw.getRawMode(0), + tw.getRawMode(1), + tw.getRawMode(2)); + dce.setFileMode(newMode == FileMode.MISSING.getBits() + ? FileMode.REGULAR_FILE + : FileMode.fromBits(newMode)); + if (mergedFile != null) { + long len = mergedFile.length(); + dce.setLastModified(mergedFile.lastModified()); + dce.setLength((int) len); + InputStream is = new FileInputStream(mergedFile); try { - dce.setObjectId(getObjectInserter().insert( - Constants.OBJ_BLOB, of.length(), is)); + dce.setObjectId(getObjectInserter().insert(OBJ_BLOB, len, is)); } finally { is.close(); - if (inCore) - FileUtils.delete(of); } - builder.add(dce); - } + } else + dce.setObjectId(insertMergeResult(result)); + builder.add(dce); } /** - * Writes merged file content to the working tree. In case {@link #inCore} - * is set and we don't have a working tree the content is written to a - * temporary file + * Writes merged file content to the working tree. * * @param result * the result of the content merge - * @return the file to which the merged content was written + * @return the working tree file to which the merged content was written. * @throws FileNotFoundException * @throws IOException */ private File writeMergedFile(MergeResult result) throws FileNotFoundException, IOException { - MergeFormatter fmt = new MergeFormatter(); - File of = null; - FileOutputStream fos; - if (!inCore) { - File workTree = db.getWorkTree(); - if (workTree == null) - // TODO: This should be handled by WorkingTreeIterators which - // support write operations - throw new UnsupportedOperationException(); - - FS fs = db.getFS(); - of = new File(workTree, tw.getPathString()); - File parentFolder = of.getParentFile(); - if (!fs.exists(parentFolder)) - parentFolder.mkdirs(); - fos = new FileOutputStream(of); - try { - fmt.formatMerge(fos, result, Arrays.asList(commitNames), - Constants.CHARACTER_ENCODING); - } finally { - fos.close(); - } - } else if (!result.containsConflicts()) { - // When working inCore, only trivial merges can be handled, - // so we generate objects only in conflict free cases - of = File.createTempFile("merge_", "_temp", null); //$NON-NLS-1$ //$NON-NLS-2$ - fos = new FileOutputStream(of); - try { - fmt.formatMerge(fos, result, Arrays.asList(commitNames), - Constants.CHARACTER_ENCODING); - } finally { - fos.close(); - } + File workTree = db.getWorkTree(); + if (workTree == null) + // TODO: This should be handled by WorkingTreeIterators which + // support write operations + throw new UnsupportedOperationException(); + + FS fs = db.getFS(); + File of = new File(workTree, tw.getPathString()); + File parentFolder = of.getParentFile(); + if (!fs.exists(parentFolder)) + parentFolder.mkdirs(); + FileOutputStream fos = new FileOutputStream(of); + try { + new MergeFormatter().formatMerge(fos, result, + Arrays.asList(commitNames), CHARACTER_ENCODING); + } finally { + fos.close(); } return of; } + private ObjectId insertMergeResult(MergeResult result) + throws IOException { + TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(10 << 20); + try { + new MergeFormatter().formatMerge(buf, result, + Arrays.asList(commitNames), CHARACTER_ENCODING); + buf.close(); + return getObjectInserter().insert(OBJ_BLOB, buf.length(), + buf.openInputStream()); + } finally { + buf.destroy(); + } + } + /** * Try to merge filemodes. If only ours or theirs have changed the mode * (compared to base) we choose that one. If ours and theirs have equal @@ -872,7 +877,7 @@ public class ResolveMerger extends ThreeWayMerger { throws IOException { if (id.equals(ObjectId.zeroId())) return new RawText(new byte[] {}); - return new RawText(db.open(id, Constants.OBJ_BLOB).getCachedBytes()); + return new RawText(db.open(id, OBJ_BLOB).getCachedBytes()); } private static boolean nonTree(final int mode) {