diff: test precedence of external diff drivers
authorJeff King <peff@peff.net>
Thu, 19 Jul 2012 11:49:38 +0000 (07:49 -0400)
committerJunio C Hamano <gitster@pobox.com>
Thu, 19 Jul 2012 17:17:05 +0000 (10:17 -0700)
There are three ways to specify an external diff command:
GIT_EXTERNAL_DIFF in the environment, diff.external in the
config, or a "diff" gitattribute. The current order of
precedence is:

  1. gitattribute

  2. GIT_EXTERNAL_DIFF

  3. diff.external

Usually our rule is that environment variables should take
precedence over on-disk config (i.e., option 2 should come
before option 1). However, this situation is trickier than
some, because option 1 is more specific to the individual
file than option 2 (which affects all files), so it might be
preferable. So the current behavior can be seen as
implementing "do the specific thing if we can, but fall back
to this general thing".

This is probably not what we would do if we were writing git
from scratch, but it has been this way for several years,
and is not worth changing. So let's at least document that
this is the way it's supposed to work with a test.

While we're there, let's also make sure that diff.external
(which was not previously tested at all) works by running it
through the same tests as GIT_EXTERNAL_DIFF.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t4020-diff-external.sh

index 025df533ca8969e67c38f8dcb913c9021b816c57..8a309795c9c9654446d82c2e474e1ca08486e081 100755 (executable)
@@ -65,6 +65,33 @@ test_expect_success SYMLINKS 'typechange diff' '
        test_cmp expect actual
 '
 
+test_expect_success 'diff.external' '
+       git reset --hard &&
+       echo third >file &&
+       test_config diff.external echo &&
+       git diff | {
+               read path oldfile oldhex oldmode newfile newhex newmode &&
+               test "z$path" = zfile &&
+               test "z$oldmode" = z100644 &&
+               test "z$newhex" = "z$_z40" &&
+               test "z$newmode" = z100644 &&
+               oh=$(git rev-parse --verify HEAD:file) &&
+               test "z$oh" = "z$oldhex"
+       }
+'
+
+test_expect_success 'diff.external should apply only to diff' '
+       test_config diff.external echo &&
+       git log -p -1 HEAD |
+       grep "^diff --git a/file b/file"
+'
+
+test_expect_success 'diff.external and --no-ext-diff' '
+       test_config diff.external echo &&
+       git diff --no-ext-diff |
+       grep "^diff --git a/file b/file"
+'
+
 test_expect_success 'diff attribute' '
        git reset --hard &&
        echo third >file &&
@@ -132,6 +159,19 @@ test_expect_success 'diff attribute and --no-ext-diff' '
 
 '
 
+test_expect_success 'GIT_EXTERNAL_DIFF trumps diff.external' '
+       >.gitattributes &&
+       test_config diff.external "echo ext-global" &&
+       GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-env
+'
+
+test_expect_success 'attributes trump GIT_EXTERNAL_DIFF and diff.external' '
+       test_config diff.foo.command "echo ext-attribute" &&
+       test_config diff.external "echo ext-global" &&
+       echo "file diff=foo" >.gitattributes &&
+       GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-attribute
+'
+
 test_expect_success 'no diff with -diff' '
        echo >.gitattributes "file -diff" &&
        git diff | grep Binary