I've found what really looks to be a buggy edge case with the automatic merge feature of 1.8.X which can occur if: * a partial (reintegrate-like) merge into a sparse working copy is committed * and then immediately followed by merging the same branch again into a full working copy.
By a partial merge I specifically mean that the sparse working copy was missing a target of the merge. Here is a diagram of the branching in question: 3-X4------6-+---+ ^/branch/some_feature / / & \ 1-2-+------Y5-+-----7---8 ^/trunk (Obviously the ampersand indicates the partial merge due to sparse WC. Also two commits are showing a name along with a revision number). With that particular pattern I see two anomalies that do not occur if the order of commits X and Y are reversed: 3----X5---6-+---+ ^/branch/some_feature / / & \ 1-2-+---Y4----+-----7---8 ^/trunk As for what I see, if the commented-out line in the script below is left commented-out, then I get what appears to be a bogus tree conflict during the merge to create r8. If you uncomment the line, the merge occurs perfectly with no conflicts, except that something weird happens with the mergeinfo. I'll describe that in more detail below the script. Since commits 4 and 5 are in parallel branches, the order of them really should not make a difference, which is why I'm pretty sure this is a bug. --START OF SCRIPT-- #!/bin/sh #1: svnadmin create repo url=file://`pwd`/repo svn mkdir $url/B1 ^/trunk ^/branch -m "create structure" svn co $url/trunk wc cd wc #2: mkdir A #echo 1 >B.txt echo 1 >C.txt echo 1 > A/D.txt svn add * svn ci -m "Simulate some development" #3: svn cp ^/trunk ^/branch/some_feature -m "Create feature branch" #X: svn sw ^/branch/some_feature echo 2 >> A/D.txt echo 2 >> B.txt sed -i '1i 0' C.txt #prepend a 0 line svn add --force B.txt svn ci -m "Simulate some development on the branch". #Y: svn sw ^/trunk echo 2 >> C.txt sed -i '1i 0' C.txt #prepend a 0 line svn ci -m "Simulate concurrent trunk changes". #6: svn sw ^/branch/some_feature svn merge ^/trunk svn ci -m "Sync Trunk to branch" #7: #set up a sparse trunk checkout svn sw ^/trunk svn up --set-depth exclude A #merge into the sparse trunk checkout svn merge ^/branch/some_feature svn ci -m "Partial merge due to sparse checkout" #r7 #8: #create clean full checkout rm -r * svn revert -R . svn up --set-depth infinity #re-merge svn merge ^/branch/some_feature svn ci -m "Re-Merge" --END SCRIPT-- Now with the line B uncommented everything works as expected, without any attempt to double merge the changes from either the trunk or branch, which further supports my contention that the tree conflict is bogus. But for the mergeinfo issue I mentioned, look closely at the output from the last merge: $ svn merge ^/branch/some_feature --- Merging differences between repository URLs into '.': U A/C.txt --- Recording mergeinfo for merge between repository URLs into '.': --- Eliding mergeinfo from 'A': U A --- Eliding mergeinfo from 'A': U A U . U A Notice that the properties of the directory named A got changed 3 different times. Lets look at the mergeinfo for revision 7: $ svn pg svn:mergeinfo ^/trunk@7 /branch/some_feature:3-6* $ svn pg svn:mergeinfo ^/trunk/A@7 $ svn pg svn:mergeinfo ^/trunk/A/D.txt@7 $ svn pg svn:mergeinfo ^/trunk/B.txt@7 /branch/some_feature/B.txt:3-6 $ svn pg svn:mergeinfo ^/trunk/C.txt@7 /branch/some_feature/B.txt:3-6 That is obviously correct. The mergeinfo must be non-inheriting because A was not merged, and it must be duplicated onto B.txt and C.txt because they were merged. Now lets look at what happened with revision 8: $ svn pg svn:mergeinfo ^/trunk@8 /branch/some_feature:3-7 $ svn pg svn:mergeinfo ^/trunk/A@8 /branch/some_feature/A:3-7 $ svn pg svn:mergeinfo ^/trunk/A/D.txt@8 $ svn pg svn:mergeinfo ^/trunk/B.txt@8 /branch/some_feature/B.txt:3-6 $ svn pg svn:mergeinfo ^/trunk/C.txt@8 /branch/some_feature/C.txt:3-6 Ok, so it did the right thing with the trunk, but why on earth did it add explicit mergeinfo to ^/trunk/A? According to the output I quoted earlier in this message, it tried to elide that mergeinfo twice. It gets worse. The only reason that things work if you reverse the order of commit X and Y is due to what looks like another bug. SVN gets confused as to the direction of the last full merge which was in fact from trunk to branch. This causes it to run a sync-like merge on what happens to be precisely the correct commits to avoid double merging changes that originated on the trunk. To support that assertion: Try swapping the order of the X and Y chunks in the script, and commenting out the last merge and commit. Now in the working copy: $ svn mergeinfo ^/branch/some_feature youngest common ancestor | last full merge | | tip of branch | | | repository path 2 4 7 | | | --| |------------ branch/some_feature / \ / \ -------| |------------ trunk | WC Hmm.. If X and Y are reversed then Y is commit number 4. Commit Y is a commit on the trunk, that was merged into the branch. That diagram has the merge backwards! Let me paste the diagram for commit Y before X again for reference: 3----X5---6-+---+ ^/branch/some_feature / / & \ 1-2-+---Y4----+-----7---8 ^/trunk Ok. Try running the merge anyway: $ svn merge ^/branch/some_feature --- Merging r5 through r6 into 'A': U A/D.txt --- Recording mergeinfo for merge of r3 through r7 into '.': U . --- Recording mergeinfo for merge of r3 through r7 into 'A': G A --- Eliding mergeinfo from 'A': U A Notice how it references specific revision numbers? That only happens in a sync-like merge. What s going on here? Am I fundamentally misunderstanding something or are these really bugs? Note: The above was tested with 1.8.8, 1.8.9 (prior to announcement), and build of trunk from May 13 2014.