Hi,

Attached is a completed patch to resolve issue 3686[1], where the executable
bit is not maintained during the merge of a binary file.

I thought about making this change more generic, and applying it to text
files as well (there was discussion with performance of simple-case merging
a month ago on users@), but thought I'd leave that for later. I didn't want
to worry about (potential) line-endings, keywords, etc. problems.

[[[
Fix issue #3686 - executable bit not set during merge.

The cause was the special case in libsvn_client, which bypassed the use of
the
workqueue. This logic has now been moved into libsvn_wc.

Additionally, this change allows the status of binary files (during a
dry-run
merge) to be reported correctly (previously, all binary files were reported
as
conflicted).

* subversion/libsvn_client/merge.c
 (merge_file_changed): Removed binary-merge special case (now in libsvn_wc).
   Removed merge_required variable (resulting in indentation changes).

* subversion/libsvn_wc/merge.c
 (merge_binary_file): Added dry_run parameter. Add the special case merging
  of binary files.

* subversion/tests/cmdline/merge_tests.py
 (merge_change_to_file_with_executable): Remove @XFail decorator.
]]]

[1]
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=463&dsMessageId=2635024

Cheers,
Daniel B.

---
Daniel Becroft
Index: subversion/tests/cmdline/merge_tests.py
===================================================================
--- subversion/tests/cmdline/merge_tests.py	(revision 1068136)
+++ subversion/tests/cmdline/merge_tests.py	(working copy)
@@ -16469,7 +16469,6 @@
 #----------------------------------------------------------------------
 # Test for issue #3686 'executable flag not correctly set on merge'
 # See http://subversion.tigris.org/issues/show_bug.cgi?id=3686
-@XFail()
 @Issue(3686)
 @SkipUnless(svntest.main.is_posix_os)
 def merge_change_to_file_with_executable(sbox):
Index: subversion/libsvn_wc/merge.c
===================================================================
--- subversion/libsvn_wc/merge.c	(revision 1068136)
+++ subversion/libsvn_wc/merge.c	(working copy)
@@ -1094,6 +1094,7 @@
                   const char *left_label,
                   const char *right_label,
                   const char *target_label,
+                  svn_boolean_t dry_run,
                   const svn_wc_conflict_version_t *left_version,
                   const svn_wc_conflict_version_t *right_version,
                   const char *detranslated_target_abspath,
@@ -1111,13 +1112,31 @@
   const char *merge_dirpath, *merge_filename;
   const char *conflict_wrk;
   svn_skel_t *work_item;
+  svn_boolean_t same_contents = FALSE;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
 
   *work_items = NULL;
 
   svn_dirent_split(&merge_dirpath, &merge_filename, target_abspath, pool);
+ 
+  /* Attempt to merge the binary file. At the moment, we can only 
+     handle the special case: if the LEFT side of the merge is equal
+     to WORKING, then we can copy RIGHT directly. */
+  SVN_ERR(svn_io_files_contents_same_p(&same_contents,
+                                      left_abspath,
+                                      target_abspath,
+                                      scratch_pool));
 
+  if (same_contents)
+    {
+      if (!dry_run)
+        SVN_ERR(svn_io_file_move(right_abspath, target_abspath,
+                                         scratch_pool));
+      *merge_outcome = svn_wc_merge_merged;
+      return SVN_NO_ERROR;
+    }
+
   /* Give the conflict resolution callback a chance to clean
      up the conflict before we mark the file 'conflicted' */
   if (conflict_func)
@@ -1357,26 +1376,23 @@
 
   if (is_binary)
     {
-      if (dry_run)
-        /* in dry-run mode, binary files always conflict */
-        *merge_outcome = svn_wc_merge_conflict;
-      else
-        SVN_ERR(merge_binary_file(work_items,
-                                  merge_outcome,
-                                  db,
-                                  left_abspath,
-                                  right_abspath,
-                                  target_abspath,
-                                  left_label,
-                                  right_label,
-                                  target_label,
-                                  left_version,
-                                  right_version,
-                                  detranslated_target_abspath,
-                                  mimeprop,
-                                  conflict_func,
-                                  conflict_baton,
-                                  result_pool, scratch_pool));
+      SVN_ERR(merge_binary_file(work_items,
+                                merge_outcome,
+                                db,
+                                left_abspath,
+                                right_abspath,
+                                target_abspath,
+                                left_label,
+                                right_label,
+                                target_label,
+                                dry_run,
+                                left_version,
+                                right_version,
+                                detranslated_target_abspath,
+                                mimeprop,
+                                conflict_func,
+                                conflict_baton,
+                                result_pool, scratch_pool));
     }
   else
     {
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1068136)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -1300,7 +1300,6 @@
 {
   merge_cmd_baton_t *merge_b = baton;
   apr_pool_t *subpool = svn_pool_create(merge_b->pool);
-  svn_boolean_t merge_required = TRUE;
   enum svn_wc_merge_outcome_t merge_outcome;
 
   SVN_ERR_ASSERT(mine_abspath && svn_dirent_is_absolute(mine_abspath));
@@ -1452,75 +1451,38 @@
       SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, merge_b->ctx->wc_ctx,
                                       mine_abspath, FALSE, subpool));
 
-      /* Special case:  if a binary file's working file is
-         exactly identical to the 'left' side of the merge, then don't
-         allow svn_wc_merge to produce a conflict.  Instead, just
-         overwrite the working file with the 'right' side of the
-         merge.  Why'd we check for local mods above?  Because we want
-         to do a different notification depending on whether or not
-         the file was locally modified.
+      /* xgettext: the '.working', '.merge-left.r%ld' and
+         '.merge-right.r%ld' strings are used to tag onto a file
+         name in case of a merge conflict */
+      const char *target_label = _(".working");
+      const char *left_label = apr_psprintf(subpool,
+                                            _(".merge-left.r%ld"),
+                                            older_rev);
+      const char *right_label = apr_psprintf(subpool,
+                                             _(".merge-right.r%ld"),
+                                             yours_rev);
+      conflict_resolver_baton_t conflict_baton = { 0 };
+      const svn_wc_conflict_version_t *left;
+      const svn_wc_conflict_version_t *right;
 
-         Alternately, if the 'left' side of the merge doesn't exist in
-         the repository, and the 'right' side of the merge is
-         identical to the WC, pretend we did the merge (a no-op). */
-      if ((mimetype1 && svn_mime_type_is_binary(mimetype1))
-          || (mimetype2 && svn_mime_type_is_binary(mimetype2)))
-        {
-          /* For adds, the 'left' side of the merge doesn't exist. */
-          svn_boolean_t older_revision_exists =
-              !merge_b->add_necessitated_merge;
-          svn_boolean_t same_contents;
-          SVN_ERR(svn_io_files_contents_same_p(&same_contents,
-                                               (older_revision_exists ?
-                                                older_abspath : yours_abspath),
-                                               mine_abspath, subpool));
-          if (same_contents)
-            {
-              if (older_revision_exists && !merge_b->dry_run)
-                {
-                  SVN_ERR(svn_io_file_move(yours_abspath, mine_abspath,
-                                           subpool));
-                }
-              merge_outcome = svn_wc_merge_merged;
-              merge_required = FALSE;
-            }
-        }
+      conflict_baton.wrapped_func = merge_b->ctx->conflict_func;
+      conflict_baton.wrapped_baton = merge_b->ctx->conflict_baton;
+      conflict_baton.conflicted_paths = &merge_b->conflicted_paths;
+      conflict_baton.pool = merge_b->pool;
 
-      if (merge_required)
-        {
-          /* xgettext: the '.working', '.merge-left.r%ld' and
-             '.merge-right.r%ld' strings are used to tag onto a file
-             name in case of a merge conflict */
-          const char *target_label = _(".working");
-          const char *left_label = apr_psprintf(subpool,
-                                                _(".merge-left.r%ld"),
-                                                older_rev);
-          const char *right_label = apr_psprintf(subpool,
-                                                 _(".merge-right.r%ld"),
-                                                 yours_rev);
-          conflict_resolver_baton_t conflict_baton = { 0 };
-          const svn_wc_conflict_version_t *left;
-          const svn_wc_conflict_version_t *right;
+      SVN_ERR(make_conflict_versions(&left, &right, mine_abspath,
+                                     svn_node_file, merge_b));
+      SVN_ERR(svn_wc_merge4(&merge_outcome, merge_b->ctx->wc_ctx,
+                            older_abspath, yours_abspath, mine_abspath,
+                            left_label, right_label, target_label,
+                            left, right,
+                            merge_b->dry_run, merge_b->diff3_cmd,
+                            merge_b->merge_options, prop_changes,
+                            conflict_resolver, &conflict_baton,
+                            merge_b->ctx->cancel_func,
+                            merge_b->ctx->cancel_baton,
+                            subpool));
 
-          conflict_baton.wrapped_func = merge_b->ctx->conflict_func;
-          conflict_baton.wrapped_baton = merge_b->ctx->conflict_baton;
-          conflict_baton.conflicted_paths = &merge_b->conflicted_paths;
-          conflict_baton.pool = merge_b->pool;
-
-          SVN_ERR(make_conflict_versions(&left, &right, mine_abspath,
-                                         svn_node_file, merge_b));
-          SVN_ERR(svn_wc_merge4(&merge_outcome, merge_b->ctx->wc_ctx,
-                                older_abspath, yours_abspath, mine_abspath,
-                                left_label, right_label, target_label,
-                                left, right,
-                                merge_b->dry_run, merge_b->diff3_cmd,
-                                merge_b->merge_options, prop_changes,
-                                conflict_resolver, &conflict_baton,
-                                merge_b->ctx->cancel_func,
-                                merge_b->ctx->cancel_baton,
-                                subpool));
-        }
-
       if (content_state)
         {
           if (merge_outcome == svn_wc_merge_conflict)

Reply via email to