Index: subversion/include/private/svn_wc_private.h
===================================================================
--- subversion/include/private/svn_wc_private.h	(revision 1611312)
+++ subversion/include/private/svn_wc_private.h	(working copy)
@@ -1845,6 +1845,7 @@
               const char *local_abspath,
               svn_depth_t depth,
               svn_boolean_t ignore_ancestry,
+              svn_boolean_t no_normalization,
               const apr_array_header_t *changelist_filter,
               const svn_diff_tree_processor_t *diff_processor,
               svn_cancel_func_t cancel_func,
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h	(revision 1611312)
+++ subversion/include/svn_client.h	(working copy)
@@ -2994,6 +2994,41 @@
  * @{
  */
 
+/** Just like svn_client_diff6() but with an added parameter @a
+ * no_normalization.
+ *
+ * If @a no_normalization is TRUE, then local diffs in the working copy
+ * won't be made against a potentially normalized, temporary version of the
+ * working copy version of the file. This is normally done if the file in
+ * question has got the svn:keywords or svn:eol-style property set. However,
+ * this makes it impossible to edit diffed files in an external diff tool,
+ * therefore setting @a no_normalization sacrifices normalization in favor
+ * of being able to edit the working copy file from the differ.
+ **/
+svn_error_t *
+svn_client_diff7(const apr_array_header_t *diff_options,
+                 const char *path_or_url1,
+                 const svn_opt_revision_t *revision1,
+                 const char *path_or_url2,
+                 const svn_opt_revision_t *revision2,
+                 const char *relative_to_dir,
+                 svn_depth_t depth,
+                 svn_boolean_t ignore_ancestry,
+                 svn_boolean_t no_diff_added,
+                 svn_boolean_t no_diff_deleted,
+                 svn_boolean_t show_copies_as_adds,
+                 svn_boolean_t no_normalization,
+                 svn_boolean_t ignore_content_type,
+                 svn_boolean_t ignore_properties,
+                 svn_boolean_t properties_only,
+                 svn_boolean_t use_git_diff_format,
+                 const char *header_encoding,
+                 svn_stream_t *outstream,
+                 svn_stream_t *errstream,
+                 const apr_array_header_t *changelists,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool);
+
 /**
  * Produce diff output which describes the delta between
  * @a path_or_url1/@a revision1 and @a path_or_url2/@a revision2.  Print
Index: subversion/libsvn_client/deprecated.c
===================================================================
--- subversion/libsvn_client/deprecated.c	(revision 1611312)
+++ subversion/libsvn_client/deprecated.c	(working copy)
@@ -914,6 +914,41 @@
 /*** From diff.c ***/
 
 svn_error_t *
+svn_client_diff6(const apr_array_header_t *diff_options,
+                 const char *path_or_url1,
+                 const svn_opt_revision_t *revision1,
+                 const char *path_or_url2,
+                 const svn_opt_revision_t *revision2,
+                 const char *relative_to_dir,
+                 svn_depth_t depth,
+                 svn_boolean_t ignore_ancestry,
+                 svn_boolean_t no_diff_added,
+                 svn_boolean_t no_diff_deleted,
+                 svn_boolean_t show_copies_as_adds,
+                 svn_boolean_t ignore_content_type,
+                 svn_boolean_t ignore_properties,
+                 svn_boolean_t properties_only,
+                 svn_boolean_t use_git_diff_format,
+                 const char *header_encoding,
+                 svn_stream_t *outstream,
+                 svn_stream_t *errstream,
+                 const apr_array_header_t *changelists,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool)
+{
+  return svn_client_diff7(diff_options, path_or_url1, revision1, path_or_url2,
+                          revision2, relative_to_dir, depth,
+                          ignore_ancestry, no_diff_added,
+                          no_diff_deleted, show_copies_as_adds,
+                          FALSE /* no normalization */,
+                          ignore_content_type, ignore_properties,
+                          properties_only, use_git_diff_format,
+                          header_encoding,
+                          outstream, errstream, changelists, ctx, pool);
+ 
+}
+
+svn_error_t *
 svn_client_diff5(const apr_array_header_t *diff_options,
                  const char *path1,
                  const svn_opt_revision_t *revision1,
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c	(revision 1611312)
+++ subversion/libsvn_client/diff.c	(working copy)
@@ -564,6 +564,12 @@
   /* Set this if you want diff output even for binary files. */
   svn_boolean_t force_binary;
 
+  /* Set this if you don't want to get temporary version of files during local
+    * diff, because svn:eol_style or svn:keywords are set on the old/new file.
+    * This allows to always edit the working file when invoking external diff
+    * commands. */
+  svn_boolean_t no_normalization;
+
   /* The directory that diff target paths should be considered as
      relative to for output generation (see issue #2723). */
   const char *relative_to_dir;
@@ -1638,6 +1644,7 @@
            apr_pool_t *scratch_pool)
 {
   const char *abspath1;
+  diff_writer_info_t *dwi = (diff_writer_info_t*)diff_processor->baton;
 
   SVN_ERR_ASSERT(! svn_path_is_url(path1));
   SVN_ERR_ASSERT(! svn_path_is_url(path2));
@@ -1670,8 +1677,8 @@
 
   SVN_ERR(svn_wc__diff7(root_relpath, root_is_dir,
                         ctx->wc_ctx, abspath1, depth,
-                        ignore_ancestry, changelists,
-                        diff_processor,
+                        ignore_ancestry, dwi->no_normalization,
+                        changelists, diff_processor,
                         ctx->cancel_func, ctx->cancel_baton,
                         result_pool, scratch_pool));
   return SVN_NO_ERROR;
@@ -2328,7 +2335,7 @@
       * These cases require server communication.
 */
 svn_error_t *
-svn_client_diff6(const apr_array_header_t *options,
+svn_client_diff7(const apr_array_header_t *options,
                  const char *path_or_url1,
                  const svn_opt_revision_t *revision1,
                  const char *path_or_url2,
@@ -2339,6 +2346,7 @@
                  svn_boolean_t no_diff_added,
                  svn_boolean_t no_diff_deleted,
                  svn_boolean_t show_copies_as_adds,
+                 svn_boolean_t no_normalization,
                  svn_boolean_t ignore_content_type,
                  svn_boolean_t ignore_properties,
                  svn_boolean_t properties_only,
@@ -2382,6 +2390,7 @@
   dwi.no_diff_added = no_diff_added;
   dwi.no_diff_deleted = no_diff_deleted;
   dwi.show_copies_as_adds = show_copies_as_adds;
+  dwi.no_normalization = no_normalization;
 
   dwi.cancel_func = ctx->cancel_func;
   dwi.cancel_baton = ctx->cancel_baton;
Index: subversion/libsvn_wc/diff.h
===================================================================
--- subversion/libsvn_wc/diff.h	(revision 1611312)
+++ subversion/libsvn_wc/diff.h	(working copy)
@@ -136,6 +136,7 @@
                                const svn_diff_tree_processor_t *processor,
                                void *processor_dir_baton,
                                svn_boolean_t diff_pristine,
+                               svn_boolean_t no_normalization,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool);
Index: subversion/libsvn_wc/diff_editor.c
===================================================================
--- subversion/libsvn_wc/diff_editor.c	(revision 1611312)
+++ subversion/libsvn_wc/diff_editor.c	(working copy)
@@ -396,6 +396,7 @@
                                const svn_diff_tree_processor_t *processor,
                                void *processor_dir_baton,
                                svn_boolean_t diff_pristine,
+                               svn_boolean_t no_normalization,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool)
@@ -505,7 +506,7 @@
                                          db, local_abspath,
                                          working_checksum,
                                          scratch_pool, scratch_pool));
-  else if (! (had_props || props_mod))
+  else if (! (had_props || props_mod) || (!files_same && no_normalization) )
     local_file = local_abspath;
   else if (files_same)
     local_file = pristine_file;
@@ -817,6 +818,7 @@
                                                 eb->changelist_hash,
                                                 eb->processor, dir_baton,
                                                 eb->diff_pristine,
+                                                FALSE /* no normalization */,
                                                 eb->cancel_func,
                                                 eb->cancel_baton,
                                                 scratch_pool));
Index: subversion/libsvn_wc/diff_local.c
===================================================================
--- subversion/libsvn_wc/diff_local.c	(revision 1611312)
+++ subversion/libsvn_wc/diff_local.c	(working copy)
@@ -88,6 +88,9 @@
 
   /* Should this diff ignore node ancestry? */
   svn_boolean_t ignore_ancestry;
+  
+  /* don't perform normalization even if eol_style or keywords are set */
+  svn_boolean_t no_normalization;
 
   /* Hash whose keys are const char * changelist names. */
   apr_hash_t *changelist_hash;
@@ -364,6 +367,7 @@
                                                         ? eb->cur->baton
                                                         : NULL,
                                                    FALSE,
+                                                   eb->no_normalization,
                                                    eb->cancel_func,
                                                    eb->cancel_baton,
                                                    scratch_pool));
@@ -435,6 +439,7 @@
               const char *local_abspath,
               svn_depth_t depth,
               svn_boolean_t ignore_ancestry,
+              svn_boolean_t no_normalization,
               const apr_array_header_t *changelist_filter,
               const svn_diff_tree_processor_t *diff_processor,
               svn_cancel_func_t cancel_func,
@@ -454,6 +459,7 @@
                                scratch_pool));
 
   eb.anchor_abspath = local_abspath;
+  eb.no_normalization = no_normalization;
 
   if (root_relpath)
     {
@@ -564,6 +570,7 @@
                                        wc_ctx, local_abspath,
                                        depth,
                                        ignore_ancestry,
+                                       FALSE, /* no normalization */
                                        changelist_filter,
                                        processor,
                                        cancel_func, cancel_baton,
Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h	(revision 1611312)
+++ subversion/svn/cl.h	(working copy)
@@ -188,6 +188,7 @@
   svn_boolean_t no_diff_added;       /* do not show diffs for deleted files */
   svn_boolean_t no_diff_deleted;     /* do not show diffs for deleted files */
   svn_boolean_t show_copies_as_adds; /* do not diff copies with their source */
+  svn_boolean_t no_normalization;    /* do not use temporary, normalized files */
   svn_boolean_t notice_ancestry;     /* notice ancestry for diff-y operations */
   svn_boolean_t summarize;           /* create a summary of a diff */
   svn_boolean_t use_git_diff_format; /* Use git's extended diff format */
Index: subversion/svn/diff-cmd.c
===================================================================
--- subversion/svn/diff-cmd.c	(revision 1611312)
+++ subversion/svn/diff-cmd.c	(working copy)
@@ -404,7 +404,7 @@
                                 ctx, iterpool));
             }
           else
-            SVN_ERR(svn_client_diff6(
+            SVN_ERR(svn_client_diff7(
                      options,
                      target1,
                      &(opt_state->start_revision),
@@ -416,6 +416,7 @@
                      opt_state->diff.no_diff_added,
                      opt_state->diff.no_diff_deleted,
                      show_copies_as_adds,
+                     opt_state->diff.no_normalization,
                      ignore_content_type,
                      ignore_properties,
                      opt_state->diff.properties_only,
Index: subversion/svn/svn.c
===================================================================
--- subversion/svn/svn.c	(revision 1611312)
+++ subversion/svn/svn.c	(working copy)
@@ -79,6 +79,7 @@
   opt_no_diff_added,
   opt_no_diff_deleted,
   opt_show_copies_as_adds,
+  opt_no_normalization,
   opt_notice_ancestry,
   opt_summarize,
   opt_use_git_diff_format,
@@ -352,6 +353,14 @@
                     N_("do not print differences for deleted files")},
   {"show-copies-as-adds", opt_show_copies_as_adds, 0,
                     N_("don't diff copied or moved files with their source")},
+  {"no-normalization", opt_no_normalization, 0,
+                   N_("don't pass temporary, normalized files to the diff\n"
+                      "                             "
+                      "tool but the local working copy file. This is otherwise\n"
+                      "                             "
+                      "done if the svn:keywords or svn:eol-style property is set\n"
+                      "                             "
+                      "on the file")},
   {"notice-ancestry", opt_notice_ancestry, 0,
                     N_("diff unrelated nodes as delete and add")},
   {"summarize",     opt_summarize, 0, N_("show a summary of the results")},
@@ -636,7 +645,8 @@
     {'r', 'c', opt_old_cmd, opt_new_cmd, 'N', opt_depth, opt_diff_cmd,
      opt_internal_diff, 'x', opt_no_diff_added, opt_no_diff_deleted,
      opt_ignore_properties, opt_properties_only,
-     opt_show_copies_as_adds, opt_notice_ancestry, opt_summarize, opt_changelist,
+     opt_show_copies_as_adds, opt_no_normalization, opt_notice_ancestry,
+     opt_summarize, opt_changelist,
      opt_force, opt_xml, opt_use_git_diff_format, opt_patch_compatible} },
   { "export", svn_cl__export, {0}, N_
     ("Create an unversioned copy of a tree.\n"
@@ -2136,6 +2146,9 @@
       case opt_show_copies_as_adds:
         opt_state.diff.show_copies_as_adds = TRUE;
         break;
+      case opt_no_normalization:
+        opt_state.diff.no_normalization = TRUE;
+        break;
       case opt_notice_ancestry:
         opt_state.diff.notice_ancestry = TRUE;
         break;

