You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/08/27 14:38:02 UTC

svn commit: r990128 - in /subversion/trunk/subversion: libsvn_client/diff.c tests/cmdline/diff_tests.py

Author: stsp
Date: Fri Aug 27 12:38:02 2010
New Revision: 990128

URL: http://svn.apache.org/viewvc?rev=990128&view=rev
Log:
Make all paths in git diffs appear relative to the repository root.
This way, copyfrom information shown in git diffs is always valid,
and the patch provides an exact representation of a commit.

The normal diff mode is not affected by this change.

Because Subversion represents branches as directories, when applying git
diffs generated from Subversion, users may need to strip some leading path
components from the diff. However, it's possible to generate git diffs where
the source and target have a different amount of leading components, for
instance a diff between /trunk and /branches/mybranch. Convenient application
of such patches will require support for independent source/target strip counts
in svn patch, git, and hg, or manual editing of the patch. Welcome to the
exciting adventures of version-control interoperability :)

As a bonus, this commit makes all four existing git diff tests pass.
One known remaining issue is that paths aren't shown relative to the
repository root if a git diff contains only property changes.

* subversion/tests/cmdline/diff_tests.py
  (make_git_diff_header, diff_git_format_wc_wc, diff_git_format_url_wc,
   diff_git_format_url_url, test_list): Adjust to the new path semantics
    and remove XFail markers from two tests.

* subversion/libsvn_client/diff.c
  (adjust_relative_to_repos_root): New function to make paths relative to
   the repository root for presentation purposes in git diff headers.
  (print_git_diff_header): Add new parameters RA_SESSION and WC_CTX, which
   are needed for calls to adjust_relative_to_repos_root(). Make all paths
   in git diff headers appear relative to the repository root.
  (diff_cmd_baton): Add a new RA_SESSION member, needed for calling the new
   adjust_relative_to_repos_root() helper. Add a docstring for the
   USE_GIT_DIFF_FORMAT member while here.
  (diff_content_changed): While generating diff headers, don't clobber the
   original diff targets, modify copies of them instead. We now need the
   original diff targets to remain intact for printing correct git diff
   headers. Pass the ra session and working copy context from the diff baton
   to print_git_diff_header().
  (diff_repos_repos, diff_repos_wc): Store the RA session inside the diff
   baton for later use.
  (svn_client_diff5, svn_client_diff_peg5): Initialise the new RA_SESSION
   member of the diff baton.

Modified:
    subversion/trunk/subversion/libsvn_client/diff.c
    subversion/trunk/subversion/tests/cmdline/diff_tests.py

Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=990128&r1=990127&r2=990128&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Fri Aug 27 12:38:02 2010
@@ -190,6 +190,140 @@ maybe_append_eol(const svn_string_t *tok
     }
 }
 
+/* Adjust PATH_OR_URL to be relative to the repository root, using RA_SESSION
+ * and WC_CTX, and return the result in *ADJUSTED_PATH.
+ * ORIG_TARGET is one of the original targets passed to the diff command,
+ * and may be used to derive leading path components missing from PATH_OR_URL.
+ * Do all allocations in POOL. */
+static svn_error_t *
+adjust_relative_to_repos_root(const char **adjusted_path,
+                              const char *path_or_url,
+                              const char *orig_target,
+                              svn_ra_session_t *ra_session,
+                              svn_wc_context_t *wc_ctx,
+                              svn_boolean_t is_repos_repos_diff,
+                              apr_pool_t *pool)
+{
+  const char *local_abspath;
+  const char *repos_root_url;
+  const char *node_url;
+
+  if (ra_session)
+    {
+      const char *wc_root_abspath;
+      svn_boolean_t wc_root_found;
+      apr_pool_t *iterpool;
+
+      if (is_repos_repos_diff)
+        {
+          /* Ask the repository for the adjusted path. */
+          if (svn_path_is_url(path_or_url))
+            {
+              SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
+                                                       adjusted_path,
+                                                       path_or_url, pool));
+            }
+          else
+            {
+              const char *orig_anchor;
+
+              SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
+                                                       &orig_anchor,
+                                                       orig_target, pool));
+              *adjusted_path = svn_relpath_join(orig_anchor, path_or_url, pool);
+            }
+
+          return SVN_NO_ERROR;
+        }
+
+      /* Now deal with the repos->wc and wc->repos cases, where PATH_OR_URL
+       * is a path. The path can either be pointing inside a working copy,
+       * (or be a working copy root), or it is relative to the URL of the
+       * original target. */
+
+      /* Check if the path is pointing to or is inside a working copy. */
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
+      wc_root_abspath = local_abspath;
+      wc_root_found = FALSE;
+      iterpool = svn_pool_create(pool);
+      while (! wc_root_found && *wc_root_abspath)
+        {
+          svn_error_t *err;
+
+          svn_pool_clear(iterpool);
+
+          err = svn_wc_is_wc_root2(&wc_root_found, wc_ctx, wc_root_abspath,
+                                   iterpool);
+          if (err)
+            {
+              /* Ignore all errors. It could be no working copy, or a missing
+               * item, or permission denied -- whatever. We don't care,
+               * because if all we get is errors, the path is most certainly
+               * unrelated to a working copy. */
+              svn_error_clear(err);
+            }
+          if (svn_dirent_is_root(wc_root_abspath, strlen(wc_root_abspath)))
+            break;
+          if (! wc_root_found)
+            wc_root_abspath = svn_dirent_dirname(wc_root_abspath, pool);
+        }
+      svn_pool_destroy(iterpool);
+
+      if (wc_root_found)
+        {
+          const char *wc_url;
+          const char *wc_anchor;
+          const char *in_wc_relpath;
+
+          /* The path is inside a working copy, so it's anchored beneath
+           * the URL corresponding to the working copy.
+           * ### Is it possible that we find a working copy by accident? */
+          SVN_ERR(svn_wc__node_get_url(&wc_url, wc_ctx, wc_root_abspath,
+                                       pool, pool));
+          SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &wc_anchor,
+                                                   wc_url, pool));
+          in_wc_relpath = svn_dirent_is_child(wc_root_abspath, local_abspath,
+                                              pool);
+          *adjusted_path = svn_relpath_join(wc_anchor, in_wc_relpath, pool);
+        }
+      else
+        {
+          const char *orig_anchor;
+          const char *orig_abspath;
+
+          /* The path is not inside an existing WC, so it's anchored
+           * beneath the original target. */
+          if (! svn_path_is_url(orig_target))
+            {
+              SVN_ERR(svn_dirent_get_absolute(&orig_abspath, orig_target,
+                                              pool));
+              SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL,
+                                                  wc_ctx, orig_abspath,
+                                                  TRUE, TRUE, pool, pool));
+              SVN_ERR(svn_wc__node_get_url(&orig_target, wc_ctx, orig_abspath,
+                                           pool, pool));
+            }
+          SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &orig_anchor,
+                                                   orig_target, pool));
+          *adjusted_path = svn_relpath_join(orig_anchor, path_or_url, pool);
+        }
+    }
+  else
+    {
+      /* We're doing a WC-WC diff, so we can retreive all information we
+       * need from the working copy. */
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
+      SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL,
+                                          wc_ctx, local_abspath,
+                                          TRUE, TRUE, pool, pool));
+      SVN_ERR(svn_wc__node_get_url(&node_url, wc_ctx, local_abspath, pool,
+                                   pool));
+      *adjusted_path = svn_uri_is_child(repos_root_url, node_url, pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Adjust PATH, ORIG_PATH_1 and ORIG_PATH_2, representing the changed file
  * and the two original targets passed to the diff command, to handle the
  * case when we're dealing with different anchors. RELATIVE_TO_DIR is the
@@ -529,9 +663,11 @@ print_git_diff_header_modified(svn_strea
 
 /* Print a git diff header showing the OPERATION to the stream OS using
  * HEADER_ENCODING. Return suitable diff labels for the git diff in *LABEL1
- * and *LABEL2. PATH is the path being diffed, PATH1 and PATH2 are the paths
- * passed to the original diff command. REV1 and REV2 are revisions being
- * diffed. COPYFROM_PATH indicates where the diffed item was copied from.
+ * and *LABEL2. PATH is the path being diffed, ORIG_TARGET1 and ORIG_TARGET2
+ * are the paths passed to the original diff command. REV1 and REV2 are
+ * revisions being diffed. COPYFROM_PATH indicates where the diffed item
+ * was copied from. RA_SESSION and WC_CTX are used to adjust paths in the
+ * headers to be relative to the repository root.
  * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
 print_git_diff_header(svn_stream_t *os,
@@ -544,54 +680,68 @@ print_git_diff_header(svn_stream_t *os,
                       svn_revnum_t rev2,
                       const char *copyfrom_path,
                       const char *header_encoding,
+                      svn_ra_session_t *ra_session,
+                      svn_wc_context_t *wc_ctx,
                       apr_pool_t *scratch_pool)
 {
-  /* Add git headers and adjust the labels. 
-   * ### Once we're using the git format everywhere, we can create
-   * ### one func that sets the correct labels in one place. */
+  const char *repos_relpath1;
+  const char *repos_relpath2;
+
+  SVN_ERR(adjust_relative_to_repos_root(&repos_relpath1, path, path1,
+                                        ra_session, wc_ctx,
+                                        svn_path_is_url(path1) &&
+                                          svn_path_is_url(path2),
+                                        scratch_pool));
+  SVN_ERR(adjust_relative_to_repos_root(&repos_relpath2, path, path2,
+                                        ra_session, wc_ctx,
+                                        svn_path_is_url(path1) &&
+                                          svn_path_is_url(path2),
+                                        scratch_pool));
+
   if (operation == svn_diff_op_deleted)
     {
       SVN_ERR(print_git_diff_header_deleted(os, header_encoding,
-                                            path, scratch_pool));
-      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", path1), rev1,
-                          scratch_pool);
+                                            repos_relpath2, scratch_pool));
+      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1),
+                           rev1, scratch_pool);
       *label2 = diff_label("/dev/null", rev2, scratch_pool);
 
     }
   else if (operation == svn_diff_op_copied)
     {
       SVN_ERR(print_git_diff_header_copied(os, header_encoding,
-                                           path, copyfrom_path, scratch_pool));
-      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", path1), rev1,
-                           scratch_pool);
-      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", path2), rev2,
-                           scratch_pool);
+                                           repos_relpath2, copyfrom_path,
+                                           scratch_pool));
+      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", copyfrom_path),
+                           rev1, scratch_pool);
+      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+                           rev2, scratch_pool);
     }
   else if (operation == svn_diff_op_added)
     {
       SVN_ERR(print_git_diff_header_added(os, header_encoding,
-                                          path, scratch_pool));
+                                          repos_relpath2, scratch_pool));
       *label1 = diff_label("/dev/null", rev1, scratch_pool);
-      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", path2), rev2,
-                           scratch_pool);
+      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+                           rev2, scratch_pool);
     }
   else if (operation == svn_diff_op_modified)
     {
       SVN_ERR(print_git_diff_header_modified(os, header_encoding,
-                                             path, scratch_pool));
-      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", path1), rev1,
-                           scratch_pool);
-      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", path2), rev2,
-                           scratch_pool);
+                                             repos_relpath2, scratch_pool));
+      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath2),
+                           rev1, scratch_pool);
+      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+                           rev2, scratch_pool);
     }
   else if (operation == svn_diff_op_moved)
     {
       SVN_ERR(print_git_diff_header_moved(os, header_encoding,
-                                          copyfrom_path, path, scratch_pool));
-      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", path1), rev1,
-                           scratch_pool);
-      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", path2), rev2,
-                           scratch_pool);
+                                          path, copyfrom_path, scratch_pool));
+      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", copyfrom_path),
+                           rev1, scratch_pool);
+      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+                           rev2, scratch_pool);
     }
 
   /* ### Print git headers for renames, too, in the future. */
@@ -658,10 +808,14 @@ struct diff_cmd_baton {
      relative to for output generation (see issue #2723). */
   const char *relative_to_dir;
 
+  /* Whether we're producing a git-style diff. */
   svn_boolean_t use_git_diff_format;
 
   svn_wc_context_t *wc_ctx;
 
+  /* The RA session used during diffs involving the repository. */
+  svn_ra_session_t *ra_session;
+
   /* A hashtable using the visited paths as keys. 
    * ### This is needed for us to know if we need to print a diff header for
    * ### a path that has property changes. */
@@ -756,8 +910,8 @@ diff_content_changed(const char *path,
 
   /* Generate the diff headers. */
 
-  path1 = diff_cmd_baton->orig_path_1;
-  path2 = diff_cmd_baton->orig_path_2;
+  path1 = apr_pstrdup(subpool, diff_cmd_baton->orig_path_1);
+  path2 = apr_pstrdup(subpool, diff_cmd_baton->orig_path_2);
 
   SVN_ERR(adjust_paths_for_diff_labels(&path, &path1, &path2,
                                        rel_to_dir, subpool));
@@ -856,9 +1010,13 @@ diff_content_changed(const char *path,
 
           if (diff_cmd_baton->use_git_diff_format)
             SVN_ERR(print_git_diff_header(os, &label1, &label2, operation,
-                                          path, path1, path2, rev1, rev2,
+                                          path, diff_cmd_baton->orig_path_1,
+                                          diff_cmd_baton->orig_path_2,
+                                          rev1, rev2,
                                           copyfrom_path,
                                           diff_cmd_baton->header_encoding,
+                                          diff_cmd_baton->ra_session,
+                                          diff_cmd_baton->wc_ctx,
                                           subpool));
 
           /* Output the actual diff */
@@ -1532,6 +1690,8 @@ diff_repos_repos(const svn_wc_diff_callb
   callback_baton->revnum1 = rev1;
   callback_baton->revnum2 = rev2;
 
+  callback_baton->ra_session = ra_session;
+
   /* Now, we open an extra RA session to the correct anchor
      location for URL1.  This is used during the editor calls to fetch file
      contents.  */
@@ -1661,6 +1821,7 @@ diff_repos_wc(const char *path1,
   SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, anchor_url,
                                                NULL, NULL, FALSE, TRUE,
                                                ctx, pool));
+  callback_baton->ra_session = ra_session;
 
   SVN_ERR(svn_wc_get_diff_editor6(&diff_editor, &diff_edit_baton,
                                   ctx->wc_ctx,
@@ -2032,6 +2193,7 @@ svn_client_diff5(const apr_array_header_
   diff_cmd_baton.use_git_diff_format = use_git_diff_format;
   diff_cmd_baton.wc_ctx = ctx->wc_ctx;
   diff_cmd_baton.visited_paths = apr_hash_make(pool);
+  diff_cmd_baton.ra_session = NULL;
 
   return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,
                  path1, path2, revision1, revision2, &peg_revision,
@@ -2091,6 +2253,7 @@ svn_client_diff_peg5(const apr_array_hea
   diff_cmd_baton.use_git_diff_format = use_git_diff_format;
   diff_cmd_baton.wc_ctx = ctx->wc_ctx;
   diff_cmd_baton.visited_paths = apr_hash_make(pool);
+  diff_cmd_baton.ra_session = NULL;
 
   return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,
                  path, path, start_revision, end_revision, peg_revision,

Modified: subversion/trunk/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/diff_tests.py?rev=990128&r1=990127&r2=990128&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/diff_tests.py Fri Aug 27 12:38:02 2010
@@ -52,20 +52,21 @@ def make_diff_header(path, old_tag, new_
     "+++ " + path_as_shown + "\t(" + new_tag + ")\n",
     ]
 
-def make_git_diff_header(path, old_tag, new_tag, add=False, src_label=None,
+def make_git_diff_header(target_path, repos_relpath,
+                         old_tag, new_tag, add=False, src_label=None,
                          dst_label=None, delete=False, text_changes=True,
-                         cp=False, mv=False, copyfrom=None):
-  """ Generate the expected 'git diff' header for file PATH, with its old
-  and new versions described in parentheses by OLD_TAG and NEW_TAG.
+                         cp=False, mv=False, copyfrom_path=None):
+  """ Generate the expected 'git diff' header for file TARGET_PATH.
+  REPOS_RELPATH is the location of the path relative to the repository root.
+  The old and new versions ("revision X", or "working copy") must be
+  specified in OLD_TAG and NEW_TAG.
   SRC_LABEL and DST_LABEL are paths or urls that are added to the diff
   labels if we're diffing against the repository. ADD, DELETE, CP and MV
-  denotes the operations performed on the file. COPYFROM is the source of a
-  copy or move.  Return the header as an array of newline-terminated
+  denotes the operations performed on the file. COPYFROM_PATH is the source
+  of a copy or move.  Return the header as an array of newline-terminated
   strings."""
 
-  path_as_shown = path.replace('\\', '/')
-  if copyfrom:
-    copyfrom_as_shown = copyfrom.replace('\\', '/')
+  path_as_shown = target_path.replace('\\', '/')
   if src_label:
     src_label = src_label.replace('\\', '/')
     src_label = '\t(.../' + src_label + ')'
@@ -81,59 +82,59 @@ def make_git_diff_header(path, old_tag, 
     output = [
       "Index: " + path_as_shown + "\n",
       "===================================================================\n",
-      "diff --git a/" + path_as_shown + " b/" + path_as_shown + "\n",
+      "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n",
       "new file mode 10644\n",
     ]
     if text_changes:
       output.extend([
         "--- /dev/null\t(" + old_tag + ")\n",
-        "+++ b/" + path_as_shown + dst_label + "\t(" + new_tag + ")\n"
+        "+++ b/" + repos_relpath + dst_label + "\t(" + new_tag + ")\n"
       ])
   elif delete:
     output = [
       "Index: " + path_as_shown + "\n",
       "===================================================================\n",
-      "diff --git a/" + path_as_shown + " b/" + path_as_shown + "\n",
+      "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n",
       "deleted file mode 10644\n",
     ]
     if text_changes:
       output.extend([
-        "--- a/" + path_as_shown + src_label + "\t(" + old_tag + ")\n",
+        "--- a/" + repos_relpath + src_label + "\t(" + old_tag + ")\n",
         "+++ /dev/null\t(" + new_tag + ")\n"
       ])
   elif cp:
     output = [
       "Index: " + path_as_shown + "\n",
       "===================================================================\n",
-      "diff --git a/" + copyfrom_as_shown + " b/" + path_as_shown + "\n",
-      "copy from " + copyfrom_as_shown + "\n",
-      "copy to " + path_as_shown + "\n",
+      "diff --git a/" + copyfrom_path + " b/" + repos_relpath + "\n",
+      "copy from " + copyfrom_path + "\n",
+      "copy to " + repos_relpath + "\n",
     ]
     if text_changes:
       output.extend([
-        "--- a/" + copyfrom_as_shown + src_label + "\t(" + old_tag + ")\n",
+        "--- a/" + copyfrom_path + src_label + "\t(" + old_tag + ")\n",
         "+++ b/" + path_as_shown + "\t(" + new_tag + ")\n"
       ])
   elif mv:
     return [
       "Index: " + path_as_shown + "\n",
       "===================================================================\n",
-      "diff --git a/" + copyfrom_as_shown + " b/" + path_as_shown + "\n",
-      "rename from " + copyfrom_as_shown + "\n",
-      "rename to " + path_as_shown + "\n",
+      "diff --git a/" + copyfrom_path + " b/" + path_as_shown + "\n",
+      "rename from " + copyfrom_path + "\n",
+      "rename to " + repos_relpath + "\n",
     ]
     if text_changes:
       output.extend([
-        "--- a/" + copyfrom_as_shown + src_label + "\t(" + old_tag + ")\n",
-        "+++ b/" + path_as_shown + "\t(" + new_tag + ")\n"
+        "--- a/" + copyfrom_path + src_label + "\t(" + old_tag + ")\n",
+        "+++ b/" + repos_relpath + "\t(" + new_tag + ")\n"
       ])
   else:
     output = [
       "Index: " + path_as_shown + "\n",
       "===================================================================\n",
-      "diff --git a/" + path_as_shown + " b/" + path_as_shown + "\n",
-      "--- a/" + path_as_shown + src_label + "\t(" + old_tag + ")\n",
-      "+++ b/" + path_as_shown + dst_label + "\t(" + new_tag + ")\n",
+      "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n",
+      "--- a/" + repos_relpath + src_label + "\t(" + old_tag + ")\n",
+      "+++ b/" + repos_relpath + dst_label + "\t(" + new_tag + ")\n",
     ]
   return output
 
@@ -3376,22 +3377,26 @@ def diff_git_format_wc_wc(sbox):
 
   ### We're not testing moved paths
 
-  expected_output = make_git_diff_header(mu_path, "revision 1", 
+  expected_output = make_git_diff_header(lambda_copied_path,
+                                         "A/B/lambda_copied",
+                                         "revision 1", "working copy",
+                                         copyfrom_path="A/B/lambda", cp=True,
+                                         text_changes=False) \
+  + make_git_diff_header(mu_path, "A/mu", "revision 1", 
                                          "working copy", 
                                          delete=True) + [
     "@@ -1 +0,0 @@\n",
     "-This is the file 'mu'.\n",
-  ] + make_git_diff_header(new_path, "revision 0", "working copy", 
-                           add=True) + [
+  ] + make_git_diff_header(new_path, "new", "revision 0",
+                           "working copy", add=True) + [
     "@@ -0,0 +1 @@\n",
     "+This is the file 'new'.\n",
-  ] +  make_git_diff_header(iota_path, "revision 1", 
+  ] +  make_git_diff_header(iota_path, "iota", "revision 1", 
                             "working copy") + [
     "@@ -1 +1,2 @@\n",
     " This is the file 'iota'.\n",
     "+Changed 'iota'.\n",
-  ] + make_git_diff_header(lambda_copied_path, "revision 1",
-                           "working copy", copyfrom=lambda_path)
+  ]
 
   svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff', 
                                      '--git', wc_dir)
@@ -3414,19 +3419,16 @@ def diff_git_format_url_wc(sbox):
   svntest.main.run_svn(None, 'commit', '-m', 'Committing changes', wc_dir)
   svntest.main.run_svn(None, 'up', wc_dir)
 
-  expected_output = make_git_diff_header(new_path, "revision 0", "revision 2", 
-                                         dst_label=wc_dir, add=True) + [
+  expected_output = make_git_diff_header(new_path, "new", "revision 0",
+                                         "revision 2", add=True) + [
     "@@ -0,0 +1 @@\n",
     "+This is the file 'new'.\n",
-  ] + make_git_diff_header(mu_path, "revision 1", 
-                           "working copy", 
-                           src_label=repo_url,
+  ] + make_git_diff_header(mu_path, "A/mu", "revision 1", "working copy", 
                            delete=True) + [
     "@@ -1 +0,0 @@\n",
     "-This is the file 'mu'.\n",
-  ] +  make_git_diff_header(iota_path, "revision 1", 
-                            "working copy", src_label=repo_url,
-                            dst_label=wc_dir) + [
+  ] +  make_git_diff_header(iota_path, "iota", "revision 1", 
+                            "working copy") + [
     "@@ -1 +1,2 @@\n",
     " This is the file 'iota'.\n",
     "+Changed 'iota'.\n",
@@ -3456,16 +3458,16 @@ def diff_git_format_url_url(sbox):
   svntest.main.run_svn(None, 'commit', '-m', 'Committing changes', wc_dir)
   svntest.main.run_svn(None, 'up', wc_dir)
 
-  expected_output = make_git_diff_header("A/mu", "revision 1", 
+  expected_output = make_git_diff_header("A/mu", "A/mu", "revision 1", 
                                          "revision 2", 
                                          delete=True) + [
     "@@ -1 +0,0 @@\n",
     "-This is the file 'mu'.\n",
-    ] + make_git_diff_header("new", "revision 0", "revision 2", 
-                              add=True) + [
+    ] + make_git_diff_header("new", "new", "revision 0", "revision 2", 
+                             add=True) + [
     "@@ -0,0 +1 @@\n",
     "+This is the file 'new'.\n",
-  ] +  make_git_diff_header("iota", "revision 1", 
+  ] +  make_git_diff_header("iota", "iota", "revision 1", 
                             "revision 2") + [
     "@@ -1 +1,2 @@\n",
     " This is the file 'iota'.\n",
@@ -3634,10 +3636,10 @@ def diff_git_empty_files(sbox):
   svntest.main.run_svn(None, 'add', new_path)
   svntest.main.run_svn(None, 'rm', iota_path)
 
-  expected_output = make_git_diff_header(new_path, "revision 0", 
+  expected_output = make_git_diff_header(new_path, "new", "revision 0", 
                                          "working copy", 
                                          add=True, text_changes=False) + [
-  ] + make_git_diff_header(new_path, "revision 2", "working copy", 
+  ] + make_git_diff_header(iota_path, "iota", "revision 2", "working copy", 
                            delete=True, text_changes=False)
 
   svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff', 
@@ -3700,12 +3702,12 @@ test_list = [ None,
               diff_external_diffcmd,
               XFail(diff_url_against_local_mods),
               XFail(diff_preexisting_rev_against_local_add),
-              XFail(diff_git_format_wc_wc),
+              diff_git_format_wc_wc,
               diff_git_format_url_wc,
               diff_git_format_url_url,
               diff_prop_missing_context,
               diff_prop_multiple_hunks,
-              XFail(diff_git_empty_files),
+              diff_git_empty_files,
               ]
 
 if __name__ == '__main__':