Re: Bugs? with "automatic" merge and sparse working copies

2014-05-22 Thread Kevin Cathcart
On May 22, 2014 7:02 AM, Stefan Sperling wrote:
> Hi Kevin,
>
> I didn't get a response from you so I've filed an issue:
> http://subversion.tigris.org/issues/show_bug.cgi?id=4506

Sorry for not responding. I've been a bit busy and had not gotten back to
this. Thanks for filling the issue for me.

Kevin Cathcart


Bugs? with "automatic" merge and sparse working copies

2014-05-16 Thread Kevin Cathcart
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:

3X5---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 '.':
UA/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 47
| |