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>
tags/v1.3.0.201202121842-rc4
Christian Halstrick 12 years ago
parent
commit
200d3f5aaf
1 changed files with 96 additions and 59 deletions
  1. 96
    59
      org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

+ 96
- 59
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java View File

@@ -487,9 +487,12 @@ public class ResolveMerger extends ThreeWayMerger {
// Check worktree before modifying files
if (isWorktreeDirty())
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());
}
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<RawText> 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 <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() {
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<RawText> 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<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;
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;
}

/**

Loading…
Cancel
Save