@ -204,6 +204,13 @@ public class ResolveMerger extends ThreeWayMerger {
}
}
if ( ! inCore ) {
if ( ! inCore ) {
// No problem found. The only thing left to be done is to
// checkout
// all files from "theirs" which have been selected to go into
// the
// new index.
checkout ( ) ;
// All content-merges are successfully done. If we can now write the
// All content-merges are successfully done. If we can now write the
// new index we are on quite safe ground. Even if the checkout of
// new index we are on quite safe ground. Even if the checkout of
// files coming from "theirs" fails the user can work around such
// files coming from "theirs" fails the user can work around such
@ -214,10 +221,6 @@ public class ResolveMerger extends ThreeWayMerger {
}
}
builder = null ;
builder = null ;
// No problem found. The only thing left to be done is to checkout
// all files from "theirs" which have been selected to go into the
// new index.
checkout ( ) ;
} else {
} else {
builder . finish ( ) ;
builder . finish ( ) ;
builder = null ;
builder = null ;
@ -313,19 +316,43 @@ public class ResolveMerger extends ThreeWayMerger {
* @param path
* @param path
* @param p
* @param p
* @param stage
* @param stage
* @param lastMod
* @param len
* @return the entry which was added to the index
* @return the entry which was added to the index
* /
* /
private DirCacheEntry add ( byte [ ] path , CanonicalTreeParser p , int stage ) {
private DirCacheEntry add ( byte [ ] path , CanonicalTreeParser p , int stage ,
long lastMod , long len ) {
if ( p ! = null & & ! p . getEntryFileMode ( ) . equals ( FileMode . TREE ) ) {
if ( p ! = null & & ! p . getEntryFileMode ( ) . equals ( FileMode . TREE ) ) {
DirCacheEntry e = new DirCacheEntry ( path , stage ) ;
DirCacheEntry e = new DirCacheEntry ( path , stage ) ;
e . setFileMode ( p . getEntryFileMode ( ) ) ;
e . setFileMode ( p . getEntryFileMode ( ) ) ;
e . setObjectId ( p . getEntryObjectId ( ) ) ;
e . setObjectId ( p . getEntryObjectId ( ) ) ;
e . setLastModified ( lastMod ) ;
e . setLength ( len ) ;
builder . add ( e ) ;
builder . add ( e ) ;
return e ;
return e ;
}
}
return null ;
return null ;
}
}
/ * *
* adds a entry to the index builder which is a copy of the specified
* DirCacheEntry
*
* @param e
* the entry which should be copied
*
* @return the entry which was added to the index
* /
private DirCacheEntry keep ( DirCacheEntry e ) {
DirCacheEntry newEntry = new DirCacheEntry ( e . getPathString ( ) , e . getStage ( ) ) ;
newEntry . setFileMode ( e . getFileMode ( ) ) ;
newEntry . setObjectId ( e . getObjectId ( ) ) ;
newEntry . setLastModified ( e . getLastModified ( ) ) ;
newEntry . setLength ( e . getLength ( ) ) ;
builder . add ( newEntry ) ;
return newEntry ;
}
/ * *
/ * *
* Processes one path and tries to merge . This method will do all do all
* Processes one path and tries to merge . This method will do all do all
* trivial ( not content ) merges and will also detect if a merge will fail .
* trivial ( not content ) merges and will also detect if a merge will fail .
@ -382,12 +409,27 @@ public class ResolveMerger extends ThreeWayMerger {
if ( isIndexDirty ( ) )
if ( isIndexDirty ( ) )
return false ;
return false ;
DirCacheEntry ourDce = null ;
if ( index = = null ) {
// create a fake DCE, but only if ours is valid. ours is kept only
// in case it is valid, so a null ourDce is ok in all other cases.
if ( modeO ! = 0 ) {
ourDce = new DirCacheEntry ( tw . getRawPath ( ) ) ;
ourDce . setObjectId ( tw . getObjectId ( T_OURS ) ) ;
ourDce . setFileMode ( tw . getFileMode ( T_OURS ) ) ;
}
} else {
ourDce = index . getDirCacheEntry ( ) ;
}
if ( nonTree ( modeO ) & & nonTree ( modeT ) & & tw . idEqual ( T_OURS , T_THEIRS ) ) {
if ( nonTree ( modeO ) & & nonTree ( modeT ) & & tw . idEqual ( T_OURS , T_THEIRS ) ) {
// OURS and THEIRS have equal content. Check the file mode
// OURS and THEIRS have equal content. Check the file mode
if ( modeO = = modeT ) {
if ( modeO = = modeT ) {
// content and mode of OURS and THEIRS are equal: it doesn't
// content and mode of OURS and THEIRS are equal: it doesn't
// matter which one we choose. OURS is chosen.
// matter which one we choose. OURS is chosen. Since the index
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_0 ) ;
// is clean (the index matches already OURS) we can keep the existing one
keep ( ourDce ) ;
// no checkout needed!
// no checkout needed!
return true ;
return true ;
} else {
} else {
@ -398,22 +440,25 @@ public class ResolveMerger extends ThreeWayMerger {
if ( newMode ! = FileMode . MISSING . getBits ( ) ) {
if ( newMode ! = FileMode . MISSING . getBits ( ) ) {
if ( newMode = = modeO )
if ( newMode = = modeO )
// ours version is preferred
// ours version is preferred
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_0 ) ;
keep ( ourDce ) ;
else {
else {
// the preferred version THEIRS has a different mode
// the preferred version THEIRS has a different mode
// than ours. Check it out!
// than ours. Check it out!
if ( isWorktreeDirty ( work ) )
if ( isWorktreeDirty ( work ) )
return false ;
return false ;
// we know about length and lastMod only after we have written the new content.
// This will happen later. Set these values to 0 for know.
DirCacheEntry e = add ( tw . getRawPath ( ) , theirs ,
DirCacheEntry e = add ( tw . getRawPath ( ) , theirs ,
DirCacheEntry . STAGE_0 ) ;
DirCacheEntry . STAGE_0 , 0 , 0 ) ;
toBeCheckedOut . put ( tw . getPathString ( ) , e ) ;
toBeCheckedOut . put ( tw . getPathString ( ) , e ) ;
}
}
return true ;
return true ;
} else {
} else {
// FileModes are not mergeable. We found a conflict on modes
// FileModes are not mergeable. We found a conflict on modes.
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 ) ;
// For conflicting entries we don't know lastModified and length.
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 ) ;
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , theirs , DirCacheEntry . STAGE_3 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , theirs , DirCacheEntry . STAGE_3 , 0 , 0 ) ;
unmergedPaths . add ( tw . getPathString ( ) ) ;
unmergedPaths . add ( tw . getPathString ( ) ) ;
mergeResults . put (
mergeResults . put (
tw . getPathString ( ) ,
tw . getPathString ( ) ,
@ -426,8 +471,8 @@ public class ResolveMerger extends ThreeWayMerger {
if ( nonTree ( modeO ) & & modeB = = modeT & & tw . idEqual ( T_BASE , T_THEIRS ) ) {
if ( nonTree ( modeO ) & & modeB = = modeT & & tw . idEqual ( T_BASE , T_THEIRS ) ) {
// THEIRS was not changed compared to BASE. All changes must be in
// THEIRS was not changed compared to BASE. All changes must be in
// OURS. OURS is chosen.
// OURS. OURS is chosen. We can keep the existing entry.
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_0 ) ;
keep ( ourDce ) ;
// no checkout needed!
// no checkout needed!
return true ;
return true ;
}
}
@ -440,8 +485,11 @@ public class ResolveMerger extends ThreeWayMerger {
if ( isWorktreeDirty ( work ) )
if ( isWorktreeDirty ( work ) )
return false ;
return false ;
if ( nonTree ( modeT ) ) {
if ( nonTree ( modeT ) ) {
// we know about length and lastMod only after we have written
// the new content.
// This will happen later. Set these values to 0 for know.
DirCacheEntry e = add ( tw . getRawPath ( ) , theirs ,
DirCacheEntry e = add ( tw . getRawPath ( ) , theirs ,
DirCacheEntry . STAGE_0 ) ;
DirCacheEntry . STAGE_0 , 0 , 0 ) ;
if ( e ! = null )
if ( e ! = null )
toBeCheckedOut . put ( tw . getPathString ( ) , e ) ;
toBeCheckedOut . put ( tw . getPathString ( ) , e ) ;
return true ;
return true ;
@ -460,16 +508,16 @@ public class ResolveMerger extends ThreeWayMerger {
// detected later
// detected later
if ( nonTree ( modeO ) & & ! nonTree ( modeT ) ) {
if ( nonTree ( modeO ) & & ! nonTree ( modeT ) ) {
if ( nonTree ( modeB ) )
if ( nonTree ( modeB ) )
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 ) ;
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 , 0 , 0 ) ;
unmergedPaths . add ( tw . getPathString ( ) ) ;
unmergedPaths . add ( tw . getPathString ( ) ) ;
enterSubtree = false ;
enterSubtree = false ;
return true ;
return true ;
}
}
if ( nonTree ( modeT ) & & ! nonTree ( modeO ) ) {
if ( nonTree ( modeT ) & & ! nonTree ( modeO ) ) {
if ( nonTree ( modeB ) )
if ( nonTree ( modeB ) )
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 ) ;
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , theirs , DirCacheEntry . STAGE_3 ) ;
add ( tw . getRawPath ( ) , theirs , DirCacheEntry . STAGE_3 , 0 , 0 ) ;
unmergedPaths . add ( tw . getPathString ( ) ) ;
unmergedPaths . add ( tw . getPathString ( ) ) ;
enterSubtree = false ;
enterSubtree = false ;
return true ;
return true ;
@ -502,10 +550,10 @@ public class ResolveMerger extends ThreeWayMerger {
if ( ( ( modeO ! = 0 & & ! tw . idEqual ( T_BASE , T_OURS ) ) | | ( modeT ! = 0 & & ! tw
if ( ( ( modeO ! = 0 & & ! tw . idEqual ( T_BASE , T_OURS ) ) | | ( modeT ! = 0 & & ! tw
. idEqual ( T_BASE , T_THEIRS ) ) ) ) {
. idEqual ( T_BASE , T_THEIRS ) ) ) ) {
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 ) ;
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 , 0 , 0 ) ;
DirCacheEntry e = add ( tw . getRawPath ( ) , theirs ,
DirCacheEntry e = add ( tw . getRawPath ( ) , theirs ,
DirCacheEntry . STAGE_3 ) ;
DirCacheEntry . STAGE_3 , 0 , 0 ) ;
// OURS was deleted checkout THEIRS
// OURS was deleted checkout THEIRS
if ( modeO = = 0 ) {
if ( modeO = = 0 ) {
@ -609,9 +657,9 @@ public class ResolveMerger extends ThreeWayMerger {
// 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 only the
// workdir (if used) contains the halfways merged content
// workdir (if used) contains the halfways merged content
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 ) ;
add ( tw . getRawPath ( ) , base , DirCacheEntry . STAGE_1 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 ) ;
add ( tw . getRawPath ( ) , ours , DirCacheEntry . STAGE_2 , 0 , 0 ) ;
add ( tw . getRawPath ( ) , theirs , DirCacheEntry . STAGE_3 ) ;
add ( tw . getRawPath ( ) , theirs , DirCacheEntry . STAGE_3 , 0 , 0 ) ;
mergeResults . put ( tw . getPathString ( ) , result ) ;
mergeResults . put ( tw . getPathString ( ) , result ) ;
} else {
} else {
// no conflict occurred, the file will contain fully merged content.
// no conflict occurred, the file will contain fully merged content.