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

how issue-2897 branch solves reflective merges?

From: Kamesh Jayachandran <kamesh_at_collab.net>
Date: Fri, 11 Jan 2008 17:08:50 +0530

Hi All,

Let me summarize the changes in issue-2897 branch.

I would love to get some real technical reasons for not accepting 2897
for 1.5 rather than '*it is complex*'.

Yes it was complex when I started and while working on it at times. Now
I see no complexity.

I would love to see real technical problem that justifies that it can
not get in to 1.5.

For those interested to review it, following explanation should help.

1)Implement 'get-commit-and-merge-ranges' API in all layers (40% of the
change)
2)Write the testcases (30-35% change)
3)Extract non-reflective changes from a reflective revision, pure
libsvn_client change (25-30%)

To review item 1) Major focus need to be in
subversion/libsvn_fs_util/mergeinfo-sqlite-index.c,
rest of the other functions at every level is just a wrapper over this
core implementation.

Item 2)Testcases: covers almost all the cases I can imagine, it covers
all reflective callbacks.

Item 3) libsvn_client is very tricky to understand but logic is simple
as described below,
 a) Identify reflective revision and merge that reflective revision
alone with reflective callbacks.
 b) Let me explain each callback.

  i) file_changed callback
  reflective_merge_file_changed(mine, older, yours)
  mine = WC file.
  older = file_at_reflective_rev-1
  yours = file_at_reflective_rev

Normal merge_file_changed applies diff(older, yours) to mine.
This diff can contain the changes 'synch up from trunk' as well as the
local adhoc changes and conflict resolutions.

Applying the diff directly is going to cause lots of headaches.

So objective is to have a meaningful diff of *only local adhoc changes
done before committing the merge*.

Let me take the example and explain,

Case1:

We merge -r13, -r17, -r29 from /trunk to /feature_branch and commit at
r40 (Assume this is the only synch up)

Now we merge /feature_branch -r1:40 back to /trunk.

It does a merge of -r1:39 which is a normal merge.
It does a reflective merge of 40.
Let us say /feature_branch/test.c got a change from a merge at r40(Our
first merge)

To calculate the *meaningful diff*, We apply -r13 change to OLDER, and
r17 change to OLDER, r29 change to OLDER.

Now in this case after the above 3 merges(r13, r17, r29) OLDER becomes
YOURS and hence no change is applied to MINE.

Case2:

We merge -r13, -r17, -r29 from /trunk to /feature_branch + local
non-conflicting change to /feature_branch/test.c and commit at r40
(Assume this is the only synch up)

Now we merge /feature_branch -r1:40 back to /trunk.

It does a merge of -r1:39 which is a normal merge.
It does a reflective merge of 40.
Let us say /feature_branch/test.c got a change from a merge at r40(Our
first merge)

To calculate the *meaningful diff*, We apply -r13 change to OLDER, and
r17 change to OLDER, r29 change to OLDER.

Now in this case after the above 3 merges(r13, r17, r29) OLDER becomes
(YOURS-local non conflicting changes) and hence
(YOURS-YOURS +local non conflicting changes) is applied to MINE. i.e
local non conflicting changes

Case3:

We merge -r13, -r17(conflicting), -r29 from /trunk to /feature_branch +
local non-conflicting change + conflict resolution to r17 to
/feature_branch/test.c and commit at r40
(Assume this is the only synch up)

Now we merge /feature_branch -r1:40 back to /trunk.

It does a merge of -r1:39 which is a normal merge.
It does a reflective merge of 40.
Let us say /feature_branch/test.c got a change from a merge at r40(Our
first merge)

To calculate the *meaningful diff*, We apply -r13 change to OLDER, and
r29 change to OLDER. (SEE WE DONT APPLY r17 as it is a conflicting one)/

Now in this case after the above 2 merges(r13, r29) OLDER becomes
(YOURS-local non conflicting changes - r17 - conflict resolution to r17)
and hence
(YOURS-YOURS +local non conflicting changes + r17 + conflict resolution
to r17) is applied to MINE. i.e local non conflicting changes + r17 +
conflict resolution to r17. Moral: If synch up gave a conflict reverse
also would give

ii)dir_added/dir_deleted/file_added/file_deleted.
Prior to a *reflective* merge drive we run 'diff summarize on
*reflected* ranges'.
Case 4:

We merge -r13, -r17, -r29 from /trunk to /feature_branch and commit at
r40 (Assume this is the only synch up)(merge adds test.c at r13, deletes
the same at r14)

Now we merge /feature_branch -r1:40 back to /trunk.

It does a merge of -r1:39 which is a normal merge.
It does a reflective merge of 40.

Our summary implementation won't care about 'test.c' as in effect A+D
= NO_CHANGE_COMMITTED and we won't get 'file_added' callback in this case.

Case 5:

We merge -r13, -r17, -r29 from /trunk to /feature_branch and commit at
r40 (Assume this is the only synch up)(merge adds test.c at r13, deletes
the same at r14, user adds adhoc 'test.c')

Now we merge /feature_branch -r1:40 back to /trunk.

It does a merge of -r1:39 which is a normal merge.
It does a reflective merge of 40.

Our summary implementation Would say nothing about 'test.c' as in
effect A+D = NO_CHANGE_COMMITTED.
But we get 'file_added' callback in this case due to local addition.
*SUMMARY IMPLEMENTATION* would help us in deciding whether to add the
file or not. (If there is *no* summary add the file or else leave it).

Same explanation applies to dir additions, file/dir deletions.

Would love to get more feedbacks on it.

With regards
Kamesh Jayachandran

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-01-11 12:42:31 CET

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