You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/10/30 00:41:12 UTC

svn commit: r1536931 - in /subversion/trunk/subversion: libsvn_client/commit_util.c tests/cmdline/merge_tests.py tests/libsvn_wc/op-depth-test.c

Author: rhuijben
Date: Tue Oct 29 23:41:12 2013
New Revision: 1536931

URL: http://svn.apache.org/r1536931
Log:
Fix a commit problem for copies of mixed revision trees, by properly detecting
when 'adds' on top of a not present node should really be committed as
replacement, just like how we already handled unmodified not present
descendants.

The specific testcase in op-depth-tests didn't trigger the automatic
replacement behavior in libsvn_repos/commit.c add_file_or_directory() as
in this case the new node was not a copy (which has this behavior),
but a plain add (which has not).

This fix makes the client commit both the copy and the plain add case
explicitly without relying on the automatic replacement behavior.

* subversion/libsvn_client/commit_util.c
  (handle_descendants): Properly handle not-present descendants of a copy that
    already have some other committable modification registered.

* subversion/tests/cmdline/merge_tests.py
  (merge_binary_with_common_ancestry): Update expected commit notification for
    a mixed revision copy. (The add was already committed as a replacement by
    the magic in libsvn_repos/commit.c)

* subversion/tests/libsvn_wc/op-depth-test.c
  (test_funcs): Remove XFail marker from copy_mixed_rev_mods.

Modified:
    subversion/trunk/subversion/libsvn_client/commit_util.c
    subversion/trunk/subversion/tests/cmdline/merge_tests.py
    subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c

Modified: subversion/trunk/subversion/libsvn_client/commit_util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/commit_util.c?rev=1536931&r1=1536930&r2=1536931&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/commit_util.c (original)
+++ subversion/trunk/subversion/libsvn_client/commit_util.c Tue Oct 29 23:41:12 2013
@@ -1005,18 +1005,64 @@ handle_descendants(void *baton,
       for (j = 0; j < absent_descendants->nelts; j++)
         {
           svn_node_kind_t kind;
+          svn_client_commit_item3_t *desc_item;
           const char *relpath = APR_ARRAY_IDX(absent_descendants, j,
                                               const char *);
           const char *local_abspath = svn_dirent_join(item->path, relpath,
                                                       iterpool);
 
-          /* If the path has a commit operation, we do nothing.
-             (It will be deleted by the operation) */
-          if (svn_hash_gets(hdb->committables->by_path, local_abspath))
-            continue; /* We have an explicit delete or replace for this path */
-
           /* ### Need a sub-iterpool? */
 
+
+          /* We found a 'not present' descendant during a copy (at op_depth>0),
+             this is most commonly caused by copying some mixed revision tree.
+
+             In this case not present can imply that the node does not exist
+             in the parent revision, or that the node does. But we want to copy
+             the working copy state in which it does not exist, but might be
+             replaced. */
+
+          desc_item = svn_hash_gets(hdb->committables->by_path, local_abspath);
+
+          /* If the path has a commit operation (possibly at an higher
+             op_depth, we might want to turn an add in a replace. */
+          if (desc_item)
+            {
+              const char *dir;
+              svn_boolean_t found_intermediate = FALSE;
+
+              if (desc_item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
+                continue; /* We already have a delete or replace */
+              else if (!(desc_item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
+                continue; /* Not a copy/add, just a modification */
+
+              dir = svn_dirent_dirname(local_abspath, iterpool);
+
+              while (strcmp(dir, item->path))
+                {
+                  svn_client_commit_item3_t *i_item;
+
+                  i_item = svn_hash_gets(hdb->committables->by_path, dir);
+
+                  if (i_item)
+                    {
+                      if ((i_item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
+                          || (i_item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
+                        {
+                          found_intermediate = TRUE;
+                          break;
+                        }
+                    }
+                  dir = svn_dirent_dirname(dir, iterpool);
+                }
+
+              if (found_intermediate)
+                continue; /* Some intermediate ancestor is an add or delete */
+
+              /* Fall through to detect if we need to turn the add in a
+                 replace. */
+            }
+
           if (hdb->check_url_func)
             {
               const char *from_url = svn_path_url_add_component2(
@@ -1033,6 +1079,13 @@ handle_descendants(void *baton,
           else
             kind = svn_node_unknown; /* 'Ok' for a delete of something */
 
+          if (desc_item)
+            {
+              /* Extend the existing add/copy item to create a replace */
+              desc_item->state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE;
+              continue;
+            }
+
           /* Add a new commit item that describes the delete */
 
           SVN_ERR(add_committable(hdb->committables,

Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=1536931&r1=1536930&r2=1536931&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Tue Oct 29 23:41:12 2013
@@ -1977,7 +1977,7 @@ def merge_binary_with_common_ancestry(sb
   # Commit the second branch
   expected_output = wc.State(wc_dir, {
     'L'       : Item(verb='Adding'),
-    'L/theta' : Item(verb='Adding  (bin)'),
+    'L/theta' : Item(verb='Replacing'),
     })
 
   expected_status.add({

Modified: subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c?rev=1536931&r1=1536930&r2=1536931&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Tue Oct 29 23:41:12 2013
@@ -8908,7 +8908,7 @@ struct svn_test_descriptor_t test_funcs[
                        "update with tree conflict (issue 4347)"),
     SVN_TEST_OPTS_PASS(move_update_parent_replace,
                        "move update with replaced parent (issue 4388)"),
-    SVN_TEST_OPTS_XFAIL(copy_mixed_rev_mods,
+    SVN_TEST_OPTS_PASS(copy_mixed_rev_mods,
                        "copy mixed-rev with mods"),
     SVN_TEST_OPTS_PASS(move_child_to_parent_revert,
                        "move child to parent and revert (issue 4436)"),