vcs-svn: move remaining repo_tree functions to fast_export.h
[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 exit status if command not found' '
128         test_config difftool.nonexistent.cmd i-dont-exist &&
129         test_config difftool.trustExitCode false &&
130         test_must_fail git difftool -y -t nonexistent branch
131 '
132
133 test_expect_success PERL 'difftool honors --gui' '
134         difftool_test_setup &&
135         test_config merge.tool bogus-tool &&
136         test_config diff.tool bogus-tool &&
137         test_config diff.guitool test-tool &&
138
139         echo branch >expect &&
140         git difftool --no-prompt --gui branch >actual &&
141         test_cmp expect actual
142 '
143
144 test_expect_success PERL 'difftool --gui last setting wins' '
145         difftool_test_setup &&
146         : >expect &&
147         git difftool --no-prompt --gui --no-gui >actual &&
148         test_cmp expect actual &&
149
150         test_config merge.tool bogus-tool &&
151         test_config diff.tool bogus-tool &&
152         test_config diff.guitool test-tool &&
153         echo branch >expect &&
154         git difftool --no-prompt --no-gui --gui branch >actual &&
155         test_cmp expect actual
156 '
157
158 test_expect_success PERL 'difftool --gui works without configured diff.guitool' '
159         difftool_test_setup &&
160         echo branch >expect &&
161         git difftool --no-prompt --gui branch >actual &&
162         test_cmp expect actual
163 '
164
165 # Specify the diff tool using $GIT_DIFF_TOOL
166 test_expect_success PERL 'GIT_DIFF_TOOL variable' '
167         difftool_test_setup &&
168         git config --unset diff.tool &&
169         echo branch >expect &&
170         GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
171         test_cmp expect actual
172 '
173
174 # Test the $GIT_*_TOOL variables and ensure
175 # that $GIT_DIFF_TOOL always wins unless --tool is specified
176 test_expect_success PERL 'GIT_DIFF_TOOL overrides' '
177         difftool_test_setup &&
178         test_config diff.tool bogus-tool &&
179         test_config merge.tool bogus-tool &&
180
181         echo branch >expect &&
182         GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
183         test_cmp expect actual &&
184
185         test_config diff.tool bogus-tool &&
186         test_config merge.tool bogus-tool &&
187         GIT_DIFF_TOOL=bogus-tool \
188                 git difftool --no-prompt --tool=test-tool branch >actual &&
189         test_cmp expect actual
190 '
191
192 # Test that we don't have to pass --no-prompt to difftool
193 # when $GIT_DIFFTOOL_NO_PROMPT is true
194 test_expect_success PERL 'GIT_DIFFTOOL_NO_PROMPT variable' '
195         difftool_test_setup &&
196         echo branch >expect &&
197         GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual &&
198         test_cmp expect actual
199 '
200
201 # git-difftool supports the difftool.prompt variable.
202 # Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
203 test_expect_success PERL 'GIT_DIFFTOOL_PROMPT variable' '
204         difftool_test_setup &&
205         test_config difftool.prompt false &&
206         echo >input &&
207         GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
208         prompt=$(tail -1 <output) &&
209         prompt_given "$prompt"
210 '
211
212 # Test that we don't have to pass --no-prompt when difftool.prompt is false
213 test_expect_success PERL 'difftool.prompt config variable is false' '
214         difftool_test_setup &&
215         test_config difftool.prompt false &&
216         echo branch >expect &&
217         git difftool branch >actual &&
218         test_cmp expect actual
219 '
220
221 # Test that we don't have to pass --no-prompt when mergetool.prompt is false
222 test_expect_success PERL 'difftool merge.prompt = false' '
223         difftool_test_setup &&
224         test_might_fail git config --unset difftool.prompt &&
225         test_config mergetool.prompt false &&
226         echo branch >expect &&
227         git difftool branch >actual &&
228         test_cmp expect actual
229 '
230
231 # Test that the -y flag can override difftool.prompt = true
232 test_expect_success PERL 'difftool.prompt can overridden with -y' '
233         difftool_test_setup &&
234         test_config difftool.prompt true &&
235         echo branch >expect &&
236         git difftool -y branch >actual &&
237         test_cmp expect actual
238 '
239
240 # Test that the --prompt flag can override difftool.prompt = false
241 test_expect_success PERL 'difftool.prompt can overridden with --prompt' '
242         difftool_test_setup &&
243         test_config difftool.prompt false &&
244         echo >input &&
245         git difftool --prompt branch <input >output &&
246         prompt=$(tail -1 <output) &&
247         prompt_given "$prompt"
248 '
249
250 # Test that the last flag passed on the command-line wins
251 test_expect_success PERL 'difftool last flag wins' '
252         difftool_test_setup &&
253         echo branch >expect &&
254         git difftool --prompt --no-prompt branch >actual &&
255         test_cmp expect actual &&
256         echo >input &&
257         git difftool --no-prompt --prompt branch <input >output &&
258         prompt=$(tail -1 <output) &&
259         prompt_given "$prompt"
260 '
261
262 # git-difftool falls back to git-mergetool config variables
263 # so test that behavior here
264 test_expect_success PERL 'difftool + mergetool config variables' '
265         test_config merge.tool test-tool &&
266         test_config mergetool.test-tool.cmd "cat \$LOCAL" &&
267         echo branch >expect &&
268         git difftool --no-prompt branch >actual &&
269         test_cmp expect actual &&
270
271         # set merge.tool to something bogus, diff.tool to test-tool
272         test_config merge.tool bogus-tool &&
273         test_config diff.tool test-tool &&
274         git difftool --no-prompt branch >actual &&
275         test_cmp expect actual
276 '
277
278 test_expect_success PERL 'difftool.<tool>.path' '
279         test_config difftool.tkdiff.path echo &&
280         git difftool --tool=tkdiff --no-prompt branch >output &&
281         lines=$(grep file output | wc -l) &&
282         test "$lines" -eq 1
283 '
284
285 test_expect_success PERL 'difftool --extcmd=cat' '
286         echo branch >expect &&
287         echo master >>expect &&
288         git difftool --no-prompt --extcmd=cat branch >actual &&
289         test_cmp expect actual
290 '
291
292 test_expect_success PERL 'difftool --extcmd cat' '
293         echo branch >expect &&
294         echo master >>expect &&
295         git difftool --no-prompt --extcmd=cat branch >actual &&
296         test_cmp expect actual
297 '
298
299 test_expect_success PERL 'difftool -x cat' '
300         echo branch >expect &&
301         echo master >>expect &&
302         git difftool --no-prompt -x cat branch >actual &&
303         test_cmp expect actual
304 '
305
306 test_expect_success PERL 'difftool --extcmd echo arg1' '
307         echo file >expect &&
308         git difftool --no-prompt \
309                 --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
310         test_cmp expect actual
311 '
312
313 test_expect_success PERL 'difftool --extcmd cat arg1' '
314         echo master >expect &&
315         git difftool --no-prompt \
316                 --extcmd sh\ -c\ \"cat\ \$1\" branch >actual &&
317         test_cmp expect actual
318 '
319
320 test_expect_success PERL 'difftool --extcmd cat arg2' '
321         echo branch >expect &&
322         git difftool --no-prompt \
323                 --extcmd sh\ -c\ \"cat\ \$2\" branch >actual &&
324         test_cmp expect actual
325 '
326
327 # Create a second file on master and a different version on branch
328 test_expect_success PERL 'setup with 2 files different' '
329         echo m2 >file2 &&
330         git add file2 &&
331         git commit -m "added file2" &&
332
333         git checkout branch &&
334         echo br2 >file2 &&
335         git add file2 &&
336         git commit -a -m "branch changed file2" &&
337         git checkout master
338 '
339
340 test_expect_success PERL 'say no to the first file' '
341         (echo n && echo) >input &&
342         git difftool -x cat branch <input >output &&
343         grep m2 output &&
344         grep br2 output &&
345         ! grep master output &&
346         ! grep branch output
347 '
348
349 test_expect_success PERL 'say no to the second file' '
350         (echo && echo n) >input &&
351         git difftool -x cat branch <input >output &&
352         grep master output &&
353         grep branch output &&
354         ! grep m2 output &&
355         ! grep br2 output
356 '
357
358 test_expect_success PERL 'ending prompt input with EOF' '
359         git difftool -x cat branch </dev/null >output &&
360         ! grep master output &&
361         ! grep branch output &&
362         ! grep m2 output &&
363         ! grep br2 output
364 '
365
366 test_expect_success PERL 'difftool --tool-help' '
367         git difftool --tool-help >output &&
368         grep tool output
369 '
370
371 test_expect_success PERL 'setup change in subdirectory' '
372         git checkout master &&
373         mkdir sub &&
374         echo master >sub/sub &&
375         git add sub/sub &&
376         git commit -m "added sub/sub" &&
377         echo test >>file &&
378         echo test >>sub/sub &&
379         git add file sub/sub &&
380         git commit -m "modified both"
381 '
382
383 run_dir_diff_test () {
384         test_expect_success PERL "$1 --no-symlinks" "
385                 symlinks=--no-symlinks &&
386                 $2
387         "
388         test_expect_success PERL,SYMLINKS "$1 --symlinks" "
389                 symlinks=--symlinks &&
390                 $2
391         "
392 }
393
394 run_dir_diff_test 'difftool -d' '
395         git difftool -d $symlinks --extcmd ls branch >output &&
396         grep sub output &&
397         grep file output
398 '
399
400 run_dir_diff_test 'difftool --dir-diff' '
401         git difftool --dir-diff $symlinks --extcmd ls branch >output &&
402         grep sub output &&
403         grep file output
404 '
405
406 run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
407         git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
408         grep sub output &&
409         grep file output
410 '
411
412 run_dir_diff_test 'difftool --dir-diff from subdirectory' '
413         (
414                 cd sub &&
415                 git difftool --dir-diff $symlinks --extcmd ls branch >output &&
416                 grep sub output &&
417                 grep file output
418         )
419 '
420
421 run_dir_diff_test 'difftool --dir-diff from subdirectory with GIT_DIR set' '
422         (
423                 GIT_DIR=$(pwd)/.git &&
424                 export GIT_DIR &&
425                 GIT_WORK_TREE=$(pwd) &&
426                 export GIT_WORK_TREE &&
427                 cd sub &&
428                 git difftool --dir-diff $symlinks --extcmd ls \
429                         branch -- sub >output &&
430                 grep sub output &&
431                 ! grep file output
432         )
433 '
434
435 run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
436         test_when_finished git reset --hard &&
437         rm file2 &&
438         git difftool --dir-diff $symlinks --extcmd ls branch master >output &&
439         grep file2 output
440 '
441
442 run_dir_diff_test 'difftool --dir-diff with unmerged files' '
443         test_when_finished git reset --hard &&
444         test_config difftool.echo.cmd "echo ok" &&
445         git checkout -B conflict-a &&
446         git checkout -B conflict-b &&
447         git checkout conflict-a &&
448         echo a >>file &&
449         git add file &&
450         git commit -m conflict-a &&
451         git checkout conflict-b &&
452         echo b >>file &&
453         git add file &&
454         git commit -m conflict-b &&
455         git checkout master &&
456         git merge conflict-a &&
457         test_must_fail git merge conflict-b &&
458         cat >expect <<-EOF &&
459                 ok
460         EOF
461         git difftool --dir-diff $symlinks -t echo >actual &&
462         test_cmp expect actual
463 '
464
465 write_script .git/CHECK_SYMLINKS <<\EOF
466 for f in file file2 sub/sub
467 do
468         echo "$f"
469         ls -ld "$2/$f" | sed -e 's/.* -> //'
470 done >actual
471 EOF
472
473 test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
474         cat >expect <<-EOF &&
475         file
476         $PWD/file
477         file2
478         $PWD/file2
479         sub/sub
480         $PWD/sub/sub
481         EOF
482         git difftool --dir-diff --symlink \
483                 --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
484         test_cmp actual expect
485 '
486
487 write_script modify-right-file <<\EOF
488 echo "new content" >"$2/file"
489 EOF
490
491 run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
492         test_when_finished git reset --hard &&
493         echo "orig content" >file &&
494         git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
495         echo "new content" >expect &&
496         test_cmp expect file
497 '
498
499 run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
500         test_when_finished git reset --hard &&
501         git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
502         echo "new content" >expect &&
503         test_cmp expect file
504 '
505
506 write_script modify-file <<\EOF
507 echo "new content" >file
508 EOF
509
510 test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
511         echo "orig content" >file &&
512         git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch &&
513         echo "new content" >expect &&
514         test_cmp expect file
515 '
516
517 write_script modify-both-files <<\EOF
518 echo "wt content" >file &&
519 echo "tmp content" >"$2/file" &&
520 echo "$2" >tmpdir
521 EOF
522
523 test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
524         (
525                 TMPDIR=$TRASH_DIRECTORY &&
526                 export TMPDIR &&
527                 echo "orig content" >file &&
528                 test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch &&
529                 echo "wt content" >expect &&
530                 test_cmp expect file &&
531                 echo "tmp content" >expect &&
532                 test_cmp expect "$(cat tmpdir)/file"
533         )
534 '
535
536 test_expect_success PERL 'difftool properly honors gitlink and core.worktree' '
537         git submodule add ./. submod/ule &&
538         test_config -C submod/ule diff.tool checktrees &&
539         test_config -C submod/ule difftool.checktrees.cmd '\''
540                 test -d "$LOCAL" && test -d "$REMOTE" && echo good
541                 '\'' &&
542         (
543                 cd submod/ule &&
544                 echo good >expect &&
545                 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
546                 test_cmp expect actual
547         )
548 '
549
550 test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' '
551         git init dirlinks &&
552         (
553                 cd dirlinks &&
554                 git config diff.tool checktrees &&
555                 git config difftool.checktrees.cmd "echo good" &&
556                 mkdir foo &&
557                 : >foo/bar &&
558                 git add foo/bar &&
559                 test_commit symlink-one &&
560                 ln -s foo link &&
561                 git add link &&
562                 test_commit symlink-two &&
563                 echo good >expect &&
564                 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
565                 test_cmp expect actual
566         )
567 '
568
569 test_done