Improve case-only rename behavior on case-insensitive filesystems by
performing deletes before adds when updating a directory.

* subversion/libsvn_repos/reporter.c (delta_dirs): Perform deletes
  before adds.

Index: subversion/libsvn_repos/reporter.c
===================================================================
--- subversion/libsvn_repos/reporter.c	(revision 12171)
+++ subversion/libsvn_repos/reporter.c	(working copy)
@@ -735,6 +735,19 @@
       SVN_ERR (fetch_path_info (b, &name, &info, e_path, subpool));
       if (!name)
         break;
+
+      if (info && !SVN_IS_VALID_REVNUM (info->rev))
+        {
+          /* We want to perform deletes before non-replacement adds,
+             for graceful handling of case-only renames on
+             case-insensitive client filesystems.  So, if the report
+             item is a delete, remove the entry from the source hash,
+             but don't update the entry yet. */
+          if (s_entries)
+            apr_hash_set (s_entries, name, APR_HASH_KEY_STRING, NULL);
+          continue;
+        }
+
       e_fullpath = svn_path_join (e_path, name, subpool);
       t_fullpath = svn_path_join (t_path, name, subpool);
       t_entry = apr_hash_get (t_entries, name, APR_HASH_KEY_STRING);
@@ -757,7 +770,30 @@
         svn_pool_destroy (info->pool);
     }
 
-  /* Loop over the remaining dirents in the target. */
+  /* Remove any deleted entries.  Do this before processing the
+     target, for graceful handling of case-only renames. */
+  if (s_entries)
+    {
+      for (hi = apr_hash_first (pool, s_entries); hi; hi = apr_hash_next (hi))
+        {
+          svn_pool_clear (subpool);
+          apr_hash_this (hi, NULL, NULL, &val);
+          s_entry = val;
+
+          if (apr_hash_get (t_entries, s_entry->name,
+                            APR_HASH_KEY_STRING) == NULL)
+            {
+              /* There is no corresponding target entry, so delete. */
+              e_fullpath = svn_path_join (e_path, s_entry->name, subpool);
+              if (b->recurse || s_entry->kind != svn_node_dir)
+                SVN_ERR (b->editor->delete_entry (e_fullpath,
+                                                  SVN_INVALID_REVNUM,
+                                                  dir_baton, subpool));
+            }
+        }
+    }
+
+  /* Loop over the dirents in the target. */
   for (hi = apr_hash_first (pool, t_entries); hi; hi = apr_hash_next (hi))
     {
       svn_pool_clear (subpool);
@@ -777,29 +813,8 @@
       SVN_ERR (update_entry (b, s_rev, s_fullpath, s_entry, t_fullpath,
                              t_entry, dir_baton, e_fullpath, NULL,
                              b->recurse, subpool));
-
-      /* Don't revisit this name in the source entries. */
-      if (s_entries)
-        apr_hash_set (s_entries, t_entry->name, APR_HASH_KEY_STRING, NULL);
     }
 
-  /* Loop over the remaining dirents in the source. */
-  if (s_entries)
-    {
-      for (hi = apr_hash_first (pool, s_entries); hi; hi = apr_hash_next (hi))
-        {
-          svn_pool_clear (subpool);
-          apr_hash_this (hi, NULL, NULL, &val);
-          s_entry = val;
-
-          /* We know there is no corresponding target entry, so just delete. */
-          e_fullpath = svn_path_join (e_path, s_entry->name, subpool);
-          if (b->recurse || s_entry->kind != svn_node_dir)
-            SVN_ERR (b->editor->delete_entry (e_fullpath, SVN_INVALID_REVNUM,
-                                              dir_baton, subpool));
-        }
-    }
-
   /* Destroy iteration subpool. */
   svn_pool_destroy (subpool);