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 2011/07/29 16:48:19 UTC

svn commit: r1152245 - in /subversion/trunk/subversion: libsvn_client/commit.c libsvn_wc/wc_db.c

Author: stsp
Date: Fri Jul 29 14:48:18 2011
New Revision: 1152245

URL: http://svn.apache.org/viewvc?rev=1152245&view=rev
Log:
Update moved-to information on the BASE path of a node which is being moved
out of, or within, an existing moved subtree. Also, make 'svn commit' deal
with the add-half of such moves correctly.

* subversion/libsvn_wc/wc_db.c
  (op_delete_txn): If the node was moved-here and we are moving it away,
   we always want to update moved-to in BASE, regardless of whether the node
   itself was the op-root of the move that moved it here. Prior to this
   commit, we only updated moved-to if the node itself was the op-root.

* subversion/libsvn_client/commit.c
  (svn_client_commit5): If the delete-half of a move is not in the
   commit target list, look up the op-root of the delete and check
   if the op-root is among the commit targets. If it is, the delete-half
   of the move will be committed along with it, and we can allow the commit.

Modified:
    subversion/trunk/subversion/libsvn_client/commit.c
    subversion/trunk/subversion/libsvn_wc/wc_db.c

Modified: subversion/trunk/subversion/libsvn_client/commit.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/commit.c?rev=1152245&r1=1152244&r2=1152245&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/commit.c (original)
+++ subversion/trunk/subversion/libsvn_client/commit.c Fri Jul 29 14:48:18 2011
@@ -1379,19 +1379,72 @@ svn_client_commit5(const apr_array_heade
             goto cleanup;
 
           if (moved_from_abspath && delete_op_root_abspath &&
-              strcmp(moved_from_abspath, delete_op_root_abspath) == 0 &&
-              apr_hash_get(committables->by_path, delete_op_root_abspath,
-                           APR_HASH_KEY_STRING) == NULL)
+              strcmp(moved_from_abspath, delete_op_root_abspath) == 0)
+
             {
-              cmt_err = svn_error_createf(
-                          SVN_ERR_ILLEGAL_TARGET, NULL,
-                          _("Cannot commit '%s' because it was moved from "
-                            "'%s' which is not part of the commit; both "
-                            "sides of the move must be committed together"),
-                          svn_dirent_local_style(item->path, iterpool),
-                          svn_dirent_local_style(delete_op_root_abspath,
-                                                 iterpool));
-              goto cleanup;
+              svn_boolean_t found_delete_half =
+                (apr_hash_get(committables->by_path, delete_op_root_abspath,
+                               APR_HASH_KEY_STRING) != NULL);
+              
+              if (!found_delete_half)
+                {
+                  const char *delete_half_parent_abspath;
+
+                  /* The delete-half isn't in the commit target list.
+                   * However, it might itself be the child of a deleted node,
+                   * either because of another move or a deletion.
+                   *
+                   * For example, consider: mv A/B B; mv B/C C; commit;
+                   * C's moved-from A/B/C is a child of the deleted A/B.
+                   * A/B/C does not appear in the commit target list, but
+                   * A/B does appear.
+                   * (Note that moved-from information is always stored
+                   * relative to the BASE tree, so we have 'C moved-from
+                   * A/B/C', not 'C moved-from B/C'.)
+                   *
+                   * An example involving a move and a delete would be:
+                   * mv A/B C; rm A; commit;
+                   * Now C is moved-from A/B which does not appear in the
+                   * commit target list, but A does appear.
+                   */
+
+                  /* Scan upwards for a deletion op-root from the
+                   * delete-half's parent directory. */
+                  delete_half_parent_abspath =
+                    svn_dirent_dirname(delete_op_root_abspath, iterpool);
+                  if (strcmp(delete_op_root_abspath,
+                             delete_half_parent_abspath) != 0)
+                    {
+                      const char *parent_delete_op_root_abspath;
+
+                      cmt_err = svn_error_trace(
+                                  svn_wc__node_get_deleted_ancestor(
+                                    &parent_delete_op_root_abspath,
+                                    ctx->wc_ctx, delete_half_parent_abspath,
+                                    iterpool, iterpool));
+                      if (cmt_err)
+                        goto cleanup;
+
+                      if (parent_delete_op_root_abspath)
+                        found_delete_half =
+                          (apr_hash_get(committables->by_path,
+                                        parent_delete_op_root_abspath,
+                                        APR_HASH_KEY_STRING) != NULL);
+                    }
+                }
+
+              if (!found_delete_half)
+                {
+                  cmt_err = svn_error_createf(
+                              SVN_ERR_ILLEGAL_TARGET, NULL,
+                              _("Cannot commit '%s' because it was moved from "
+                                "'%s' which is not part of the commit; both "
+                                "sides of the move must be committed together"),
+                              svn_dirent_local_style(item->path, iterpool),
+                              svn_dirent_local_style(delete_op_root_abspath,
+                                                     iterpool));
+                  goto cleanup;
+                }
             }
         }
       /* ### TODO: check the delete-half, too */

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1152245&r1=1152244&r2=1152245&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Fri Jul 29 14:48:18 2011
@@ -6070,21 +6070,19 @@ op_delete_txn(void *baton,
   if (b->moved_to_relpath)
     {
       const char *moved_from_relpath;
-      const char *delete_op_root_relpath;
 
       /* ### call scan_addition_txn() directly? */
       if (status == svn_wc__db_status_added)
         SVN_ERR(scan_addition(&status, NULL, NULL, NULL,
                               NULL, NULL, NULL,
-                              &moved_from_relpath,
-                              &delete_op_root_relpath,
+                              &moved_from_relpath, NULL,
                               wcroot, local_relpath,
                               scratch_pool, scratch_pool));
 
-      if (status == svn_wc__db_status_moved_here &&
-          strcmp(moved_from_relpath, delete_op_root_relpath) == 0)
+      if (status == svn_wc__db_status_moved_here)
         {
-          /* The node has already been moved and is being moved again.
+          /* The node has already been moved, possibly along with a parent,
+           * and is being moved again.
            * Update the existing moved_to path at the delete-half of
            * the prior move. The source of a move is in the BASE tree
            * so it remains constant if a node is moved around multiple