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

Re: unexpected tree conflict on merge for same source file

From: Sven Uhlig <svenuhlig_at_web.de>
Date: Thu, 18 Oct 2012 14:10:25 +0200

Am 17.10.2012 19:12, schrieb Stefan Sperling:
> On Wed, Oct 17, 2012 at 05:30:14PM +0200, Sven Uhlig wrote:
>> There could be
>> changes that are commited to prj1 that are requried in prj2 because of
>> e.g. some shared code.
>>
>> I would do this with the following command:
>> svn merge -r A:B "^/branches/prj1"
>>
>> Reintegration is not an option because the development will continue on
>> both branches in parallel.
>
> This approach sounds very chaotic to me.

For me it sounds like the "Keep Alive Dance". (See also the very bottom
of this mail.)

> Usually you'd isolate branches from another precisely because each
> branch should *not* see code developed on the other cousin branches.
> But at the same time you want these branches to share some code?

Sometimes only a small part of the changes in branch A is needed in
branch B because the ideas evolve for branch B. Usually I isolate
branches as suggested.

> That's a contradicition. And it makes merging harder than it needs to be.
>
> Every time you cherry-pick changes between cousins you run a high
> risk of merge conflicts later when the cousins are merged into other
> branches.

Yes, it makes merging more difficult. But that is what cherry-pick and
svn:mergeinfo are for? svn:mergeinfo has all the required information if
it looks into the past.

> In your case, why are the branches which need to share common code not
> branches off a branch which contains the shared code?

At the time when the branches were created there was no use of shared
code. Later some functions seem to be unexpectedly usefull in the other
branch.

> If the above won't work for some reason, maybe you shouldn't be using
> branching/merging in the first place. Instead, you could treat the
> shared code as an external dependency which your build system will
> pull into the build.

I think externals are not the right solutions if only single files or
even only some lines of source code are to be shared.

>> >> 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.
>>
>> I do not understand why there is a conflict in "second.txt".
>>
>> With svn:mergeinfo the SVN should have enough information to see that
>> the files are the same. There was no change and the original source is
>> the same (/branches/prj1/)
>
> You created second.txt on the prj1 branch. Let's assume you did so
> in revision 40, so that the change within prj1_at_40 looks like this:
>
> A second.txt
>
> ("add a file called second.txt")
>
> You then cherry-picked this revision from prj1 into prj2, causing a commit
> that added second.txt to prj2. Let's call this changeset 'prj2_at_50':
>
> A second.txt (copied from, say, prj1_at_49)
> Mergeinfo addition: Merged prj1:40-49
>
> Now you merge prj1 into testing, let's say in r61. The common ancestor of
> testing and prj1 is trunk, which does not contain second.txt.
> So among other changes you are merging:
>
> A second.txt (copied from, say, prj1_at_60)
> Mergeinfo addition: Merged prj1:40-60
>
> Next, you merge prj2 into testing, let's say in r71. The common ancestor
> of prj2 and testing is trunk, which does not contain second.txt.
> So the changeset being merged looks something like this:
>
> A second.txt (copied from, say, prj2_at_70)
> [no mergeinfo addition for prj1 see Stefan Sperlings 2nd mail]
> [old merginfo: Merged prj1:40-60, see previous merge]
> Mergeinfo addition: Merged prj2:50-70
>
> This results in the add vs. add tree conflict.
>
> How is Subversion supposed to tell that prj1:40-70 contains the same
> semantic change as prj2:50-70, the change which we cherry-picked from
> prj1 to prj2? In terms of mergeinfo the addition of second.txt happens
> in two distinct changesets: prj1_at_40 and prj2_at_50
> Mergeinfo doesn't tell us that, semantically, prj1_at_40 and prj2_at_50 contain
> the same change.
>
> And neither does tracing back history to the common ancestor of prj2 and
> testing tell us that these 'second.txt' files are related.
> The common ancestor is trunk, which has never seen 'second.txt'.

Just before the conflict in r71 the paths for second.txt to it's
original source (using your revisions) look like this:
1. prj1/second.txt_at_40 is the original file
2. prj2/second.txt_at_50 comes from prj1/second.txt_at_49
3. testing/second.txt_at_61 comes from prj1/second.txt_at_60

When merging prj2/ into testing, then SVN has two files "second.txt" at
hand:
1. prj2/second.txt_at_50
2. testing/second.txt_at_61

But if SVN looked back in the history of those two files it would see
both are from prj1/second.txt (@49 and @60)

Looking back in the history since those two revisions r49 and r60 there
was no change. So they are not from r49 an r60 but in fact from r40.

I think that SVN records the wrong revisions for mergeinfo or copy
because the file was not changed since addition but SVN still remembers
a newer revision than the latest change and thus sees a conflict/difference.

> The fact that this is a spurious conflict is evident to us because we
> know how the second.txt addition to prj2 came about. But what if we had
> added a different 'second.txt' file to prj2, which just happens to have
> the same name but is otherwise unrelated to the existing file in testing
> and prj1?

I can see that two independent adds with the same file name can cause
conflicts. But the files have the same source and SVN knows about it.
See my explanation above.

> Subversion cannot tell the difference between this scenario
> and the one above, so it needs to flag a tree conflict to alert us of
> the possibility that there is a genuine tree conflict.

There is a difference between "svn add" and "svn merge"/"svn copy". The
latter store mergeinfo or copy revision information.

> One key aspect here is that Subversion treats addition as a first-class
> operation. It doesn't care what the content of a newly added file is.
> If the change you are merging contains an 'A foo' change, that means
> "add foo", regardless of foo's content.

Your are right. The content is not important for this conflict. But the
difference between "svn add" and "svn merge"/"svn copy" is.

In the meantime I found the following document in the roadmap for SVN
1.8: "merge improvements"/"Symmetric Merging"

http://wiki.apache.org/subversion/SymmetricMerge

I think this document discusses similar problems in the sections "1.6.
The Keep-Alive Dance" and "1.9. Symmetric Merge with Criss-Cross Merge".

Seeing the discussion over there, I hope to see some improvements in the
merging algorithms :) Unfortunately it seems I have to use record-only
merges until then.

Best regards
Sven.
Received on 2012-10-18 14:11:48 CEST

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.