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

svn 1.6 merge fails with Target path '/branches/branch' does not exist

From: Dmitry Pavlenko <pavlenko_at_tmatesoft.com>
Date: Wed, 15 Aug 2012 23:32:56 +0200

Hello,

In this letter I would like to describe some case I've encountered into. I have a repository (dump)
attached. I checkout trunk and merge branch (simply "svn merge file:///..../branches/branch") and
 * with svn 1.6 I get "Target path '/branches/branch' does not exist",
 * with svn 1.7 everything works fine.

The repository has the following history (of trunk and branch)

                           file
    -----------------------x[5] [6]--------------
   / -----------------/ \
  / / \
[1]----[2]----[3]----[4]------------------[7]----[8]--?
+file -file +file

And at r8 of trunk file "/trunk/file" contains some svn:mergeinfo (actually it's value doesn't matter,
it just should not include revisions [4,7] of the branch --- it should be just to turn on the merge
tracking on that file) and "/trunk" also contains svn:mergeinfo.

Properties on '.':
  svn:mergeinfo
    /branches/branch:6-7
Properties on 'file':
  svn:mergeinfo
    /branches/branch/file:3

After some investigation for svn 1.6 I've found that the following code is executed:
function "adjust_deleted_subtree_ranges" in libsvn_client/merge.c:

              /* PRIMARY_URL_at_older_rev exists, so it was deleted at some
                 revision prior to peg_rev, find that revision. */
              SVN_ERR(svn_ra_get_deleted_rev(ra_session, rel_source_path,
                                             older_rev, younger_rev,
                                             &revision_primary_url_deleted,
                                             subpool));

older_rev=3 /* for svn_ra_get_deleted_rev this parameter should play role of peg revision */
younger_rev=8
rel_source_path="file"
ra_session's url is "file:///..../branches/branch"

For that history this call is absolutely senseless because file:///..../branches/branch_at_3 is
absolutely different branch than file:///..../branches/branch_at_HEAD which we merge.
Moreover, file:///..../branches/branch_at_HEAD never contained "file" at all since creation at r6.

As result "adjust_deleted_subtree_ranges" function leaves "4,8" value in child->remaining_ranges,
and "diff" request fails.

Why svn 1.7 works fine?
"adjust_deleted_subtree_ranges" is called only from "fix_deleted_subtree_ranges", and in svn 1.7 (but
no in svn 1.6) before "fix_deleted_subtree_ranges" invocation another method is invoked:

      /* Remove inoperative ranges from any subtrees' remaining_ranges
         to spare the expense of noop editor drives. */
      if (!is_rollback)
        SVN_ERR(remove_noop_subtree_ranges(url1, revision1, url2, revision2,
                                           ra_session,
                                           notify_b, merge_b,
                                           scratch_pool, iterpool));

      /* Adjust subtrees' remaining_ranges to deal with issue #3067 */
      SVN_ERR(fix_deleted_subtree_ranges(url1, revision1, url2, revision2,
                                         ra_session, notify_b, merge_b,
                                         scratch_pool, iterpool));

And this changes everything. "remove_noop_subtree_ranges" has simple logic:
1. Get log for URL_at_rev we merge (file:///..../branches/branch_at_HEAD) to form 2 lists: revisions that
actually have changes (operative_ranges), and revisions that have changes but already merged
(merged_ranges). In my case operative_ranges=merged_ranges={[6,6]}
2. Create a range that shouldn't be merged [oldest_gap_rev, youngest_gap_rev]. In my case [3,8]
3. Exclude from it operative_ranges. In my case now it contains [3,5], [7,8].
4. Include into it merged_ranges. So now we have the list of all revisions that shouldn't be
considered. In my case now it contains [3,8] again.
5. Remove all these revisions from child->remaining_ranges. For my case child->remaining_ranges is
empty.

This optimization ("remove_noop_subtree_ranges") actually looks like a very reasonable filter and
prevents this bug. The only thing that looks suspicious --- "if (!is_rollback)" condition... I
didn't test but maybe with is_rollback=TRUE the problem can appear again.

Actually when I try to think how to replace "svn_ra_get_deleted_rev" with something working I also
find that "log" should be called on URL_at_rev we merge and changed paths should be analyzed.

As a conclusion:

Maybe the best one can do for svn 1.6 --- just add "remove_noop_subtree_ranges" method from svn 1.7
and leave everything as is. For trunk maybe it's better to add some assertions that
"remove_noop_subtree_ranges" has solved all problems instead of "svn_ra_get_deleted_rev" (that
could be expected to be an unreachable code --- though here I'm not sure) and to consider the case
is_rollback=FALSE.

I have a similar issue in SVNKit
http://issues.tmatesoft.com/issue/SVNKIT-305?projectKey=SVNKIT

Sorry for bothering if 1.6 bugs are not interesting or if you already know about this bug.

--
Dmitry Pavlenko,
TMate Software,
http://subgit.com/ - git+svn on the server side

Received on 2012-08-15 23:34:46 CEST

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