You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2016/11/30 17:10:20 UTC

svn commit: r1772086 - /subversion/trunk/subversion/libsvn_client/conflicts.c

Author: stsp
Date: Wed Nov 30 17:10:20 2016
New Revision: 1772086

URL: http://svn.apache.org/viewvc?rev=1772086&view=rev
Log:
Allow the conflict resolver to find nested moves which were left in a
conflicted state while resolving an incoming move during update.

With this change, the resolver will correctly identify the move of the tree
conflict victim left at the end of conflict test 25. Resolving this conflict
does not work yet, though, because some pre-condition checks still fail.

* subversion/libsvn_client/conflicts.c
  (find_related_node): New helper function, extracted from ...
  (conflict_tree_get_details_local_missing): ... this function.
  (conflict_tree_get_details_incoming_delete): Use the new helper function
   to find related nodes which are already deleted in the HEAD revision.
   Only implements the forward update direction (older rev -> younger rev)
   for now. We'll need to build new test cases for the other direction anyway.

Modified:
    subversion/trunk/subversion/libsvn_client/conflicts.c

Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1772086&r1=1772085&r2=1772086&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Wed Nov 30 17:10:20 2016
@@ -1539,6 +1539,88 @@ struct conflict_tree_local_missing_detai
   const char *moved_to_abspath;
 };
 
+static svn_error_t *
+find_related_node(const char **related_repos_relpath,
+                  svn_revnum_t *related_peg_rev,
+                  const char *younger_related_repos_relpath,
+                  svn_revnum_t younger_related_peg_rev,
+                  const char *older_repos_relpath,
+                  svn_revnum_t older_peg_rev,
+                  svn_client_conflict_t *conflict,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
+{
+  const char *repos_root_url;
+  const char *related_url;
+  const char *corrected_url;
+  svn_node_kind_t related_node_kind;
+  svn_ra_session_t *ra_session;
+
+  *related_repos_relpath = NULL;
+  *related_peg_rev = SVN_INVALID_REVNUM;
+
+  SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL,
+                                             conflict,
+                                             scratch_pool, scratch_pool));
+  related_url = svn_path_url_add_component2(repos_root_url,
+                                            younger_related_repos_relpath,
+                                            scratch_pool);
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session,
+                                               &corrected_url,
+                                               related_url, NULL,
+                                               NULL,
+                                               FALSE,
+                                               FALSE,
+                                               ctx,
+                                               scratch_pool,
+                                               scratch_pool));
+  SVN_ERR(svn_ra_check_path(ra_session, "", younger_related_peg_rev,
+                            &related_node_kind, scratch_pool));
+  if (related_node_kind == svn_node_none)
+    {
+      svn_revnum_t related_deleted_rev;
+      const char *related_deleted_rev_author;
+      svn_node_kind_t related_replacing_node_kind;
+      const char *related_basename;
+      const char *related_parent_repos_relpath;
+      apr_array_header_t *related_moves;
+
+      /* Looks like the younger node, which we'd like to use as our
+       * 'related node', was deleted. Try to find its deleted revision
+       *  so we can calculate a peg revision at which it exists.
+       * The younger node is related to the older node, so we can use
+       * the older node to guide us in our search. */
+      related_basename = svn_relpath_basename(younger_related_repos_relpath,
+                                              scratch_pool);
+      related_parent_repos_relpath =
+        svn_relpath_dirname(younger_related_repos_relpath, scratch_pool);
+      SVN_ERR(find_revision_for_suspected_deletion(
+                &related_deleted_rev, &related_deleted_rev_author,
+                &related_replacing_node_kind, &related_moves,
+                conflict, related_basename,
+                related_parent_repos_relpath,
+                younger_related_peg_rev, 0,
+                older_repos_relpath, older_peg_rev,
+                ctx, conflict->pool, scratch_pool));
+
+      /* If we can't find a related node, bail. */
+      if (related_deleted_rev == SVN_INVALID_REVNUM)
+        return SVN_NO_ERROR;
+
+      /* The node should exist in the revision before it was deleted. */
+      *related_repos_relpath = younger_related_repos_relpath;
+      *related_peg_rev = rev_below(related_deleted_rev);
+    }
+  else
+    {
+      *related_repos_relpath = younger_related_repos_relpath;
+      *related_peg_rev = younger_related_peg_rev;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Implements tree_conflict_get_details_func_t. */
 static svn_error_t *
 conflict_tree_get_details_local_missing(svn_client_conflict_t *conflict,
@@ -1588,78 +1670,19 @@ conflict_tree_get_details_local_missing(
   /* Make sure we're going to search the related node in a revision where
    * it exists. The younger incoming node might have been deleted in HEAD. */
   if (related_repos_relpath != NULL && related_peg_rev != SVN_INVALID_REVNUM)
-    {
-      const char *repos_root_url;
-      const char *related_url;
-      const char *corrected_url;
-      svn_node_kind_t related_node_kind;
-      svn_ra_session_t *ra_session;
-
-      SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL,
-                                                 conflict,
-                                                 scratch_pool, scratch_pool));
-      related_url = svn_path_url_add_component2(repos_root_url,
-                                                related_repos_relpath,
-                                                scratch_pool);
-      SVN_ERR(svn_client__open_ra_session_internal(&ra_session,
-                                                   &corrected_url,
-                                                   related_url, NULL,
-                                                   NULL,
-                                                   FALSE,
-                                                   FALSE,
-                                                   ctx,
-                                                   scratch_pool,
-                                                   scratch_pool));
-      SVN_ERR(svn_ra_check_path(ra_session, "", related_peg_rev,
-                                &related_node_kind, scratch_pool));
-      if (related_node_kind == svn_node_none)
-        {
-          svn_revnum_t related_deleted_rev;
-          const char *related_deleted_rev_author;
-          svn_node_kind_t related_replacing_node_kind;
-          const char *related_basename;
-          const char *related_parent_repos_relpath;
-          apr_array_header_t *related_moves;
-          const char *older_incoming_repos_relpath;
-          svn_revnum_t older_incoming_peg_rev;
-
-          /* Looks like the younger incoming node, which we'd like to use as
-           * our 'related node', was also deleted. Try to find its deleted
-           * revision so we can calculate a peg revision at which it exists.
-           * The younger incoming node is related to the older incoming node,
-           * so we can use the older incoming node to guide us in our search. */
-          related_basename = svn_relpath_basename(related_repos_relpath,
-                                                  scratch_pool);
-          related_parent_repos_relpath =
-            svn_relpath_dirname(related_repos_relpath, scratch_pool);
-          older_incoming_repos_relpath =
-                    (old_rev < new_rev ? old_repos_relpath : new_repos_relpath);
-          older_incoming_peg_rev = (old_rev < new_rev ? old_rev : new_rev);
-          SVN_ERR(find_revision_for_suspected_deletion(
-                    &related_deleted_rev, &related_deleted_rev_author,
-                    &related_replacing_node_kind, &related_moves,
-                    conflict, related_basename,
-                    related_parent_repos_relpath,
-                    old_rev < new_rev ? new_rev : old_rev, 0,
-                    older_incoming_repos_relpath, older_incoming_peg_rev,
-                    ctx, conflict->pool, scratch_pool));
-
-          /* If we can't find a related node, bail. */
-          if (related_deleted_rev == SVN_INVALID_REVNUM)
-            return SVN_NO_ERROR;
-
-          /* The node should exist in the revision before it was deleted. */
-          related_peg_rev = rev_below(related_deleted_rev);
-        }
-    }
+    SVN_ERR(find_related_node(
+              &related_repos_relpath, &related_peg_rev,
+              related_repos_relpath, related_peg_rev,
+              (old_rev < new_rev ? old_repos_relpath : new_repos_relpath),
+              (old_rev < new_rev ? old_rev : new_rev),
+              conflict, ctx, scratch_pool, scratch_pool));
     
   SVN_ERR(find_revision_for_suspected_deletion(
             &deleted_rev, &deleted_rev_author, &replacing_node_kind, &moves,
             conflict, deleted_basename, parent_repos_relpath,
             old_rev < new_rev ? new_rev : old_rev, 0,
-            related_repos_relpath,
-            related_peg_rev, ctx,
-            conflict->pool, scratch_pool));
+            related_repos_relpath, related_peg_rev,
+            ctx, conflict->pool, scratch_pool));
 
   if (deleted_rev == SVN_INVALID_REVNUM)
     return SVN_NO_ERROR;
@@ -3509,14 +3532,16 @@ conflict_tree_get_details_incoming_delet
   const char *repos_root_url;
   svn_revnum_t old_rev;
   svn_revnum_t new_rev;
+  svn_node_kind_t old_kind;
+  svn_node_kind_t new_kind;
   struct conflict_tree_incoming_delete_details *details;
   svn_wc_operation_t operation;
 
   SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(
-            &old_repos_relpath, &old_rev, NULL, conflict, scratch_pool,
+            &old_repos_relpath, &old_rev, &old_kind, conflict, scratch_pool,
             scratch_pool));
   SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(
-            &new_repos_relpath, &new_rev, NULL, conflict, scratch_pool,
+            &new_repos_relpath, &new_rev, &new_kind, conflict, scratch_pool,
             scratch_pool));
   SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL,
                                              conflict,
@@ -3532,9 +3557,10 @@ conflict_tree_get_details_incoming_delet
           const char *deleted_rev_author;
           svn_node_kind_t replacing_node_kind;
           apr_array_header_t *moves;
+          const char *related_repos_relpath;
+          svn_revnum_t related_peg_rev;
 
           /* The update operation went forward in history. */
-
           SVN_ERR(svn_wc__node_get_repos_info(NULL, &parent_repos_relpath,
                                               NULL, NULL,
                                               ctx->wc_ctx,
@@ -3543,12 +3569,29 @@ conflict_tree_get_details_incoming_delet
                                                 scratch_pool),
                                               scratch_pool,
                                               scratch_pool));
+          if (new_kind == svn_node_none)
+            {
+              SVN_ERR(find_related_node(&related_repos_relpath,
+                                        &related_peg_rev,
+                                        new_repos_relpath, new_rev,
+                                        old_repos_relpath, old_rev,
+                                        conflict, ctx,
+                                        scratch_pool, scratch_pool));
+            }
+          else
+            {
+              /* related to self */
+              related_repos_relpath = NULL;
+              related_peg_rev = SVN_INVALID_REVNUM;
+            }
+
           SVN_ERR(find_revision_for_suspected_deletion(
                     &deleted_rev, &deleted_rev_author, &replacing_node_kind,
                     &moves, conflict,
                     svn_dirent_basename(conflict->local_abspath, scratch_pool),
-                    parent_repos_relpath, new_rev, old_rev,
-                    NULL, SVN_INVALID_REVNUM, /* related to self */
+                    parent_repos_relpath,
+                    new_rev, new_kind == svn_node_none ? 0 : old_rev,
+                    related_repos_relpath, related_peg_rev,
                     ctx, conflict->pool, scratch_pool));
           if (deleted_rev == SVN_INVALID_REVNUM)
             {