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