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