Merge branch 'jk/cache-tree-protect-from-broken-libgit2'
[git] / t / t7800-difftool.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2009, 2010, 2012, 2013 David Aguilar
4 #
5
6 test_description='git-difftool
7
8 Testing basic diff tool invocation
9 '
10
11 . ./test-lib.sh
12
13 difftool_test_setup ()
14 {
15         test_config diff.tool test-tool &&
16         test_config difftool.test-tool.cmd 'cat "$LOCAL"' &&
17         test_config difftool.bogus-tool.cmd false
18 }
19
20 prompt_given ()
21 {
22         prompt="$1"
23         test "$prompt" = "Launch 'test-tool' [Y/n]: branch"
24 }
25
26 # Create a file on master and change it on branch
27 test_expect_success PERL 'setup' '
28         echo master >file &&
29         git add file &&
30         git commit -m "added file" &&
31
32         git checkout -b branch master &&
33         echo branch >file &&
34         git commit -a -m "branch changed file" &&
35         git checkout master
36 '
37
38 # Configure a custom difftool.<tool>.cmd and use it
39 test_expect_success PERL 'custom commands' '
40         difftool_test_setup &&
41         test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" &&
42         echo master >expect &&
43         git difftool --no-prompt branch >actual &&
44         test_cmp expect actual &&
45
46         test_config difftool.test-tool.cmd "cat \"\$LOCAL\"" &&
47         echo branch >expect &&
48         git difftool --no-prompt branch >actual &&
49         test_cmp expect actual
50 '
51
52 test_expect_success PERL 'custom tool commands override built-ins' '
53         test_config difftool.vimdiff.cmd "cat \"\$REMOTE\"" &&
54         echo master >expect &&
55         git difftool --tool vimdiff --no-prompt branch >actual &&
56         test_cmp expect actual
57 '
58
59 test_expect_success PERL 'difftool ignores bad --tool values' '
60         : >expect &&
61         test_must_fail \
62                 git difftool --no-prompt --tool=bad-tool branch >actual &&
63         test_cmp expect actual
64 '
65
66 test_expect_success PERL 'difftool forwards arguments to diff' '
67         difftool_test_setup &&
68         >for-diff &&
69         git add for-diff &&
70         echo changes>for-diff &&
71         git add for-diff &&
72         : >expect &&
73         git difftool --cached --no-prompt -- for-diff >actual &&
74         test_cmp expect actual &&
75         git reset -- for-diff &&
76         rm for-diff
77 '
78
79 test_expect_success PERL 'difftool ignores exit code' '
80         test_config difftool.error.cmd false &&
81         git difftool -y -t error branch
82 '
83
84 test_expect_success PERL 'difftool forwards exit code with --trust-exit-code' '
85         test_config difftool.error.cmd false &&
86         test_must_fail git difftool -y --trust-exit-code -t error branch
87 '
88
89 test_expect_success PERL 'difftool honors difftool.trustExitCode = true' '
90         test_config difftool.error.cmd false &&
91         test_config difftool.trustExitCode true &&
92         test_must_fail git difftool -y -t error branch
93 '
94
95 test_expect_success PERL 'difftool honors difftool.trustExitCode = false' '
96         test_config difftool.error.cmd false &&
97         test_config difftool.trustExitCode false &&
98         git difftool -y -t error branch
99 '
100
101 test_expect_success PERL 'difftool ignores exit code with --no-trust-exit-code' '
102         test_config difftool.error.cmd false &&
103         test_config difftool.trustExitCode true &&
104         git difftool -y --no-trust-exit-code -t error branch
105 '
106
107 test_expect_success PERL 'difftool stops on error with --trust-exit-code' '
108         test_when_finished "rm -f for-diff .git/fail-right-file" &&
109         test_when_finished "git reset -- for-diff" &&
110         write_script .git/fail-right-file <<-\EOF &&
111         echo "$2"
112         exit 1
113         EOF
114         >for-diff &&
115         git add for-diff &&
116         echo file >expect &&
117         test_must_fail git difftool -y --trust-exit-code \
118                 --extcmd .git/fail-right-file branch >actual &&
119         test_cmp expect actual
120 '
121
122 test_expect_success PERL 'difftool honors --gui' '
123         difftool_test_setup &&
124         test_config merge.tool bogus-tool &&
125         test_config diff.tool bogus-tool &&
126         test_config diff.guitool test-tool &&
127
128         echo branch >expect &&
129         git difftool --no-prompt --gui branch >actual &&
130         test_cmp expect actual
131 '
132
133 test_expect_success PERL 'difftool --gui last setting wins' '
134         difftool_test_setup &&
135         : >expect &&
136         git difftool --no-prompt --gui --no-gui >actual &&
137         test_cmp expect actual &&
138
139         test_config merge.tool bogus-tool &&
140         test_config diff.tool bogus-tool &&
141         test_config diff.guitool test-tool &&
142         echo branch >expect &&
143         git difftool --no-prompt --no-gui --gui branch >actual &&
144         test_cmp expect actual
145 '
146
147 test_expect_success PERL 'difftool --gui works without configured diff.guitool' '
148         difftool_test_setup &&
149         echo branch >expect &&
150         git difftool --no-prompt --gui branch >actual &&
151         test_cmp expect actual
152 '
153
154 # Specify the diff tool using $GIT_DIFF_TOOL
155 test_expect_success PERL 'GIT_DIFF_TOOL variable' '
156         difftool_test_setup &&
157         git config --unset diff.tool &&
158         echo branch >expect &&
159         GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
160         test_cmp expect actual
161 '
162
163 # Test the $GIT_*_TOOL variables and ensure
164 # that $GIT_DIFF_TOOL always wins unless --tool is specified
165 test_expect_success PERL 'GIT_DIFF_TOOL overrides' '
166         difftool_test_setup &&
167         test_config diff.tool bogus-tool &&
168         test_config merge.tool bogus-tool &&
169
170         echo branch >expect &&
171         GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
172         test_cmp expect actual &&
173
174         test_config diff.tool bogus-tool &&
175         test_config merge.tool bogus-tool &&
176         GIT_DIFF_TOOL=bogus-tool \
177                 git difftool --no-prompt --tool=test-tool branch >actual &&
178         test_cmp expect actual
179 '
180
181 # Test that we don't have to pass --no-prompt to difftool
182 # when $GIT_DIFFTOOL_NO_PROMPT is true
183 test_expect_success PERL 'GIT_DIFFTOOL_NO_PROMPT variable' '
184         difftool_test_setup &&
185         echo branch >expect &&
186         GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual &&
187         test_cmp expect actual
188 '
189
190 # git-difftool supports the difftool.prompt variable.
191 # Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
192 test_expect_success PERL 'GIT_DIFFTOOL_PROMPT variable' '
193         difftool_test_setup &&
194         test_config difftool.prompt false &&
195         echo >input &&
196         GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
197         prompt=$(tail -1 <output) &&
198         prompt_given "$prompt"
199 '
200
201 # Test that we don't have to pass --no-prompt when difftool.prompt is false
202 test_expect_success PERL 'difftool.prompt config variable is false' '
203         difftool_test_setup &&
204         test_config difftool.prompt false &&
205         echo branch >expect &&
206         git difftool branch >actual &&
207         test_cmp expect actual
208 '
209
210 # Test that we don't have to pass --no-prompt when mergetool.prompt is false
211 test_expect_success PERL 'difftool merge.prompt = false' '
212         difftool_test_setup &&
213         test_might_fail git config --unset difftool.prompt &&
214         test_config mergetool.prompt false &&
215         echo branch >expect &&
216         git difftool branch >actual &&
217         test_cmp expect actual
218 '
219
220 # Test that the -y flag can override difftool.prompt = true
221 test_expect_success PERL 'difftool.prompt can overridden with -y' '
222         difftool_test_setup &&
223         test_config difftool.prompt true &&
224         echo branch >expect &&
225         git difftool -y branch >actual &&
226         test_cmp expect actual
227 '
228
229 # Test that the --prompt flag can override difftool.prompt = false
230 test_expect_success PERL 'difftool.prompt can overridden with --prompt' '
231         difftool_test_setup &&
232         test_config difftool.prompt false &&
233         echo >input &&
234         git difftool --prompt branch <input >output &&
235         prompt=$(tail -1 <output) &&
236         prompt_given "$prompt"
237 '
238
239 # Test that the last flag passed on the command-line wins
240 test_expect_success PERL 'difftool last flag wins' '
241         difftool_test_setup &&
242         echo branch >expect &&
243         git difftool --prompt --no-prompt branch >actual &&
244         test_cmp expect actual &&
245         echo >input &&
246         git difftool --no-prompt --prompt branch <input >output &&
247         prompt=$(tail -1 <output) &&
248         prompt_given "$prompt"
249 '
250
251 # git-difftool falls back to git-mergetool config variables
252 # so test that behavior here
253 test_expect_success PERL 'difftool + mergetool config variables' '
254         test_config merge.tool test-tool &&
255         test_config mergetool.test-tool.cmd "cat \$LOCAL" &&
256         echo branch >expect &&
257         git difftool --no-prompt branch >actual &&
258         test_cmp expect actual &&
259
260         # set merge.tool to something bogus, diff.tool to test-tool
261         test_config merge.tool bogus-tool &&
262         test_config diff.tool test-tool &&
263         git difftool --no-prompt branch >actual &&
264         test_cmp expect actual
265 '
266
267 test_expect_success PERL 'difftool.<tool>.path' '
268         test_config difftool.tkdiff.path echo &&
269         git difftool --tool=tkdiff --no-prompt branch >output &&
270         lines=$(grep file output | wc -l) &&
271         test "$lines" -eq 1
272 '
273
274 test_expect_success PERL 'difftool --extcmd=cat' '
275         echo branch >expect &&
276         echo master >>expect &&
277         git difftool --no-prompt --extcmd=cat branch >actual &&
278         test_cmp expect actual
279 '
280
281 test_expect_success PERL 'difftool --extcmd cat' '
282         echo branch >expect &&
283         echo master >>expect &&
284         git difftool --no-prompt --extcmd=cat branch >actual &&
285         test_cmp expect actual
286 '
287
288 test_expect_success PERL 'difftool -x cat' '
289         echo branch >expect &&
290         echo master >>expect &&
291         git difftool --no-prompt -x cat branch >actual &&
292         test_cmp expect actual
293 '
294
295 test_expect_success PERL 'difftool --extcmd echo arg1' '
296         echo file >expect &&
297         git difftool --no-prompt \
298                 --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
299         test_cmp expect actual
300 '
301
302 test_expect_success PERL 'difftool --extcmd cat arg1' '
303         echo master >expect &&
304         git difftool --no-prompt \
305                 --extcmd sh\ -c\ \"cat\ \$1\" branch >actual &&
306         test_cmp expect actual
307 '
308
309 test_expect_success PERL 'difftool --extcmd cat arg2' '
310         echo branch >expect &&
311         git difftool --no-prompt \
312                 --extcmd sh\ -c\ \"cat\ \$2\" branch >actual &&
313         test_cmp expect actual
314 '
315
316 # Create a second file on master and a different version on branch
317 test_expect_success PERL 'setup with 2 files different' '
318         echo m2 >file2 &&
319         git add file2 &&
320         git commit -m "added file2" &&
321
322         git checkout branch &&
323         echo br2 >file2 &&
324         git add file2 &&
325         git commit -a -m "branch changed file2" &&
326         git checkout master
327 '
328
329 test_expect_success PERL 'say no to the first file' '
330         (echo n && echo) >input &&
331         git difftool -x cat branch <input >output &&
332         grep m2 output &&
333         grep br2 output &&
334         ! grep master output &&
335         ! grep branch output
336 '
337
338 test_expect_success PERL 'say no to the second file' '
339         (echo && echo n) >input &&
340         git difftool -x cat branch <input >output &&
341         grep master output &&
342         grep branch output &&
343         ! grep m2 output &&
344         ! grep br2 output
345 '
346
347 test_expect_success PERL 'ending prompt input with EOF' '
348         git difftool -x cat branch </dev/null >output &&
349         ! grep master output &&
350         ! grep branch output &&
351         ! grep m2 output &&
352         ! grep br2 output
353 '
354
355 test_expect_success PERL 'difftool --tool-help' '
356         git difftool --tool-help >output &&
357         grep tool output
358 '
359
360 test_expect_success PERL 'setup change in subdirectory' '
361         git checkout master &&
362         mkdir sub &&
363         echo master >sub/sub &&
364         git add sub/sub &&
365         git commit -m "added sub/sub" &&
366         echo test >>file &&
367         echo test >>sub/sub &&
368         git add file sub/sub &&
369         git commit -m "modified both"
370 '
371
372 run_dir_diff_test () {
373         test_expect_success PERL "$1 --no-symlinks" "
374                 symlinks=--no-symlinks &&
375                 $2
376         "
377         test_expect_success PERL,SYMLINKS "$1 --symlinks" "
378                 symlinks=--symlinks &&
379                 $2
380         "
381 }
382
383 run_dir_diff_test 'difftool -d' '
384         git difftool -d $symlinks --extcmd ls branch >output &&
385         grep sub output &&
386         grep file output
387 '
388
389 run_dir_diff_test 'difftool --dir-diff' '
390         git difftool --dir-diff $symlinks --extcmd ls branch >output &&
391         grep sub output &&
392         grep file output
393 '
394
395 run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
396         git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
397         grep sub output &&
398         grep file output
399 '
400
401 run_dir_diff_test 'difftool --dir-diff from subdirectory' '
402         (
403                 cd sub &&
404                 git difftool --dir-diff $symlinks --extcmd ls branch >output &&
405                 grep sub output &&
406                 grep file output
407         )
408 '
409
410 run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
411         test_when_finished git reset --hard &&
412         rm file2 &&
413         git difftool --dir-diff $symlinks --extcmd ls branch master >output &&
414         grep file2 output
415 '
416
417 write_script .git/CHECK_SYMLINKS <<\EOF
418 for f in file file2 sub/sub
419 do
420         echo "$f"
421         readlink "$2/$f"
422 done >actual
423 EOF
424
425 test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
426         cat >expect <<-EOF &&
427         file
428         $(pwd)/file
429         file2
430         $(pwd)/file2
431         sub/sub
432         $(pwd)/sub/sub
433         EOF
434         git difftool --dir-diff --symlink \
435                 --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
436         test_cmp actual expect
437 '
438
439 write_script modify-right-file <<\EOF
440 echo "new content" >"$2/file"
441 EOF
442
443 run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
444         test_when_finished git reset --hard &&
445         echo "orig content" >file &&
446         git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch &&
447         echo "new content" >expect &&
448         test_cmp expect file
449 '
450
451 run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
452         test_when_finished git reset --hard &&
453         git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch &&
454         echo "new content" >expect &&
455         test_cmp expect file
456 '
457
458 write_script modify-file <<\EOF
459 echo "new content" >file
460 EOF
461
462 test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
463         echo "orig content" >file &&
464         git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch &&
465         echo "new content" >expect &&
466         test_cmp expect file
467 '
468
469 write_script modify-both-files <<\EOF
470 echo "wt content" >file &&
471 echo "tmp content" >"$2/file" &&
472 echo "$2" >tmpdir
473 EOF
474
475 test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
476         (
477                 TMPDIR=$TRASH_DIRECTORY &&
478                 export TMPDIR &&
479                 echo "orig content" >file &&
480                 test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch &&
481                 echo "wt content" >expect &&
482                 test_cmp expect file &&
483                 echo "tmp content" >expect &&
484                 test_cmp expect "$(cat tmpdir)/file"
485         )
486 '
487
488 test_expect_success PERL 'difftool properly honors gitlink and core.worktree' '
489         git submodule add ./. submod/ule &&
490         (
491                 cd submod/ule &&
492                 test_config diff.tool checktrees &&
493                 test_config difftool.checktrees.cmd '\''
494                         test -d "$LOCAL" && test -d "$REMOTE" && echo good
495                 '\'' &&
496                 echo good >expect &&
497                 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
498                 test_cmp expect actual
499         )
500 '
501
502 test_done