[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Question

From: Stefan Sperling <stsp_at_elego.de>
Date: Fri, 9 Dec 2011 15:00:05 +0100

On Fri, Dec 09, 2011 at 01:05:02PM +0000, Rob Pointer wrote:
> Mark
> If you put changes multiple times from trunk to a branch (in development
> terms, a re-base) you can cause reflective merges and actually cause more
> problems. The recommended merge back into trunk is a reintegrate merge.
> I am not sure if this has been addressed in 1.7, but certainly for earlier
> versions (anyone please correct me if I am wrong here though :) ).
>
> The scenario goes
> 1) trunk contains file A
> 2) copy trunk to branch1
> 3) modify file A in branch1
> 4) add folderb/fileb in trunk
> 5) branch (copy) folderb into branch (or merge if it actually works :) )
> 6) do some changes to file A and ffileb
> 7) merge back into trunk.
>
> SVN seems to get confused and when it checks the history of both trunk and
> branch1 it doesn't know that the folderb/fileb was added in branch1 using a
> copy, therefore it just thinks you added the files on trunk and then
> branch1 as two separate operations (for any clearcase users this is an evil
> twin scenario). Therefore SVN will create a tree conflict when merging
> your branch back into trunk.

Wrong, wrong, wrong. You may believe that Subversion is broken but in
fact you're just pushing its buttons the wrong way.

To be clear, if you use the correct merge syntax for each step your
scenario works just fine. And this applies to 1.6 as well as 1.7.

To demonstrate:

+ rm -rf reflective-merge
+ mkdir -p reflective-merge
+ mkdir -p reflective-merge/trunk
+ echo A
+ > reflective-merge/trunk/A
+ svnadmin create /tmp/reflective-merge/repos
+ svn import reflective-merge/trunk file:////tmp/reflective-merge/repos/trunk -m importing project tree
Adding reflective-merge/trunk/A

Committed revision 1.
+ svn copy file:////tmp/reflective-merge/repos/trunk file:////tmp/reflective-merge/repos/branch1 -m creating branch

Committed revision 2.
+ rm -rf reflective-merge/trunk
+ svn checkout file:////tmp/reflective-merge/repos/trunk reflective-merge/trunk
A reflective-merge/trunk/A
Checked out revision 2.
+ svn checkout file:////tmp/reflective-merge/repos/branch1 reflective-merge/branch1
A reflective-merge/branch1/A
Checked out revision 2.
+ echo foo
+ >> reflective-merge/branch1/A
+ svn commit -m modify A on branch reflective-merge/branch1
Sending reflective-merge/branch1/A
Transmitting file data .
Committed revision 3.
+ svn mkdir reflective-merge/trunk/folderb
A reflective-merge/trunk/folderb
+ echo bar
+ >> reflective-merge/trunk/folderb/fileb
+ svn commit -m add folderb/fileb on trunk reflective-merge/trunk
Adding reflective-merge/trunk/folderb

Committed revision 4.
+ svn update reflective-merge/branch1
Updating 'reflective-merge/branch1':
At revision 4.
+ svn merge file:////tmp/reflective-merge/repos/trunk reflective-merge/branch1 --accept postpone
--- Merging r2 through r4 into 'reflective-merge/branch1':
A reflective-merge/branch1/folderb
--- Recording mergeinfo for merge of r2 through r4 into 'reflective-merge/branch1':
 U reflective-merge/branch1
+ svn commit reflective-merge/branch1 -m merge trunk into branch (no conflicts)
Sending reflective-merge/branch1
Adding reflective-merge/branch1/folderb

Committed revision 5.
+ echo baz
+ >> reflective-merge/branch1/folderb/fileb
+ svn commit -m modify folderb/fileb on branch reflective-merge/branch1
+ svn update reflective-merge/trunk
Updating 'reflective-merge/trunk':
At revision 5.
+ svn merge --reintegrate file:////tmp/reflective-merge/repos/branch1 reflective-merge/trunk --accept postpone
--- Merging differences between repository URLs into 'reflective-merge/trunk':
U reflective-merge/trunk/A
--- Recording mergeinfo for merge between repository URLs into 'reflective-merge/trunk':
 U reflective-merge/trunk
+ svn commit reflective-merge/trunk -m reintegrate branch into trunk (no conflicts)
Sending reflective-merge/trunk
Sending reflective-merge/trunk/A
Transmitting file data .
Committed revision 6.

You only get a tree-conflict if you forget to use --reintegrate in the last
merge:

+ svn update reflective-merge/trunk
Updating 'reflective-merge/trunk':
At revision 5.
+ svn merge file:////tmp/reflective-merge/repos/branch1 reflective-merge/trunk --accept postpone
--- Merging r2 through r5 into 'reflective-merge/trunk':
U reflective-merge/trunk/A
   C reflective-merge/trunk/folderb
--- Recording mergeinfo for merge of r2 through r5 into 'reflective-merge/trunk':
 U reflective-merge/trunk
Summary of conflicts:
  Tree conflicts: 1
+ svn commit reflective-merge/trunk -m reintegrate branch into trunk (no conflicts)
subversion/svn/commit-cmd.c:183: (apr_err=155015)
subversion/libsvn_client/commit.c:853: (apr_err=155015)
subversion/libsvn_client/commit.c:853: (apr_err=155015)
svn: E155015: Commit failed (details follow):
subversion/libsvn_client/commit_util.c:1154: (apr_err=155015)
subversion/libsvn_client/commit_util.c:1154: (apr_err=155015)
subversion/libsvn_client/commit_util.c:823: (apr_err=155015)
subversion/libsvn_client/commit_util.c:329: (apr_err=155015)
svn: E155015: Aborting commit: '/tmp/reflective-merge/trunk/folderb' remains in conflict

To understand why you need the --reintegrate, see:
http://mail-archives.apache.org/mod_mbox/subversion-dev/201107.mbox/%3C20110720124721.GA7557@ted.stsp.name%3E

To understand how to repeatedly merge back and forth between the
trunk and the branch, see here:
http://svnbook.red-bean.com/en/1.7/svn.branchmerge.advanced.html#svn.branchmerge.advanced.reintegratetwice

For some reason understanding the --reintegrate option seems to be
a major usability hurdle for many when it comes to understanding merging
in Subversion. It would be nice to just make the 'svn merge ^/foobar'
magically do whatever people expect. But I don't see a good way of doing
that, unfortunately.
Once you understand what a 2-URL merge is and how that works, and that
any merge is really just a 2-URL merge, it's really not that hard to
understand that --reintegrate is just syntactic sugar and when you
should use it.

> A similar scenario occurs of you copied file A from trunk to branch1 after
> modifying it on trunk. SVN will then throw content conflicts, telling you
> that you modified the same line in the file in two branches (i.e. trunk
> and branch1) and the text is identical. Again not sure if 1.7 fixes this,
> but it is definitely present in 1.6.x

Again, please verify that you're invoking the tool in the right way
before jumping to conclusions.

If you don't carefully use the right 'svn merge' invokation syntax
for the situation at hand you can easily create conflicts for yourself.
See also the output of 'svn help merge' in 1.7, copied here:
http://subversion.apache.org/docs/svn-merge.txt
Received on 2011-12-09 15:00:44 CET

This is an archived mail posted to the Subversion Users mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.