The condition was originally added in r873100, following the discussion (mainly 
between Paul and me) at 
<http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=72921>.
  At that time, the "foreign repos" filtering was inside the function 
"filter_self_referential_mergeinfo", so that may have caused confusion.

It looks like r873100 was in error and the foreign-repos filtering should be 
unconditional.

Fix:
[[[
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c    (revision 1429021)
+++ subversion/libsvn_client/merge.c    (working copy)
@@ -1293,32 +1293,33 @@ prepare_merge_props_changed(const apr_ar
         }
       props = mergeinfo_props;
     }
 
   if (props->nelts)
     {
+      /* Issue #3383: We don't want mergeinfo from a foreign repos.
+
+         If this is a merge from a foreign repository we must strip all
+         incoming mergeinfo (including mergeinfo deletions).  Otherwise if
+         this property isn't mergeinfo or is NULL valued (i.e. prop removal)
+         or empty mergeinfo it does not require any special handling.  There
+         is nothing to filter out of empty mergeinfo and the concept of
+         filtering doesn't apply if we are trying to remove mergeinfo
+         entirely.  */
+      if (! merge_b->same_repos)
+        SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool));
+
       /* If this is a forward merge then don't add new mergeinfo to
          PATH that is already part of PATH's own history, see
          http://svn.haxx.se/dev/archive-2008-09/0006.shtml.  If the
          merge sources are not ancestral then there is no concept of a
          'forward' or 'reverse' merge and we filter unconditionally. */
       if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev
           || !merge_b->merge_source.ancestral)
         {
-          /* Issue #3383: We don't want mergeinfo from a foreign repos.
-
-             If this is a merge from a foreign repository we must strip all
-             incoming mergeinfo (including mergeinfo deletions).  Otherwise if
-             this property isn't mergeinfo or is NULL valued (i.e. prop 
removal)
-             or empty mergeinfo it does not require any special handling.  
There
-             is nothing to filter out of empty mergeinfo and the concept of
-             filtering doesn't apply if we are trying to remove mergeinfo
-             entirely.  */
-          if (! merge_b->same_repos)
-            SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool));
-          else if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge)
+          if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge)
             SVN_ERR(filter_self_referential_mergeinfo(&props,
                                                       local_abspath,
                                                       merge_b->ra_session2,
                                                       merge_b->ctx,
                                                       result_pool));
         }
]]]

FWIW, I tried removing the "if (! reverse-merge)" condition entirely (from both 
the foreign-repos and the self-ref filtering), and the test suite 
passed.  That is not too surprising, as it probably has very few test cases for 
foreign-repos reverse merge and/or self-ref mergeinfo.

- Julian


I (Julian Foad) wrote:

> I'm trying to understand prepare_merge_props_changed().  I don't get why 
> the stripping 
> of self-referential and foreign-repos mergeingo is *not* performed when 
> doing a reverse merge, as I highlight below.  Paul, can you shed any light on 
> it?
> 
> Index: subversion/libsvn_client/merge.c
> ===================================================================
> 
>  /* Prepare a set of property changes PROPCHANGES to be used for a merge
> -   operation on LOCAL_ABSPATH. Store the result in *PROP_UPDATES.
> +   operation on LOCAL_ABSPATH.
> 
> +   Remove all non-regular prop-changes (entry-props and WC-props).
> +   Remove all non-mergeinfo prop-changes if it's a record-only merge.
> +   Remove self-referential mergeinfo (### in some cases...)
> +   Remove foreign-repository mergeinfo (### in some cases...)
> +
> +   Store the filtered property changes in *PROP_UPDATES.
>     Store information on where mergeinfo is updated in MERGE_B.
> 
>     Used for both file and directory property merges. */
>  static svn_error_t *
>  prepare_merge_props_changed(const apr_array_header_t **prop_updates,
>                              const char *local_abspath,
>                              const apr_array_header_t *propchanges,
>                              merge_cmd_baton_t *merge_b,
>                              apr_pool_t *result_pool,
>                              apr_pool_t *scratch_pool)
>  {
>    apr_array_header_t *props;
> 
>    [...]
> 
>    if (props->nelts)
>      {
>        /* If this is a forward merge then don't add new mergeinfo to
>           PATH that is already part of PATH's own history, see
> http://svn.haxx.se/dev/archive-2008-09/0006.shtml.  If the
>           merge sources are not ancestral then there is no concept of a
>           'forward' or 'reverse' merge and we filter 
> unconditionally. */
> +      /*
> +       * ### Whereas, if this is a reverse merge, this implies it's OK
> +       *    to add new mergeinfo that is already part of PATH's own
> +       *    history (and OK to add foreign-repository mergeinfo) ???
> +       *
> +       *    This doesn't sound right.  Why are these two kinds of
> +       *    filtering conditional at all?
> +       */
>        if (merge_b->merge_source.loc1->rev < 
> merge_b->merge_source.loc2->rev
>            || !merge_b->merge_source.ancestral)
>          {
>            /* Issue #3383: We don't want mergeinfo from a foreign repos.
> 
>               If this is a merge from a foreign repository we must strip all
>               incoming mergeinfo (including mergeinfo deletions).  Otherwise 
> if
>               this property isn't mergeinfo or is NULL valued (i.e. prop 
> removal)
>               or empty mergeinfo it does not require any special handling.  
> There
>               is nothing to filter out of empty mergeinfo and the concept of
>               filtering doesn't apply if we are trying to remove mergeinfo
>               entirely.  */
>            if (! merge_b->same_repos)
>              SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool));
>            else if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge)
>              SVN_ERR(filter_self_referential_mergeinfo(&props,
>                                                        local_abspath,
>                                                        merge_b->ra_session2,
>                                                        merge_b->ctx,
>                                                        result_pool));
>          }
>      }
> 
> 
> It looks like if I were to try a foreign-repos reverse merge, where the 
> change 
> in the foreign repos included a mergeinfo change, that mergeinfo change would 
> (wrongly) propagate into the target repos.
> The following snippet isn't a full repro recipe but shows that a foreign 
> mergeinfo change is indeed being applied in this case:
> 
> $ svn merge -c-5 file:///home/julianfoad/tmp/svn/frm/repo/branches/A foo/
> --- Reverse-merging (from foreign repository) r5 into 'foo':
>  U   foo/A
>  C   foo
> Summary of conflicts:
>   Property conflicts: 1
> Conflict for property 'svn:mergeinfo' discovered on 'foo'.
> Trying to delete property 'svn:mergeinfo'
> but the local property value is different.
> <<<<<<< (local property value)
> /trunk:1-999=======
>>>>>>>>  (incoming property value)
> 
> 
> The discussion in 
> <http://subversion.tigris.org/issues/show_bug.cgi?id=3383> doesn't say 
> anything about the filtering of foreign-repos mergeinfo being conditional.
> 
> I haven't investigated/tested the self-ref filtering part of this.
> 
> 
> - Julian
>

Reply via email to