diff-no-index: align D/F handling with that of normal Git
When a commit changes a path P that used to be a file to a directory and creates a new path P/X in it, "git show" would say that file P was removed and file P/X was created for such a commit. However, if we compare two directories, D1 and D2, where D1 has a file D1/P in it and D2 has a directory D2/P under which there is a file D2/P/X, and ask "git diff --no-index D1 D2" to show their differences, we simply get a refusal "file/directory conflict". Surely, that may be what GNU diff does, but we can do better and it is easy to do so. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Mar 21, 2015 at 22:11 UTC
06151739988601b0fe6179c6c67a0031b85b536f
2 files changed
+33
-2
diff-no-index.c
+21
-2
@@ -97,8 +97,27 @@ static int queue_diff(struct diff_options *o,
97
if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
98
return -1;
99
100
- if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
101
- return error("file/directory conflict: %s, %s", name1, name2);
100
+ if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) {
101
+ struct diff_filespec *d1, *d2;
102
+
103
+ if (S_ISDIR(mode1)) {
104
+ /* 2 is file that is created */
105
+ d1 = noindex_filespec(NULL, 0);
106
+ d2 = noindex_filespec(name2, mode2);
107
+ name2 = NULL;
108
+ mode2 = 0;
109
+ } else {
110
+ /* 1 is file that is deleted */
111
+ d1 = noindex_filespec(name1, mode1);
112
+ d2 = noindex_filespec(NULL, 0);
113
+ name1 = NULL;
114
+ mode1 = 0;
115
+ }
116
+ /* emit that file */
117
+ diff_queue(&diff_queued_diff, d1, d2);
118
+
119
+ /* and then let the entire directory be created or deleted */
120
+ }
121
122
if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
123
struct strbuf buffer1 = STRBUF_INIT;
t/t4053-diff-no-index.sh
+12
@@ -77,4 +77,16 @@ test_expect_success 'diff D F and diff F D' '
77
)
78
'
79
80
+test_expect_success 'turning a file into a directory' '
81
+ (
82
+ cd non/git &&
83
+ mkdir d e e/sub &&
84
+ echo 1 >d/sub &&
85
+ echo 2 >e/sub/file &&
86
+ printf "D\td/sub\nA\te/sub/file\n" >expect &&
87
+ test_must_fail git diff --no-index --name-status d e >actual &&
88
+ test_cmp expect actual
89
+ )
90
+'
91
+
92
test_done