diff: do not reuse_worktree_file for submodules

The GIT_EXTERNAL_DIFF calling code attempts to reuse existing worktree files for the worktree side of diffs, for performance reasons. However, that code also tries to do the same with submodules. This results in calls to $GIT_EXTERNAL_DIFF where the old-file is a file of the form "Submodule commit $sha1", but the new-file is a directory in the worktree. Fix it by never reusing a worktree "file" in the submodule case. Reported-by: Grégory Pakosz <gregory.pakosz@gmail.com> Signed-off-by: Thomas Rast <tr@thomasrast.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Thomas Rast committed Feb 16, 2014 at 17:52 UTC aba4727281612c3e24914691727e11e1f44a9aac
2 files changed +32 -3
diff.c
+3 -2
@@ -2842,8 +2842,9 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
2842 remove_tempfile_installed = 1;
2843 }
2844
2845 - if (!one->sha1_valid ||
2846 - reuse_worktree_file(name, one->sha1, 1)) {
2845 + if (!S_ISGITLINK(one->mode) &&
2846 + (!one->sha1_valid ||
2847 + reuse_worktree_file(name, one->sha1, 1))) {
2848 struct stat st;
2849 if (lstat(name, &st) < 0) {
2850 if (errno == ENOENT)
t/t4020-diff-external.sh
+29 -1
@@ -213,12 +213,13 @@ keep_only_cr () {
213 }
214
215 test_expect_success 'external diff with autocrlf = true' '
216 - git config core.autocrlf true &&
216 + test_config core.autocrlf true &&
217 GIT_EXTERNAL_DIFF=./fake-diff.sh git diff &&
218 test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c)
219 '
220
221 test_expect_success 'diff --cached' '
222 + test_config core.autocrlf true &&
223 git add file &&
224 git update-index --assume-unchanged file &&
225 echo second >file &&
@@ -226,4 +227,31 @@ test_expect_success 'diff --cached' '
227 test_cmp "$TEST_DIRECTORY"/t4020/diff.NUL actual
228 '
229
230 +test_expect_success 'clean up crlf leftovers' '
231 + git update-index --no-assume-unchanged file &&
232 + rm -f file* &&
233 + git reset --hard
234 +'
235 +
236 +test_expect_success 'submodule diff' '
237 + git init sub &&
238 + ( cd sub && test_commit sub1 ) &&
239 + git add sub &&
240 + test_tick &&
241 + git commit -m "add submodule" &&
242 + ( cd sub && test_commit sub2 ) &&
243 + write_script gather_pre_post.sh <<-\EOF &&
244 + echo "$1 $4" # path, mode
245 + cat "$2" # old file
246 + cat "$5" # new file
247 + EOF
248 + GIT_EXTERNAL_DIFF=./gather_pre_post.sh git diff >actual &&
249 + cat >expected <<-EOF &&
250 + sub 160000
251 + Subproject commit $(git rev-parse HEAD:sub)
252 + Subproject commit $(cd sub && git rev-parse HEAD)
253 + EOF
254 + test_cmp expected actual
255 +'
256 +
257 test_done