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