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/12/19 14:39:15 UTC

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

Author: stsp
Date: Mon Dec 19 14:39:14 2016
New Revision: 1775111

URL: http://svn.apache.org/viewvc?rev=1775111&view=rev
Log:
Tweak the way the conflict resolver discovers nested moves.

This is no functional change. The effective change is that the resolver now
builds an internal list of moves which includes all nested moves found in
each revision. Previously it was adding just one particular nested move to
the list of moves, a nested move which was deemed to apply to the conflict
victim. So we now discover the full list which includes all nested moves,
and then search that list.

* subversion/libsvn_client/conflicts.c
  (map_deleted_path_to_move): Make this function recurse. If possible this
   function now finds the effective move of a node which was moved along
   with its parent and then moved again (in the same revision).
  (find_nested_move): Rename to ...
  (find_nested_moves): .. this, and return a list of all nested moves found
   in the revision, instead of perhaps returning just one nested move which
   applies to the conflict victim.
  (find_deleted_rev): Build a full list of moves in the current revision,
   including all nested ones. Then look the deleted node up in this list.

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=1775111&r1=1775110&r2=1775111&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Mon Dec 19 14:39:14 2016
@@ -626,10 +626,7 @@ map_deleted_path_to_move(const char *del
           /* This could be a nested move. Return the path-wise closest move. */
           int c = svn_path_component_count(relpath);
           if (c == 0)
-            {
-              closest_move = move;
-              break;
-            }
+             return move;
           else if (min_components == 0 || c < min_components)
             {
               min_components = c;
@@ -638,31 +635,49 @@ map_deleted_path_to_move(const char *del
         }
     }
 
+  if (closest_move)
+    {
+      const char *relpath;
+      const char *moved_along_path;
+      struct repos_move_info *move;
+      
+      /* See if we can find an even closer move for this moved-along path. */
+      relpath = svn_relpath_skip_ancestor(closest_move->moved_to_repos_relpath,
+                                          deleted_relpath);
+      moved_along_path =
+        svn_relpath_join(closest_move->moved_from_repos_relpath, relpath,
+                         scratch_pool);
+      move = map_deleted_path_to_move(moved_along_path, moves, scratch_pool);
+      if (move)
+        return move;
+    }
+
   return closest_move;
 }
 
+/* Search for nested moves in REVISION, given the already found MOVES,
+ * all DELETED_PATHS, and all COPIES, from the same revision.
+ * Append any nested moves to the MOVES array. */
 static svn_error_t *
-find_nested_move(struct repos_move_info **nested_move,
-                 const char *deleted_repos_relpath,
-                 apr_array_header_t *moves,
-                 apr_hash_t *copies,
-                 apr_array_header_t *deleted_paths,
-                 svn_revnum_t revision,
-                 svn_string_t *author,
-                 const char *repos_root_url,
-                 const char *repos_uuid,
-                 svn_ra_session_t *ra_session,
-                 svn_client_ctx_t *ctx,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
+find_nested_moves(apr_array_header_t *moves,
+                  apr_hash_t *copies,
+                  apr_array_header_t *deleted_paths,
+                  apr_hash_t *moved_paths,
+                  svn_revnum_t revision,
+                  svn_string_t *author,
+                  const char *repos_root_url,
+                  const char *repos_uuid,
+                  svn_ra_session_t *ra_session,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
+  apr_array_header_t *nested_moves;
   int i;
   apr_pool_t *iterpool;
-  struct copy_info *move_destination = NULL;
-  const char *moved_from_repos_relpath = NULL;
-
-  *nested_move = NULL;
 
+  nested_moves = apr_array_make(result_pool, 0,
+                                sizeof(struct repos_move_info *));
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < deleted_paths->nelts; i++)
     {
@@ -680,9 +695,8 @@ find_nested_move(struct repos_move_info
       move = map_deleted_path_to_move(deleted_path, moves, iterpool);
       if (move == NULL)
         continue;
-
       child_relpath = svn_relpath_skip_ancestor(move->moved_to_repos_relpath,
-                                                deleted_repos_relpath);
+                                                deleted_path);
       if (child_relpath == NULL || child_relpath[0] == '\0')
         continue; /* not a nested move */
 
@@ -710,35 +724,65 @@ find_nested_move(struct repos_move_info
                                   copy->copyfrom_path,
                                   copy->copyfrom_rev,
                                   TRUE, iterpool));
-
       if (related)
         {
-          moved_from_repos_relpath =
+          struct repos_move_info *nested_move;
+          struct repos_move_info *next_move;
+
+          /* Remember details of this move. */
+          nested_move = apr_pcalloc(result_pool, sizeof(*nested_move));
+          nested_move->moved_from_repos_relpath =
             apr_pstrdup(result_pool, moved_along_repos_relpath);
-          move_destination = copy;
-          break;
-        }
-    }
-  svn_pool_destroy(iterpool);
+          nested_move->moved_to_repos_relpath = apr_pstrdup(result_pool,
+                                                            copy->copyto_path);
+          nested_move->rev = revision;
+          nested_move->rev_author = apr_pstrdup(result_pool, author->data);
+          nested_move->copyfrom_rev = copy->copyfrom_rev;
+
+          /* Link together multiple moves of the same node.
+           * Note that we're traversing history backwards, so moves already
+           * present in the list happened in younger revisions. */
+          next_move = svn_hash_gets(moved_paths, move->moved_to_repos_relpath);
+          if (next_move)
+            {
+              /* Tracing back history of the delete-half of the next move
+               * to the copyfrom-revision of the prior move we must end up
+               * at the delete-half of the prior move. */
+              SVN_ERR(check_move_ancestry(&related, ra_session, repos_root_url,
+                                          next_move->moved_from_repos_relpath,
+                                          next_move->rev,
+                                          nested_move->moved_from_repos_relpath,
+                                          nested_move->copyfrom_rev,
+                                          FALSE, iterpool));
+              if (related)
+                {
+                  SVN_ERR_ASSERT(nested_move->rev < next_move->rev);
 
-  if (moved_from_repos_relpath && move_destination)
-    {
-      struct repos_move_info *move;
+                  /* Prepend this move to the linked list. */
+                  if (nested_move->next == NULL)
+                    nested_move->next =
+                      apr_array_make(result_pool, 1,
+                                     sizeof (struct repos_move_info *));
+                  APR_ARRAY_PUSH(nested_move->next,
+                                 struct repos_move_info *) = next_move;
+                  next_move->prev = nested_move;
+                }
+            }
 
-      /* Remember details of this move. */
-      move = apr_pcalloc(result_pool, sizeof(*move));
-      move->moved_from_repos_relpath = moved_from_repos_relpath;
-      move->moved_to_repos_relpath =
-        apr_pstrdup(result_pool,
-                    move_destination->copyto_path);
-      move->rev = revision;
-      move->rev_author = apr_pstrdup(result_pool, author->data);
-      move->copyfrom_rev = move_destination->copyfrom_rev;
+          /* Make this move the head of our next-move linking map. */
+          svn_hash_sets(moved_paths, nested_move->moved_from_repos_relpath,
+                        nested_move);
 
-      APR_ARRAY_PUSH(moves, struct repos_move_info *) = move;
-      *nested_move = move;
+          /* Add this move to the list of nested moves in this revision. */
+          APR_ARRAY_PUSH(nested_moves, struct repos_move_info *) = nested_move;
+        }
     }
 
+  svn_pool_destroy(iterpool);
+
+  /* Add all nested moves found to the list of all moves in this revision. */
+  apr_array_cat(moves, nested_moves);
+
   return SVN_NO_ERROR;
 }
 
@@ -900,22 +944,23 @@ find_deleted_rev(void *baton,
                            sizeof(svn_revnum_t));
       if (moves)
         {
-          struct repos_move_info *nested_move;
+          struct repos_move_info *move;
 
-          SVN_ERR(find_nested_move(&nested_move,
-                                   b->deleted_repos_relpath,
-                                   moves, copies, deleted_paths,
-                                   log_entry->revision,
-                                   svn_hash_gets(log_entry->revprops,
-                                                 SVN_PROP_REVISION_AUTHOR),
-                                   b->repos_root_url,
-                                   b->repos_uuid,
-                                   b->extra_ra_session, b->ctx,
-                                   b->result_pool, scratch_pool));
-          if (nested_move)
+          SVN_ERR(find_nested_moves(moves, copies, deleted_paths,
+                                    b->moved_paths, log_entry->revision,
+                                    svn_hash_gets(log_entry->revprops,
+                                                  SVN_PROP_REVISION_AUTHOR),
+                                    b->repos_root_url,
+                                    b->repos_uuid,
+                                    b->extra_ra_session, b->ctx,
+                                    b->result_pool, scratch_pool));
+          
+          move = map_deleted_path_to_move(b->deleted_repos_relpath,
+                                          moves, scratch_pool);
+          if (move)
             {
+              b->deleted_repos_relpath = move->moved_from_repos_relpath;
               deleted_node_found = TRUE;
-              b->deleted_repos_relpath = nested_move->moved_from_repos_relpath;
             }
         }
     }