@ -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 ;
}
/ * *