Browse Source

Refactor ResolveMerger

The places where ResolveMerger was doing content merges have been
refactored. The goal was to have one single method where content merge
was done and to factor out other topics (updating the index, updating
the working tree) into own methods. This was done to allow adding
pluggable content mergers in change
I7817e2123d254f3eeb315b47a61d2c55bd202c12

Change-Id: I8529697b197372a284bcd5ab2c9ba1adb925a520
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
stable-1.3
Christian Halstrick 13 years ago
parent
commit
200d3f5aaf
  1. 155
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

155
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

@ -487,9 +487,12 @@ public class ResolveMerger extends ThreeWayMerger {
// Check worktree before modifying files // Check worktree before modifying files
if (isWorktreeDirty()) if (isWorktreeDirty())
return false; return false;
if (!contentMerge(base, ours, theirs)) {
MergeResult<RawText> result = contentMerge(base, ours, theirs);
File of = writeMergedFile(result);
updateIndex(base, ours, theirs, result, of);
if (result.containsConflicts())
unmergedPaths.add(tw.getPathString()); unmergedPaths.add(tw.getPathString());
}
modifiedFiles.add(tw.getPathString()); modifiedFiles.add(tw.getPathString());
} else if (modeO != modeT) { } else if (modeO != modeT) {
// OURS or THEIRS has been deleted // OURS or THEIRS has been deleted
@ -515,21 +518,38 @@ public class ResolveMerger extends ThreeWayMerger {
unmergedPaths.add(tw.getPathString()); unmergedPaths.add(tw.getPathString());
// generate a MergeResult for the deleted file // generate a MergeResult for the deleted file
RawText baseText = base == null ? RawText.EMPTY_TEXT mergeResults.put(tw.getPathString(),
: getRawText(base.getEntryObjectId(), db); contentMerge(base, ours, theirs));
RawText ourText = ours == null ? RawText.EMPTY_TEXT
: getRawText(ours.getEntryObjectId(), db);
RawText theirsText = theirs == null ? RawText.EMPTY_TEXT
: getRawText(theirs.getEntryObjectId(), db);
MergeResult<RawText> result = mergeAlgorithm.merge(
RawTextComparator.DEFAULT, baseText, ourText,
theirsText);
mergeResults.put(tw.getPathString(), result);
} }
} }
return true; 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 <code>null</code> 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<RawText> 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() { private boolean isIndexDirty() {
final int modeI = tw.getRawMode(T_INDEX); final int modeI = tw.getRawMode(T_INDEX);
final int modeO = tw.getRawMode(T_OURS); final int modeO = tw.getRawMode(T_OURS);
@ -559,20 +579,70 @@ public class ResolveMerger extends ThreeWayMerger {
return isDirty; return isDirty;
} }
private boolean contentMerge(CanonicalTreeParser base, /**
CanonicalTreeParser ours, CanonicalTreeParser theirs) * Updates the index after a content merge has happened. If no conflict has
throws FileNotFoundException, IllegalStateException, IOException { * occurred this includes persisting the merged content to the object
MergeFormatter fmt = new MergeFormatter(); * database. In case of conflicts this method takes care to write the
* correct stages to the index.
RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText( *
base.getEntryObjectId(), db); * @param base
* @param ours
// do the merge * @param theirs
MergeResult<RawText> result = mergeAlgorithm.merge( * @param result
RawTextComparator.DEFAULT, baseText, * @param of
getRawText(ours.getEntryObjectId(), db), * @throws FileNotFoundException
getRawText(theirs.getEntryObjectId(), db)); * @throws IOException
*/
private void updateIndex(CanonicalTreeParser base,
CanonicalTreeParser ours, CanonicalTreeParser theirs,
MergeResult<RawText> 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<RawText> result)
throws FileNotFoundException, IOException {
MergeFormatter fmt = new MergeFormatter();
File of = null; File of = null;
FileOutputStream fos; FileOutputStream fos;
if (!inCore) { if (!inCore) {
@ -603,40 +673,7 @@ public class ResolveMerger extends ThreeWayMerger {
fos.close(); fos.close();
} }
} }
return of;
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;
}
} }
/** /**

Loading…
Cancel
Save