Bug Link:

Patch Link:

source code patch:


Background(‘svn merge –record-only’: modify mergeinfo metafile to mark as merged though the diff are not actually merged. Mergeinfo essentially is a meta-data file to record all the merging history. This feature is used to block the automatic change from merging.)


Record-only merging introduces unnecessary, self-referential mergeinfo metafile.

If we want to merge a branch of revision (M+1) into a trunk of revision M, using ‘--record-only merge’, we will have the following lines in mergeinfo file:

Added: svn:mergeinfo

   Merged /t1:r2-M

   Merged /t1-branch:rM+1


The line “Merged /t1:r2-M” is unnecessary and wrong!!! It is self-referential and contains the natural history!!!

If we don’t use ‘--record-only’ option, then self-referential information is successfully filtered out.

How it is diagnosed:



How to reproduce:

Step1) setup the repository

                1-1. make a branch ‘t1-branch’ from the trunk ‘t1’

                            ‘svn cp t1 t1-branch’

                1-2. commit the change-set

                            ‘svn ci –m “branch t1 to t1-branch”’

Step2) expected result

                2-1. merge branch back to the trunk

                            ‘svn merge ^/t1-branch t1’

                2-2. print out mergeinfo metadata by ‘svn diff’


Property changes on: t1


Added: svn:mergeinfo

   Merged /t1-branch:r11                                                     


=> the trunk is merged from the branch, ‘t1-branch’ of revision 11.


Step3) self-referential mergeinfo from ‘—record-only’ merging.

                3-1. record-only merge branch back to the trunk

                            ‘svn merge –record-only ^/t1-branch t1’

                3-2. print out mergeinfo metadata by ‘svn diff’


Property changes on: t1


Added: svn:mergeinfo

   Merged /t1:r2-10

   Merged /t1-branch:r11


*Result: Beside the information of t1-branch, the trunk, ‘t1’ also has its own history, ‘/t1:r2-10’. It’s unnecessary self-referential information.

Root Cause:


When running ‘svn merge –record-only’, they are creating self-referential mergeinfo because it fails to filter out the self-referential information.


In the buggy case, it contains self-referential mergeinfo because of appending every mergeinfo.

To avoid self-referential mergeinfo, we need to register this mergeinfo to the ‘implicit mergeinfo’ data structure so that ‘filter_natrual_history_from_mergeinfo()’ function can get rid of it.


To avoid self-referential mergeinfo, we need to get a ‘implicit mergeinfo’ of self-referential data. With this data, ‘filter_natural_history_from_mergeinfo()’ function can get rid of the self-referential info. In ‘populate_remaining_ranges’ function, there’s a routine that gets the target’s implicit mergeinfo during ‘–record-only merges’.


In the first call of ‘populate_remaining_ranges’ with ‘--record-only’ option, the mergeinfo is always the self-referential info while the arguments ‘url1’ and ‘url2’ are the same.

#0  populate_remaining_ranges (


                               source_root_url=0x6abc78 "svn://",

                               url1=0x6a71e8 "svn://",


                               url2=0x6a7230 "svn://",




                               parent_merge_src_canon_path=0x6abcc0 "/t1",

                               merge_b=0x7fffffffdca0, pool=0x6abbd8)

at subversion/libsvn_client/merge.c:4116

#1  do_directory_merge (...) at subversion/libsvn_client/merge.c:7826

#2  do_merge (...,   record_only=1,) at subversion/libsvn_client/merge.c:8312

#3  merge_peg_locked (...) at subversion/libsvn_client/merge.c:10100

#4  merge_peg_cb (...) at subversion/libsvn_client/merge.c:10134

#5  svn_wc__call_with_write_lock (...) at subversion/libsvn_wc/lock.c:1724

#6  svn_client_merge_peg3 (...) at subversion/libsvn_client/merge.c:10179

#7  svn_cl__merge (...) at subversion/svn/merge-cmd.c:322

#8  main (argc=5, argv=0x7fffffffe7b8) at subversion/svn/main.c:2296

After calculating the revision range of the merge info, it returns to ‘do_directory_merge’ function. In ‘do_directory_merge’ function, ‘filter_natural_history_from_mergeinfo’ function called by ‘record_mergeinfo_for_dir_merge’.

static svn_error_t *



   ... ...

  /* If we are honoring mergeinfo, then for each item in

     NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be

     merged, and then merge it.  Otherwise, we just merge what we were asked

     to merge across the whole tree.  */


   ... ...

  /* Record mergeinfo where appropriate.*/

  if (record_mergeinfo)









      ... ...


  return svn_error_return(err);


static svn_error_t *



  ... ...


  /* Record mergeinfo on any subtree affected by the merge or for

     every subtree if this is a --record-only merge.  Always record

     mergeinfo on the merge target CHILDREN_WITH_MERGEINFO[0]. */

  for (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++)


      if (...)


          ... ...


      else /* Record mergeinfo on CHILD. */


          ... ...


          /* Filter any ranges from each child's natural history before

             setting mergeinfo describing the merge. */


            &child_merge_rangelist, child_merge_src_canon_path,

            child->implicit_mergeinfo, &range, iterpool));

          /* If the mergeinfo has only natural history like self-referential info, then the corresponding revision range is deleted and returns in the following statement. However, the buggy version has no implicit information denoting self-reference, so that it does not return but print out the self-referential info */

          if (child_merge_rangelist->nelts == 0)


          ... ...


        ... ...

    } /* (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++) */



  return SVN_NO_ERROR;


 The patch is :

--- subversion/trunk/subversion/libsvn_client/merge.c           2010/05/28 21:40:36            949306

+++ subversion/trunk/subversion/libsvn_client/merge.c        2010/05/28 21:44:18            949307

@@ -4112,6 +4112,9 @@ populate_remaining_ranges(apr_array_head

   apr_pool_t *iterpool;

   int i;

   svn_revnum_t gap_start, gap_end;

+  svn_boolean_t child_inherits_implicit;

+  svn_client__merge_path_t *parent;

+  int parent_index;


   iterpool = svn_pool_create(pool);


@@ -4125,6 +4128,46 @@ populate_remaining_ranges(apr_array_head

               svn_client__merge_path_t *child =

             APR_ARRAY_IDX(children_with_mergeinfo, i,

                           svn_client__merge_path_t *);


+              parent = NULL;

+              svn_pool_clear(iterpool);


+              /* Issue #3646 'record-only merges create self-referential

+             mergeinfo'.  Get the merge target's implicit mergeinfo (natural

+             history).  We'll use it later to avoid setting self-referential

+             mergeinfo -- see filter_natural_history_from_mergeinfo(). */

+              if (i == 0) /* First item is always the merge target. */

+                {

/* by calling get_full_mergeinfo, we can make a implicit mergeinfo and this information is used later to filter out by filter_natural_history_from_mergeinfo. In no ‘record-only’ case, ‘get_full_mergeinfo’ function is also called so that implicit information is generated. Consequently, it doesn’t have self-referential info */

+                  SVN_ERR(get_full_mergeinfo(NULL, /* child->pre_merge_mergeinfo */

+                                         &(child->implicit_mergeinfo),

+                                             NULL, /* child->indirect_mergeinfo */

+                                         svn_mergeinfo_inherited, ra_session,

+                                         child->abspath,

+                                             MAX(revision1, revision2),

+                                         MIN(revision1, revision2),

+                                         merge_b->ctx, pool, iterpool));

+                }


Failure type

wrong result

Is there any log message?


Can ErrLog insert a log message?