diff: handle --no-index prefixes consistently
authorJeff King <peff@peff.net>
Tue, 13 Sep 2016 03:23:32 +0000 (20:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 13 Sep 2016 22:45:45 +0000 (15:45 -0700)
If we see an explicit "git diff --no-index ../foo ../bar",
then we do not set up the git repository at all (we already
know we are in --no-index mode, so do not have to check "are
we in a repository?"), and hence have no "prefix" within the
repository. A patch generated by this command will have the
filenames "a/../foo" and "b/../bar", no matter which
directory we are in with respect to any repository.

However, in the implicit case, where we notice that the
files are outside the repository, we will have chdir()'d to
the top-level of the repository. We then feed the prefix
back to the diff machinery. As a result, running the same
diff from a subdirectory will result in paths that look like
"a/subdir/../../foo".

Besides being unnecessarily long, this may also be confusing
to the user: they don't care about the subdir or the
repository at all; it's just where they happened to be when
running the command. We should treat this the same as the
explicit --no-index case.

One way to address this would be to chdir() back to the
original path before running our diff. However, that's a bit
hacky, as we would also need to adjust $GIT_DIR, which could
be a relative path from our top-level.

Instead, we can reuse the diff machinery's RELATIVE_NAME
option, which automatically strips off the prefix. Note that
this _also_ restricts the diff to this relative prefix, but
that's OK for our purposes: we queue our own diff pairs
manually, and do not rely on that part of the diff code.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff-no-index.c
t/t4053-diff-no-index.sh
index 03daadb25af835a695c7d0baf466b0e1f82b58c4..59237a626727864c786aca078564b632da08f294 100644 (file)
@@ -282,6 +282,9 @@ void diff_no_index(struct rev_info *revs,
 
        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 
+       DIFF_OPT_SET(&revs->diffopt, RELATIVE_NAME);
+       revs->diffopt.prefix = prefix;
+
        revs->max_count = -2;
        diff_setup_done(&revs->diffopt);
 
index 6eb83211b593ecea798eba3790b9c76fc7d3aa60..e60c951180a47c6c82e9178e4f9c332ff6a9e244 100755 (executable)
@@ -89,4 +89,22 @@ test_expect_success 'turning a file into a directory' '
        )
 '
 
+test_expect_success 'diff from repo subdir shows real paths (explicit)' '
+       echo "diff --git a/../../non/git/a b/../../non/git/b" >expect &&
+       test_expect_code 1 \
+               git -C repo/sub \
+               diff --no-index ../../non/git/a ../../non/git/b >actual &&
+       head -n 1 <actual >actual.head &&
+       test_cmp expect actual.head
+'
+
+test_expect_success 'diff from repo subdir shows real paths (implicit)' '
+       echo "diff --git a/../../non/git/a b/../../non/git/b" >expect &&
+       test_expect_code 1 \
+               git -C repo/sub \
+               diff ../../non/git/a ../../non/git/b >actual &&
+       head -n 1 <actual >actual.head &&
+       test_cmp expect actual.head
+'
+
 test_done