Hi, merge fans.

It's time to lose the temporary '--symmetric' option and make it the default 
mode in 'svn'.


Some people have been kind enough to try using the 'symmetric' mode and report 
back, mainly Paul to whom I am most grateful.  I am aware of two current issues 
([1],[2]) which I am investigating and they are looking simple enough to be 
resolved soon.  Please help me flag up any other issues.

Before we consider the details of the UI changes, I thought back to how the 
user base would see 'symmetric merge' in the context of the history of 
Subversion's merge tracking, and wrote a brief overview at
<http://wiki.apache.org/subversion/SymmetricMerge#The_User.27s_Perspective>.


UI CHANGES

I think, and please tell me if you disagree, that we will make the best 
progression with a UI like this, which the attached patch [6] roughly 
implements for illustration:

  * Use the 'symmetric'/'auto'[3] mode for any merge that was previously a 
reintegrate or a non-reintegrate 'sync' merge.  That is, when there is:
    - just one source;
    - no start revision;
    - (an end revision may be specified, which can be done without a start rev 
by specifying peg-rev syntax: SOURCE@END_REV);
    - no incompatible options (such as --ignore-ancestry).

  * If the code chooses a reintegrate-like merge, it will apply the strict WC 
checks like reintegrate does in 1.7.

  * Make the '--reintegrate' option mean the user believes a reintegrate-style 
merge is needed, so check that the previous merge is as expected (that it, in 
the opposite direction) and bail out if not.

  * Mark the '--reintegrate' option as deprecated, as the reason for its 
existence has gone.

  * Delete the '--symmetric' option; it was only there for testing and has not 
been released.


WHAT WILL NOT CHANGE

Two specific things to call out:

  * A merge specifying '--reintegrate' merge will not change in any scenario 
where 'merge --reintegrate' is the user's best option today.

  * A merge specifying '-r X:Y' will not change.  This requests a cherry-pick 
merge, using merge tracking to avoid re-merging any revs in the range that are 
already merged.  Currently, if 'X' is 1 or a low enough number such that there 
are no unmerged revisions before 'X', then Subversion performs exactly the same 
kind of merge as when 'X' is not specified, which we call a 'sync' merge.  I 
believe we could make a later enhancement to automatically use 'reintegrate' 
mode if that would be the correct thing to do for merging the requested range.


OPTIONS NOT ALLOWED WITH --REINTEGRATE

The following options are not allowed with '--reintegrate' in 1.7 but are 
allowed for non-reintegrate merge-tracking merges:
  --record-only
  --depth
  --force
  --allow-mixed-revisions

My recommendation for these options is that if we choose a reintegrate-style 
merge then we error out, saying "the required merge is reintegrate-like[4], and 
option --X is not supported for this kind of merge".  Otherwise we handle the 
option just like in 1.7.



Please let me know if this seems good, while I  go and adjust the help text.
- Julian



[1] Unexpected revision number in the "Merging r6 through r9" notification, 
<http://svn.haxx.se/dev/archive-2012-08/0005.shtml>.

[2] Behaviour when the root has not been merged, a subtree has, and now we 
merge the root in the other direction, 
<http://svn.haxx.se/dev/archive-2012-08/0008.shtml>.

[3] Every time I say 'symmetric', I try to think of a better name.  It's not 
symmetric, it's just based on a symmetric model.  'automatic'?  'bidirectional'?

[4] Need to choose terminology for a reintegrate-style merge, for the UI.  
"reversing direction"?

[5] Wiki page, <http://wiki.apache.org/subversion/SymmetricMerge>.

[6] Attachment, 'enable-symmetric-merge-1.patch'.

[7] GUIs and other clients can switch to the new svn_client API when 
they are ready to do so; here I'm just talking about our 'svn' client.

--
Subversion Live 2012 - 2 Days: training, networking, demos & more! 
http://bit.ly/NgUaRi
Certified & Supported Apache Subversion Downloads: 
http://www.wandisco.com/subversion/download
Enable symmetric merge as the default merge in 'svn'.  If the --reintegrate
option is given but a non-reintegrate merge is the kind needed, bail out.
Stop recognizing the '--symmetric' option, as that was a temporary
development tool.

### This patch should be extended to delete the '--symmetric' option and to
### update the merge help text.

* subversion/include/private/svn_client_private.h
  (svn_client__symmetric_merge_t): Move structure definition to here ...

* subversion/libsvn_client/merge.c
  (svn_client__symmetric_merge_t): ... from here.
  (do_symmetric_merge_locked): Reject unsupported options in reintegrate
    mode.

* subversion/svn/merge-cmd.c
  (pathrev_equal): New function.
  (symmetric_merge): Bail out if a non-reintegrate kind of merge is needed
    but the '--reintegrate' option was specified. Reject unsupported options
    in reintegrate mode.
  (svn_cl__merge): 

--This line, and those below, will be ignored--

Index: subversion/include/private/svn_client_private.h
===================================================================
--- subversion/include/private/svn_client_private.h	(revision 1368758)
+++ subversion/include/private/svn_client_private.h	(working copy)
@@ -185,7 +185,10 @@ svn_client__wc_node_get_origin(svn_clien
 #ifdef SVN_WITH_SYMMETRIC_MERGE
 
 /* Details of a symmetric merge. */
-typedef struct svn_client__symmetric_merge_t svn_client__symmetric_merge_t;
+typedef struct svn_client__symmetric_merge_t
+{
+  svn_client__pathrev_t *yca, *base, *mid, *right;
+} svn_client__symmetric_merge_t;
 
 /* Find the information needed to merge all unmerged changes from a source
  * branch into a target branch.  The information is the locations of the
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1368758)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -11149,12 +11149,6 @@ location_on_branch_at_rev(const branch_h
   return NULL;
 }
 
-/* Details of a symmetric merge. */
-struct svn_client__symmetric_merge_t
-{
-  svn_client__pathrev_t *yca, *base, *mid, *right;
-};
-
 /* */
 typedef struct source_and_target_t
 {
@@ -11654,6 +11648,24 @@ do_symmetric_merge_locked(const svn_clie
       svn_ra_session_t *right_ra_session = NULL;
       svn_ra_session_t *target_ra_session = NULL;
 
+      if (record_only)
+        return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the record-only option "
+                                  "cannot be used with this kind of merge"));
+
+      if (depth != svn_depth_unknown)
+        return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the depth option "
+                                  "cannot be used with this kind of merge"));
+
+      if (force)
+        return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the force option "
+                                  "cannot be used with this kind of merge"));
+
       SVN_ERR(ensure_ra_session_url(&base_ra_session, merge->base->url,
                                     ctx, scratch_pool));
       SVN_ERR(ensure_ra_session_url(&right_ra_session, merge->right->url,
Index: subversion/svn/merge-cmd.c
===================================================================
--- subversion/svn/merge-cmd.c	(revision 1368758)
+++ subversion/svn/merge-cmd.c	(working copy)
@@ -85,6 +85,15 @@ merge_reintegrate(const char *source_pat
   return SVN_NO_ERROR;
 }
 
+/*  */
+static svn_boolean_t
+pathrev_equal(const svn_client__pathrev_t *pathrev1,
+              const svn_client__pathrev_t *pathrev2)
+{
+  return (pathrev1->rev == pathrev2->rev
+          && strcmp(pathrev1->url, pathrev2->url) == 0);
+}
+
 /* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository
  * revision. */
 static svn_error_t *
@@ -116,13 +125,15 @@ symmetric_merge(const char *source_path_
                 svn_boolean_t record_only,
                 svn_boolean_t dry_run,
                 svn_boolean_t allow_mixed_rev,
-                svn_boolean_t allow_local_mods,
-                svn_boolean_t allow_switched_subtrees,
+                svn_boolean_t reintegrate,
                 const apr_array_header_t *merge_options,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *scratch_pool)
 {
+  svn_boolean_t allow_local_mods = ! reintegrate;
+  svn_boolean_t allow_switched_subtrees = ! reintegrate;
   svn_client__symmetric_merge_t *merge;
+  svn_boolean_t reintegrate_like;
 
   /* Find the 3-way merges needed (and check suitability of the WC). */
   SVN_ERR(svn_client__find_symmetric_merge(&merge,
@@ -131,5 +142,41 @@ symmetric_merge(const char *source_path_
                                            allow_local_mods, allow_switched_subtrees,
                                            ctx, scratch_pool, scratch_pool));
 
+  reintegrate_like = (merge->mid != NULL);
+
+  if (reintegrate && ! reintegrate_like
+      && ! pathrev_equal(merge->yca, merge->base))
+    {
+      return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                                _("The --reintegrate option was given but the "
+                                  "required merge is not reintegrate-like"));
+    }
+  if (reintegrate_like)
+    {
+      if (record_only)
+        return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the --record-only option "
+                                  "cannot be used with this kind of merge"));
+
+      if (depth != svn_depth_unknown)
+        return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the --depth option "
+                                  "cannot be used with this kind of merge"));
+
+      if (force)
+        return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the --force option "
+                                  "cannot be used with this kind of merge"));
+
+      if (allow_mixed_rev)
+        return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                                _("The required merge is reintegrate-like, "
+                                  "and the --allow-mixed-revisions option "
+                                  "cannot be used with this kind of merge"));
+    }
+
   /* Perform the 3-way merges */
   SVN_ERR(svn_client__do_symmetric_merge(merge, target_wcpath, depth,
@@ -405,19 +452,11 @@ svn_cl__merge(apr_getopt_t *os,
    * If any conflicts occur we'll run the conflict resolver later. */
 
 #ifdef SVN_WITH_SYMMETRIC_MERGE
-  if (opt_state->symmetric_merge)
+  /* Do a symmetric merge if just one source and no revisions. */
+  if ((! two_sources_specified) && (! opt_state->ignore_ancestry)
+      && first_range_start.kind == svn_opt_revision_unspecified
+      && first_range_end.kind == svn_opt_revision_unspecified)
     {
-      svn_boolean_t allow_local_mods = ! opt_state->reintegrate;
-      svn_boolean_t allow_switched_subtrees = ! opt_state->reintegrate;
-
-      if (two_sources_specified)
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("SOURCE2 can't be used with --symmetric"));
-      if (first_range_start.kind != svn_opt_revision_unspecified
-          || first_range_end.kind != svn_opt_revision_unspecified)
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("a revision range can't be used with --symmetric"));
-
       SVN_ERR_W(svn_cl__check_related_source_and_target(
                   sourcepath1, &peg_revision1, targetpath, &unspecified,
                   ctx, pool),
@@ -430,8 +469,7 @@ svn_cl__merge(apr_getopt_t *os,
                                   opt_state->record_only,
                                   opt_state->dry_run,
                                   opt_state->allow_mixed_rev,
-                                  allow_local_mods,
-                                  allow_switched_subtrees,
+                                  opt_state->reintegrate,
                                   options, ctx, pool);
     }
   else

Reply via email to