You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Philip Martin <ph...@codematters.co.uk> on 2002/07/25 23:44:05 UTC

Re: diff and merge behaviour [PATCH]

Ben Collins-Sussman <su...@collab.net> writes:

> Branko Čibej <br...@xbc.nu> writes:
> 
> >    1. During the merge, several new files that had appeared on /trunk
> >       were added to my WC. Well and good; _but_ they were added without
> >       ancestry, creating a new node. I submit that "svn merge" should
> >       actually perform a copy when adding or replacing files; this would
> >       let diff avoid the weirdness I describe below.
> 
> Wow, that's a really great idea.  I can't believe we never thought of
> this before.  Can you file an enhancement request for this?

How about this?  It might not be very efficient, when using ra_dav
calling svn_client_copy will open another session, and but it works.
Is it worth commiting in its present form, in order to get the new
behaviour?  As usual I had problems writing the Python test :-(

Copy-with-history when adding new files and directories during a merge.

* subversion/libsvn_client/diff.c
  (struct merge_cmd_baton): Add target, path, revision and auth_baton
  members.
  (merge_file_added, merge_dir_added): Use svn_client_copy instead of
  svn_client_add.
  (svn_client_merge): Set new members in merge_cmd_baton.

* subversion/tests/clients/cmdline/merge_tests.py
  (add_with_history): New test.



Index: ./subversion/libsvn_client/diff.c
===================================================================
--- ./subversion/libsvn_client/diff.c
+++ ./subversion/libsvn_client/diff.c	Fri Jul 26 00:10:58 2002
@@ -279,6 +279,10 @@
 
 struct merge_cmd_baton {
   svn_boolean_t force;
+  const char *target;
+  const char *path;
+  const svn_client_revision_t *revision;
+  svn_client_auth_baton_t *auth_baton;
   apr_pool_t *pool;
 };
 
@@ -347,13 +351,20 @@
   struct merge_cmd_baton *merge_b = baton;
   apr_pool_t *subpool = svn_pool_create (merge_b->pool);
   enum svn_node_kind kind;
+  const char *copyfrom_url;
+  const char *child;
 
   SVN_ERR (svn_io_check_path (mine, &kind, subpool));
   switch (kind)
     {
     case svn_node_none:
-      SVN_ERR (svn_io_copy_file (yours, mine, TRUE, subpool));
-      SVN_ERR (svn_client_add (mine, FALSE, NULL, NULL, subpool));      
+      child = svn_path_is_child(merge_b->target, mine, merge_b->pool);
+      assert (child != NULL);
+      copyfrom_url = svn_path_join (merge_b->path, child, merge_b->pool);
+      /* ### This will get the file again */
+      SVN_ERR (svn_client_copy (NULL, copyfrom_url, merge_b->revision, mine,
+                                merge_b->auth_baton, NULL, NULL, NULL, NULL,
+                                merge_b->pool));
       break;
     case svn_node_dir:
       /* ### create a .drej conflict or something someday? */
@@ -443,13 +454,19 @@
   apr_pool_t *subpool = svn_pool_create (merge_b->pool);
   enum svn_node_kind kind;
   svn_wc_entry_t *entry;
+  const char *copyfrom_url, *child;
 
   SVN_ERR (svn_io_check_path (path, &kind, subpool));
   switch (kind)
     {
     case svn_node_none:
-      SVN_ERR (svn_client_mkdir (NULL, path, NULL, NULL, NULL,
-                                 NULL, NULL, subpool));
+      child = svn_path_is_child (merge_b->target, path, merge_b->pool);
+      assert (child != NULL);
+      copyfrom_url = svn_path_join (merge_b->path, child, merge_b->pool);
+      /* ### This will get the directory tree again */
+      SVN_ERR (svn_client_copy (NULL, copyfrom_url, merge_b->revision, path,
+                                merge_b->auth_baton, NULL, NULL, NULL, NULL,
+                                merge_b->pool));
       break;
     case svn_node_dir:
       /* ### should unversioned directories generate 'obstructed update'
@@ -1254,6 +1271,10 @@
     {
       struct merge_cmd_baton merge_cmd_baton;
       merge_cmd_baton.force = force;
+      merge_cmd_baton.target = target_wcpath;
+      merge_cmd_baton.path = path2;
+      merge_cmd_baton.revision = revision2;
+      merge_cmd_baton.auth_baton = auth_baton;
       merge_cmd_baton.pool = pool;
 
       SVN_ERR (do_merge (notify_func,
Index: ./subversion/tests/clients/cmdline/merge_tests.py
===================================================================
--- ./subversion/tests/clients/cmdline/merge_tests.py
+++ ./subversion/tests/clients/cmdline/merge_tests.py	Thu Jul 25 23:48:52 2002
@@ -366,6 +366,115 @@
 
 #----------------------------------------------------------------------
 
+def add_with_history(sbox):
+  "merge and add new files/dirs with history"
+
+  if sbox.build():
+    return 1
+
+  wc_dir = sbox.wc_dir
+
+  C_path = os.path.join(wc_dir, 'A', 'C')
+  F_path = os.path.join(wc_dir, 'A', 'B', 'F')
+  F_url = os.path.join(svntest.main.current_repo_url, 'A', 'B', 'F')
+  Q_path = os.path.join(F_path, 'Q')
+  svntest.main.run_svn(None, 'mkdir', Q_path)
+  foo_path = os.path.join(F_path, 'foo')
+  svntest.main.file_append(foo_path, "foo")
+  svntest.main.run_svn(None, 'add', foo_path)
+  bar_path = os.path.join(Q_path, 'bar')
+  svntest.main.file_append(bar_path, "bar")
+  svntest.main.run_svn(None, 'add', bar_path)
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/F/Q'     : Item(verb='Adding'),
+    'A/B/F/Q/bar' : Item(verb='Adding'),
+    'A/B/F/foo'   : Item(verb='Adding'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak(wc_rev=1)
+  expected_status.add({
+    'A/B/F/Q'     : Item(status='_ ', wc_rev=2, repos_rev=2),
+    'A/B/F/Q/bar' : Item(status='_ ', wc_rev=2, repos_rev=2),
+    'A/B/F/foo'   : Item(status='_ ', wc_rev=2, repos_rev=2),
+    })
+  if svntest.actions.run_and_verify_commit(wc_dir,
+                                           expected_output,
+                                           expected_status, 
+                                           None,
+                                           None, None,
+                                           None, None,
+                                           wc_dir):
+    print "commit failed"
+    return 1
+
+### I give up, what is the magic incantation to get this to work?
+#
+#  expected_output = wc.State(C_path, {'Q'      : Item(status='A '),
+#                                      'Q/bar'  : Item(status='A '),
+#                                      'foo'    : Item(status='A '),
+#                                      })
+#
+#  expected_disk = wc.State(C_path, {'Q'       : wc.StateItem(),
+#                                    'Q/bar'   : wc.StateItem("bar"),
+#                                    'foo'     : wc.StateItem("foo"),
+#                                    })
+# 
+#  expected_status= wc.State(C_path, {
+#    'Q'   : Item(status='A ', wc_rev='-', copied='+', repos_rev=2),
+#    'foo' : Item(status='A ', wc_rev='-', copied='+', repos_rev=2),
+#    })
+#
+#  if svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url,
+#                                          expected_output,
+#                                          expected_disk,
+#                                          expected_status):
+#    print "merge failed"
+#    return 1
+
+  out,err = svntest.main.run_svn(None, 'merge', '-r1:2', F_url, C_path)
+  if (not re.match("^A.*/A/C/Q$", out[0])
+      or not re.match("^A.*/A/C/Q/bar$", out[1])
+      or not re.match("^A.*/A/C/foo$", out[2])):
+    print "merge failed"
+    return 1
+
+### Can't get this to work either.
+#
+#  expected_status.add({
+#    'A/C/Q'       : Item(status='A ', wc_rev='-', copied='+', repos_rev='2'),
+#    'A/C/Q/bar'   : Item(status='A ', wc_rev='-', copied='+', repos_rev='2'),
+#    'A/C/foo'     : Item(status='A ', wc_rev='-', copied='+', repos_rev='2'),
+#    })
+#  if svntest.actions.run_and_verify_status(wc_dir, expected_status):
+#    print "status failed"
+#    return 1
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/C/Q'     : Item(verb='Adding'),
+    'A/C/foo'   : Item(verb='Adding'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+  expected_status.tweak(wc_rev=1)
+  expected_status.add({
+    'A/B/F/Q'     : Item(status='_ ', wc_rev=2, repos_rev=3),
+    'A/B/F/Q/bar' : Item(status='_ ', wc_rev=2, repos_rev=3),
+    'A/B/F/foo'   : Item(status='_ ', wc_rev=2, repos_rev=3),
+    'A/C/Q'       : Item(status='_ ', wc_rev=3, repos_rev=3),
+    'A/C/Q/bar'   : Item(status='_ ', wc_rev=3, repos_rev=3),
+    'A/C/foo'     : Item(status='_ ', wc_rev=3, repos_rev=3),
+    })
+  if svntest.actions.run_and_verify_commit(wc_dir,
+                                           expected_output,
+                                           expected_status, 
+                                           None,
+                                           None, None,
+                                           None, None,
+                                           wc_dir):
+    print "commit of merge failed"
+    return 1
+
+#----------------------------------------------------------------------
 
 ########################################################################
 # Run the tests
@@ -374,6 +483,7 @@
 # list all tests here, starting with None:
 test_list = [ None,
               textual_merges_galore,
+              add_with_history,
               # property_merges_galore,  # Would be nice to have this.
               # tree_merges_galore,      # Would be nice to have this.
               # various_merges_galore,   # Would be nice to have this.


-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: diff and merge behaviour [PATCH]

Posted by Branko Čibej <br...@xbc.nu>.
Ben Collins-Sussman wrote:

>Philip Martin <ph...@codematters.co.uk> writes:
>
>  
>
>>How about this?  It might not be very efficient, when using ra_dav
>>calling svn_client_copy will open another session, and but it works.
>>    
>>
>
>Ah, I see that instead of the merge process calling svn_client_add(),
>you're now having it call svn_client_copy(URL, wc-path).
>
>I have a simpler proposal though:  you already *have* the file, and
>already know the copyfrom-path and copyfrom-rev.  So go ahead and
>svn_client_add() the new file... and then tweak the entry, inserting
>the copyfrom* args.  Voila, no network access, same result.  :-)
>  
>

+1, this is exactly what should be happening.


-- 
Brane Čibej   <br...@xbc.nu>   http://www.xbc.nu/brane/


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: diff and merge behaviour [PATCH]

Posted by Ben Collins-Sussman <su...@collab.net>.
Philip Martin <ph...@codematters.co.uk> writes:

> How about this?  It might not be very efficient, when using ra_dav
> calling svn_client_copy will open another session, and but it works.

Ah, I see that instead of the merge process calling svn_client_add(),
you're now having it call svn_client_copy(URL, wc-path).

I have a simpler proposal though:  you already *have* the file, and
already know the copyfrom-path and copyfrom-rev.  So go ahead and
svn_client_add() the new file... and then tweak the entry, inserting
the copyfrom* args.  Voila, no network access, same result.  :-)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org