Merge branch 'da/difftool' into maint
[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 run_dir_diff_test 'difftool --dir-diff with unmerged files' '
423         test_when_finished git reset --hard &&
424         test_config difftool.echo.cmd "echo ok" &&
425         git checkout -B conflict-a &&
426         git checkout -B conflict-b &&
427         git checkout conflict-a &&
428         echo a >>file &&
429         git add file &&
430         git commit -m conflict-a &&
431         git checkout conflict-b &&
432         echo b >>file &&
433         git add file &&
434         git commit -m conflict-b &&
435         git checkout master &&
436         git merge conflict-a &&
437         test_must_fail git merge conflict-b &&
438         cat >expect <<-EOF &&
439                 ok
440         EOF
441         git difftool --dir-diff $symlinks -t echo >actual &&
442         test_cmp expect actual
443 '
444
445 write_script .git/CHECK_SYMLINKS <<\EOF
446 for f in file file2 sub/sub
447 do
448         echo "$f"
449         readlink "$2/$f"
450 done >actual
451 EOF
452
453 test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
454         cat >expect <<-EOF &&
455         file
456         $PWD/file
457         file2
458         $PWD/file2
459         sub/sub
460         $PWD/sub/sub
461         EOF
462         git difftool --dir-diff --symlink \
463                 --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
464         test_cmp actual expect
465 '
466
467 write_script modify-right-file <<\EOF
468 echo "new content" >"$2/file"
469 EOF
470
471 run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
472         test_when_finished git reset --hard &&
473         echo "orig content" >file &&
474         git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
475         echo "new content" >expect &&
476         test_cmp expect file
477 '
478
479 run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
480         test_when_finished git reset --hard &&
481         git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
482         echo "new content" >expect &&
483         test_cmp expect file
484 '
485
486 write_script modify-file <<\EOF
487 echo "new content" >file
488 EOF
489
490 test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
491         echo "orig content" >file &&
492         git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch &&
493         echo "new content" >expect &&
494         test_cmp expect file
495 '
496
497 write_script modify-both-files <<\EOF
498 echo "wt content" >file &&
499 echo "tmp content" >"$2/file" &&
500 echo "$2" >tmpdir
501 EOF
502
503 test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
504         (
505                 TMPDIR=$TRASH_DIRECTORY &&
506                 export TMPDIR &&
507                 echo "orig content" >file &&
508                 test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch &&
509                 echo "wt content" >expect &&
510                 test_cmp expect file &&
511                 echo "tmp content" >expect &&
512                 test_cmp expect "$(cat tmpdir)/file"
513         )
514 '
515
516 test_expect_success PERL 'difftool properly honors gitlink and core.worktree' '
517         git submodule add ./. submod/ule &&
518         test_config -C submod/ule diff.tool checktrees &&
519         test_config -C submod/ule difftool.checktrees.cmd '\''
520                 test -d "$LOCAL" && test -d "$REMOTE" && echo good
521                 '\'' &&
522         (
523                 cd submod/ule &&
524                 echo good >expect &&
525                 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
526                 test_cmp expect actual
527         )
528 '
529
530 test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' '
531         git init dirlinks &&
532         (
533                 cd dirlinks &&
534                 git config diff.tool checktrees &&
535                 git config difftool.checktrees.cmd "echo good" &&
536                 mkdir foo &&
537                 : >foo/bar &&
538                 git add foo/bar &&
539                 test_commit symlink-one &&
540                 ln -s foo link &&
541                 git add link &&
542                 test_commit symlink-two &&
543                 echo good >expect &&
544                 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
545                 test_cmp expect actual
546         )
547 '
548
549 test_done