On Tue, Oct 16, 2012 at 01:17:40PM +0200, Sven Uhlig wrote: > Below is a .bat file for creating the repo with some more conflicts that > we do not understand. I would be happy if someone could explain these as > well.
Please see my remarks below. > @REM testsvn.bat > > cls > > svn --version > @REM svn, Version 1.7.2 (r1207936) > @pause > svnadmin --version > @REM svnadmin, Version 1.7.2 (r1207936) > @pause > D: > cd \ > mkdir test > cd test > > svnadmin create repo > svn checkout file:///D:/test/repo wc > > cd wc > mkdir branches > mkdir tags > mkdir trunk > svn add branches tags trunk > svn commit -m "basic repo structure" > svn switch --ignore-ancestry file:///D:/test/repo/trunk > > svn info > @REM Working Copy Root Path: D:\test\wc > @REM URL: file:///D:/test/repo/trunk > @pause > > echo .>first.txt > svn add first.txt > svn commit -m "1st" > > svn copy -m "prj0" . "^/branches/prj0" You're copying a mixed-revision working copy here. Is that really what you want? ^/branches/prj0 is a copy of ^/trunk@1 ^/branches/prj0/first.txt is a copy of ^/trunk/first.txt@2. See http://svnbook.red-bean.com/en/1.7/svn.basic.in-action.html#svn.basic.in-action.mixedrevs Usually, you'd copy URLs to create branches, as you do on the next line in the script: > svn copy -r HEAD -m "prj1" "^/trunk" "^/branches/prj1" > svn switch "^/branches/prj1" The switch, like an update, results in a single-rev working copy. > echo .>second.txt > svn add second.txt > svn commit -m "2nd" > > svn switch "^/trunk" > svn copy -r HEAD -m "testing" "^/trunk" "^/branches/testing" > > echo "change" > first.txt > svn commit -m "change" > svn copy -r HEAD -m "prj2" "^/trunk" "^/branches/prj2" > > echo "change2" > first.txt > svn commit -m "change2" > svn copy -m "prj3" . "^/branches/prj3" Mixed-rev copy again. This time ^/branches/prj3 is a copy of ^/trunk@9, and ^/branches/prj3/first.txt is a copy of ^/trunk/first.txt@8. (I hope I'm getting these numbers right. I'm not actually running the script.) > svn switch "^/branches/prj2" > svn merge "^/branches/prj1" prj1 is a branch off trunk, and so is prj2. Which means prj1 and prj2 are not ancestrally related. The merge you are running is equivalent to: svn merge ^/branches/prj1@4 ^/branches/prj1@HEAD . The common ancestor of prj1 and prj2 is trunk@3. Because this is younger than r2, which added first.txt, you do not get an 'incoming add vs. local add' tree conflict on first.txt. So this merge happens to work as you expect. Ideally, you'd reintegrate prj1 into trunk first and then merge the changes into prj2 from trunk, using a sequence such as: svn switch ^/trunk svn merge --reintegrate ^/branches/prj1 svn commit svn switch ^/branches/prj2 svn merge ^/trunk > svn commit -m "prj1 into prj2" > > svn switch "^/branches/prj3" > svn merge "^/branches/prj0" Here you run into a tree conflict because the common ancestor is trunk@1, which /branches/prj0 was copied from. Because you created prj0 as a mixed-rev copy, first.txt has a different common ancestor: first.txt@2. Subversion merges all eligible changes made between ^/trunk@1 and ^/branches/prj0@HEAD. This changeset includes the addition of first.txt, which the merge attempts to apply to the merge target prj3. There is already a node called first.txt in prj3, so you get a tree-conflict: > @REM C first.txt > @REM --- Recording mergeinfo for merge of r2 through r11 into '.': > @REM U . > @pause > svn st > @REM M . > @REM C first.txt > @REM > local add, incoming add upon merge > @pause > svn revert -R . > > svn switch "^/branches/prj1" > svn merge "^/trunk" > svn commit -m "prj1 sync" What is the purpose of this sync merge? > svn switch "^/branches/testing" > svn merge "^/branches/prj1" > svn commit -m "prj1 into testing" > > svn merge "^/branches/prj2" Again, you hit a similar problem here. > @REM --- Recording mergeinfo for merge of r2 through r7 into '.': > @REM U . > @REM -- Zusammenfuehren von r8 bis r13 in '.': > @REM C second.txt > @REM G . > @REM --- Recording mergeinfo for merge of r8 through r13 into '.': > @REM U . > @pause > svn st > @REM M . > @REM C second.txt > @REM > local add, incoming add upon merge > @pause > svn revert -R . > > cd \ What is the purpose of the separate 'testing' branch? Why are you not testing prj1 directly, reintegrate it into trunk when tests succeed, and then sync all your other branches to trunk to merge prj1 changes into them? If you did that, your approach of using 'svn merge ^/some-branch' would work fine. But make sure to use the --reintegrate option whenever you merge one of your branches back into trunk (fortunately, the requirement to use --reintegrate will go away in Subversion 1.8, but for now you must still use it). Your troubles come from merging between ancestrally unrelated branches and (probably to a lesser extent) from creating branches from mixed-revision working copies. And that you are applying of the 'svn merge ^/foo' short-hand notation to situations it wasn't designed for. See the output of 'svn help merge' for more details. It has some diagrams to illustrate which 'svn merge' invocation is appropriate for a given merge scenario. If you really must merge between unrelated branches, use the 2-URL merge syntax instead of the 'svn merge ^/foo' short-hand syntax and specify revisions for each of the 2 URL arguments to merge meaningful changesets. For instance, say you created '^/branches/A' from trunk in r399, and then made some interesting changes between r410 and r450 on branch A. You want to merge those changes into a completely unrelated branch called 'testing'. Try something like this: svn switch ^/branches/testing svn merge ^/branches/A@410 ^/branches/prj@450 . In some cases you might also have to use the --ignore-ancestry option to prevent Subversion from tracing history backwards to find a common ancestor. Note that this option prevents mergeinfo from being recorded, so I wouldn't recommend this approach if you can avoid it.