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