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 8211780ca..fce1f1a58 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -487,9 +487,12 @@ public class ResolveMerger extends ThreeWayMerger { // Check worktree before modifying files if (isWorktreeDirty()) return false; - if (!contentMerge(base, ours, theirs)) { + + MergeResult result = contentMerge(base, ours, theirs); + File of = writeMergedFile(result); + updateIndex(base, ours, theirs, result, of); + if (result.containsConflicts()) unmergedPaths.add(tw.getPathString()); - } modifiedFiles.add(tw.getPathString()); } else if (modeO != modeT) { // OURS or THEIRS has been deleted @@ -515,21 +518,38 @@ public class ResolveMerger extends ThreeWayMerger { unmergedPaths.add(tw.getPathString()); // generate a MergeResult for the deleted file - RawText baseText = base == null ? RawText.EMPTY_TEXT - : getRawText(base.getEntryObjectId(), db); - RawText ourText = ours == null ? RawText.EMPTY_TEXT - : getRawText(ours.getEntryObjectId(), db); - RawText theirsText = theirs == null ? RawText.EMPTY_TEXT - : getRawText(theirs.getEntryObjectId(), db); - MergeResult result = mergeAlgorithm.merge( - RawTextComparator.DEFAULT, baseText, ourText, - theirsText); - mergeResults.put(tw.getPathString(), result); + mergeResults.put(tw.getPathString(), + contentMerge(base, ours, theirs)); } } return true; } + /** + * Does the content merge. The three texts base, ours and theirs are + * specified with {@link CanonicalTreeParser}. If any of the parsers is + * specified as null then an empty text will be used instead. + * + * @param base + * @param ours + * @param theirs + * + * @return the result of the content merge + * @throws IOException + */ + private MergeResult contentMerge(CanonicalTreeParser base, + CanonicalTreeParser ours, CanonicalTreeParser theirs) + throws IOException { + RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText( + base.getEntryObjectId(), db); + RawText ourText = ours == null ? RawText.EMPTY_TEXT : getRawText( + ours.getEntryObjectId(), db); + RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText( + theirs.getEntryObjectId(), db); + return (mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText, + ourText, theirsText)); + } + private boolean isIndexDirty() { final int modeI = tw.getRawMode(T_INDEX); final int modeO = tw.getRawMode(T_OURS); @@ -559,20 +579,70 @@ public class ResolveMerger extends ThreeWayMerger { return isDirty; } - private boolean contentMerge(CanonicalTreeParser base, - CanonicalTreeParser ours, CanonicalTreeParser theirs) - throws FileNotFoundException, IllegalStateException, IOException { - MergeFormatter fmt = new MergeFormatter(); - - RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText( - base.getEntryObjectId(), db); - - // do the merge - MergeResult result = mergeAlgorithm.merge( - RawTextComparator.DEFAULT, baseText, - getRawText(ours.getEntryObjectId(), db), - getRawText(theirs.getEntryObjectId(), db)); + /** + * Updates the index after a content merge has happened. If no conflict has + * occurred this includes persisting the merged content to the object + * database. In case of conflicts this method takes care to write the + * correct stages to the index. + * + * @param base + * @param ours + * @param theirs + * @param result + * @param of + * @throws FileNotFoundException + * @throws IOException + */ + private void updateIndex(CanonicalTreeParser base, + CanonicalTreeParser ours, CanonicalTreeParser theirs, + MergeResult result, File of) throws FileNotFoundException, + IOException { + 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 + add(tw.getRawPath(), base, DirCacheEntry.STAGE_1); + add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2); + add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3); + 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); + try { + dce.setObjectId(oi.insert(Constants.OBJ_BLOB, of.length(), is)); + } finally { + is.close(); + if (inCore) + FileUtils.delete(of); + } + 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 + * + * @param result + * the result of the content merge + * @return the 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) { @@ -603,40 +673,7 @@ public class ResolveMerger extends ThreeWayMerger { fos.close(); } } - - 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 - add(tw.getRawPath(), base, DirCacheEntry.STAGE_1); - add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2); - add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3); - mergeResults.put(tw.getPathString(), result); - return false; - } 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); - try { - dce.setObjectId(oi.insert(Constants.OBJ_BLOB, of.length(), - is)); - } finally { - is.close(); - if (inCore) - FileUtils.delete(of); - } - builder.add(dce); - return true; - } + return of; } /**