Raw
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 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
12 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
13
14 . ./test-lib.sh
15
16 difftool_test_setup ()
17 {
18 test_config diff.tool test-tool &&
19 test_config difftool.test-tool.cmd 'cat "$LOCAL"' &&
20 test_config difftool.bogus-tool.cmd false
21 }
22
23 prompt_given ()
24 {
25 prompt="$1"
26 test "$prompt" = "Launch 'test-tool' [Y/n]? branch"
27 }
28
29 test_expect_success 'basic usage requires no repo' '
30 git difftool -h >output &&
31 test_grep ^usage: output &&
32 # create a ceiling directory to prevent Git from finding a repo
33 mkdir -p not/repo &&
34 test_when_finished rm -r not &&
35 env GIT_CEILING_DIRECTORIES="$(pwd)/not" \
36 git -C not/repo difftool -h >output &&
37 test_grep ^usage: output
38 '
39
40 # Create a file on main and change it on branch
41 test_expect_success 'setup' '
42 echo main >file &&
43 git add file &&
44 git commit -m "added file" &&
45
46 git checkout -b branch main &&
47 echo branch >file &&
48 git commit -a -m "branch changed file" &&
49 git checkout main
50 '
51
52 # Configure a custom difftool.<tool>.cmd and use it
53 test_expect_success 'custom commands' '
54 difftool_test_setup &&
55 test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" &&
56 echo main >expect &&
57 git difftool --no-prompt branch >actual &&
58 test_cmp expect actual &&
59
60 test_config difftool.test-tool.cmd "cat \"\$LOCAL\"" &&
61 echo branch >expect &&
62 git difftool --no-prompt branch >actual &&
63 test_cmp expect actual
64 '
65
66 test_expect_success 'custom tool commands override built-ins' '
67 test_config difftool.vimdiff.cmd "cat \"\$REMOTE\"" &&
68 echo main >expect &&
69 git difftool --tool vimdiff --no-prompt branch >actual &&
70 test_cmp expect actual
71 '
72
73 test_expect_success 'difftool ignores bad --tool values' '
74 : >expect &&
75 test_must_fail \
76 git difftool --no-prompt --tool=bad-tool branch >actual &&
77 test_cmp expect actual
78 '
79
80 test_expect_success 'difftool forwards arguments to diff' '
81 difftool_test_setup &&
82 >for-diff &&
83 git add for-diff &&
84 echo changes>for-diff &&
85 git add for-diff &&
86 : >expect &&
87 git difftool --cached --no-prompt -- for-diff >actual &&
88 test_cmp expect actual &&
89 git reset -- for-diff &&
90 rm for-diff
91 '
92
93 for opt in '' '--dir-diff'
94 do
95 test_expect_success "difftool ${opt:-without options} ignores exit code" '
96 test_config difftool.error.cmd false &&
97 git difftool ${opt} -y -t error branch
98 '
99
100 test_expect_success "difftool ${opt:-without options} forwards exit code with --trust-exit-code" '
101 test_config difftool.error.cmd false &&
102 test_must_fail git difftool ${opt} -y --trust-exit-code -t error branch
103 '
104
105 test_expect_success "difftool ${opt:-without options} forwards exit code with --trust-exit-code for built-ins" '
106 test_config difftool.vimdiff.path false &&
107 test_must_fail git difftool ${opt} -y --trust-exit-code -t vimdiff branch
108 '
109
110 test_expect_success "difftool ${opt:-without options} honors difftool.trustExitCode = true" '
111 test_config difftool.error.cmd false &&
112 test_config difftool.trustExitCode true &&
113 test_must_fail git difftool ${opt} -y -t error branch
114 '
115
116 test_expect_success "difftool ${opt:-without options} honors difftool.trustExitCode = false" '
117 test_config difftool.error.cmd false &&
118 test_config difftool.trustExitCode false &&
119 git difftool ${opt} -y -t error branch
120 '
121
122 test_expect_success "difftool ${opt:-without options} ignores exit code with --no-trust-exit-code" '
123 test_config difftool.error.cmd false &&
124 test_config difftool.trustExitCode true &&
125 git difftool ${opt} -y --no-trust-exit-code -t error branch
126 '
127
128 test_expect_success "difftool ${opt:-without options} stops on error with --trust-exit-code" '
129 test_when_finished "rm -f for-diff .git/fail-right-file" &&
130 test_when_finished "git reset -- for-diff" &&
131 write_script .git/fail-right-file <<-\EOF &&
132 echo failed
133 exit 1
134 EOF
135 >for-diff &&
136 git add for-diff &&
137 test_must_fail git difftool ${opt} -y --trust-exit-code \
138 --extcmd .git/fail-right-file branch >actual &&
139 test_line_count = 1 actual
140 '
141
142 test_expect_success "difftool ${opt:-without options} honors exit status if command not found" '
143 test_config difftool.nonexistent.cmd i-dont-exist &&
144 test_config difftool.trustExitCode false &&
145 if test "${opt}" = --dir-diff
146 then
147 expected_code=127
148 else
149 expected_code=128
150 fi &&
151 test_expect_code ${expected_code} git difftool ${opt} -y -t nonexistent branch
152 '
153 done
154
155 test_expect_success 'difftool honors --gui' '
156 difftool_test_setup &&
157 test_config merge.tool bogus-tool &&
158 test_config diff.tool bogus-tool &&
159 test_config diff.guitool test-tool &&
160
161 echo branch >expect &&
162 git difftool --no-prompt --gui branch >actual &&
163 test_cmp expect actual
164 '
165
166 test_expect_success 'difftool with guiDefault auto selects gui tool when there is DISPLAY' '
167 difftool_test_setup &&
168 test_config merge.tool bogus-tool &&
169 test_config diff.tool bogus-tool &&
170 test_config diff.guitool test-tool &&
171 test_config difftool.guiDefault auto &&
172 DISPLAY=SOMETHING && export DISPLAY &&
173
174 echo branch >expect &&
175 git difftool --no-prompt branch >actual &&
176 test_cmp expect actual
177 '
178 test_expect_success 'difftool with guiDefault auto selects regular tool when no DISPLAY' '
179 difftool_test_setup &&
180 test_config diff.guitool bogus-tool &&
181 test_config diff.tool test-tool &&
182 test_config difftool.guiDefault Auto &&
183 DISPLAY= && export DISPLAY &&
184
185 echo branch >expect &&
186 git difftool --no-prompt branch >actual &&
187 test_cmp expect actual
188 '
189
190 test_expect_success 'difftool with guiDefault true selects gui tool' '
191 difftool_test_setup &&
192 test_config diff.tool bogus-tool &&
193 test_config diff.guitool test-tool &&
194 test_config difftool.guiDefault true &&
195
196 DISPLAY= && export DISPLAY &&
197 echo branch >expect &&
198 git difftool --no-prompt branch >actual &&
199 test_cmp expect actual &&
200
201 DISPLAY=Something && export DISPLAY &&
202 echo branch >expect &&
203 git difftool --no-prompt branch >actual &&
204 test_cmp expect actual
205 '
206
207 test_expect_success 'difftool --no-gui trumps config guiDefault' '
208 difftool_test_setup &&
209 test_config diff.guitool bogus-tool &&
210 test_config diff.tool test-tool &&
211 test_config difftool.guiDefault true &&
212
213 echo branch >expect &&
214 git difftool --no-prompt --no-gui branch >actual &&
215 test_cmp expect actual
216 '
217
218 test_expect_success 'difftool --gui last setting wins' '
219 difftool_test_setup &&
220 : >expect &&
221 git difftool --no-prompt --gui --no-gui >actual &&
222 test_cmp expect actual &&
223
224 test_config merge.tool bogus-tool &&
225 test_config diff.tool bogus-tool &&
226 test_config diff.guitool test-tool &&
227 echo branch >expect &&
228 git difftool --no-prompt --no-gui --gui branch >actual &&
229 test_cmp expect actual
230 '
231
232 test_expect_success 'difftool --gui works without configured diff.guitool' '
233 difftool_test_setup &&
234 echo branch >expect &&
235 git difftool --no-prompt --gui branch >actual &&
236 test_cmp expect actual
237 '
238
239 # Specify the diff tool using $GIT_DIFF_TOOL
240 test_expect_success 'GIT_DIFF_TOOL variable' '
241 difftool_test_setup &&
242 git config --unset diff.tool &&
243 echo branch >expect &&
244 GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
245 test_cmp expect actual
246 '
247
248 # Test the $GIT_*_TOOL variables and ensure
249 # that $GIT_DIFF_TOOL always wins unless --tool is specified
250 test_expect_success 'GIT_DIFF_TOOL overrides' '
251 difftool_test_setup &&
252 test_config diff.tool bogus-tool &&
253 test_config merge.tool bogus-tool &&
254
255 echo branch >expect &&
256 GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
257 test_cmp expect actual &&
258
259 test_config diff.tool bogus-tool &&
260 test_config merge.tool bogus-tool &&
261 GIT_DIFF_TOOL=bogus-tool \
262 git difftool --no-prompt --tool=test-tool branch >actual &&
263 test_cmp expect actual
264 '
265
266 # Test that we don't have to pass --no-prompt to difftool
267 # when $GIT_DIFFTOOL_NO_PROMPT is true
268 test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' '
269 difftool_test_setup &&
270 echo branch >expect &&
271 GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual &&
272 test_cmp expect actual
273 '
274
275 # git-difftool supports the difftool.prompt variable.
276 # Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
277 test_expect_success 'GIT_DIFFTOOL_PROMPT variable' '
278 difftool_test_setup &&
279 test_config difftool.prompt false &&
280 echo >input &&
281 GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
282 prompt=$(tail -1 <output) &&
283 prompt_given "$prompt"
284 '
285
286 # Test that we don't have to pass --no-prompt when difftool.prompt is false
287 test_expect_success 'difftool.prompt config variable is false' '
288 difftool_test_setup &&
289 test_config difftool.prompt false &&
290 echo branch >expect &&
291 git difftool branch >actual &&
292 test_cmp expect actual
293 '
294
295 # Test that we don't have to pass --no-prompt when mergetool.prompt is false
296 test_expect_success 'difftool merge.prompt = false' '
297 difftool_test_setup &&
298 test_might_fail git config --unset difftool.prompt &&
299 test_config mergetool.prompt false &&
300 echo branch >expect &&
301 git difftool branch >actual &&
302 test_cmp expect actual
303 '
304
305 # Test that the -y flag can override difftool.prompt = true
306 test_expect_success 'difftool.prompt can overridden with -y' '
307 difftool_test_setup &&
308 test_config difftool.prompt true &&
309 echo branch >expect &&
310 git difftool -y branch >actual &&
311 test_cmp expect actual
312 '
313
314 # Test that the --prompt flag can override difftool.prompt = false
315 test_expect_success 'difftool.prompt can overridden with --prompt' '
316 difftool_test_setup &&
317 test_config difftool.prompt false &&
318 echo >input &&
319 git difftool --prompt branch <input >output &&
320 prompt=$(tail -1 <output) &&
321 prompt_given "$prompt"
322 '
323
324 # Test that the last flag passed on the command-line wins
325 test_expect_success 'difftool last flag wins' '
326 difftool_test_setup &&
327 echo branch >expect &&
328 git difftool --prompt --no-prompt branch >actual &&
329 test_cmp expect actual &&
330 echo >input &&
331 git difftool --no-prompt --prompt branch <input >output &&
332 prompt=$(tail -1 <output) &&
333 prompt_given "$prompt"
334 '
335
336 # git-difftool falls back to git-mergetool config variables
337 # so test that behavior here
338 test_expect_success 'difftool + mergetool config variables' '
339 test_config merge.tool test-tool &&
340 test_config mergetool.test-tool.cmd "cat \$LOCAL" &&
341 echo branch >expect &&
342 git difftool --no-prompt branch >actual &&
343 test_cmp expect actual &&
344 git difftool --gui --no-prompt branch >actual &&
345 test_cmp expect actual &&
346
347 # set merge.tool to something bogus, diff.tool to test-tool
348 test_config merge.tool bogus-tool &&
349 test_config diff.tool test-tool &&
350 git difftool --no-prompt branch >actual &&
351 test_cmp expect actual &&
352 git difftool --gui --no-prompt branch >actual &&
353 test_cmp expect actual &&
354
355 # set merge.tool, diff.tool to something bogus, merge.guitool to test-tool
356 test_config diff.tool bogus-tool &&
357 test_config merge.guitool test-tool &&
358 git difftool --gui --no-prompt branch >actual &&
359 test_cmp expect actual &&
360
361 # set merge.tool, diff.tool, merge.guitool to something bogus, diff.guitool to test-tool
362 test_config merge.guitool bogus-tool &&
363 test_config diff.guitool test-tool &&
364 git difftool --gui --no-prompt branch >actual &&
365 test_cmp expect actual
366 '
367
368 test_expect_success 'difftool.<tool>.path' '
369 test_config difftool.tkdiff.path echo &&
370 git difftool --tool=tkdiff --no-prompt branch >output &&
371 grep file output >grep-output &&
372 test_line_count = 1 grep-output
373 '
374
375 test_expect_success 'difftool --extcmd=cat' '
376 echo branch >expect &&
377 echo main >>expect &&
378 git difftool --no-prompt --extcmd=cat branch >actual &&
379 test_cmp expect actual
380 '
381
382 test_expect_success 'difftool --extcmd cat' '
383 echo branch >expect &&
384 echo main >>expect &&
385 git difftool --no-prompt --extcmd=cat branch >actual &&
386 test_cmp expect actual
387 '
388
389 test_expect_success 'difftool -x cat' '
390 echo branch >expect &&
391 echo main >>expect &&
392 git difftool --no-prompt -x cat branch >actual &&
393 test_cmp expect actual
394 '
395
396 test_expect_success 'difftool --extcmd echo arg1' '
397 echo file >expect &&
398 git difftool --no-prompt \
399 --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
400 test_cmp expect actual
401 '
402
403 test_expect_success 'difftool --extcmd cat arg1' '
404 echo main >expect &&
405 git difftool --no-prompt \
406 --extcmd sh\ -c\ \"cat\ \$1\" branch >actual &&
407 test_cmp expect actual
408 '
409
410 test_expect_success 'difftool --extcmd cat arg2' '
411 echo branch >expect &&
412 git difftool --no-prompt \
413 --extcmd sh\ -c\ \"cat\ \\\"\$2\\\"\" branch >actual &&
414 test_cmp expect actual
415 '
416
417 # Create a second file on main and a different version on branch
418 test_expect_success 'setup with 2 files different' '
419 echo m2 >file2 &&
420 git add file2 &&
421 git commit -m "added file2" &&
422
423 git checkout branch &&
424 echo br2 >file2 &&
425 git add file2 &&
426 git commit -a -m "branch changed file2" &&
427 git checkout main
428 '
429
430 test_expect_success 'say no to the first file' '
431 (echo n && echo) >input &&
432 git difftool -x cat branch <input >output &&
433 test_grep m2 output &&
434 test_grep br2 output &&
435 test_grep ! main output &&
436 test_grep ! branch output
437 '
438
439 test_expect_success 'say no to the second file' '
440 (echo && echo n) >input &&
441 git difftool -x cat branch <input >output &&
442 test_grep main output &&
443 test_grep branch output &&
444 test_grep ! m2 output &&
445 test_grep ! br2 output
446 '
447
448 test_expect_success 'ending prompt input with EOF' '
449 git difftool -x cat branch </dev/null >output &&
450 test_grep ! main output &&
451 test_grep ! branch output &&
452 test_grep ! m2 output &&
453 test_grep ! br2 output
454 '
455
456 test_expect_success 'difftool --tool-help' '
457 git difftool --tool-help >output &&
458 test_grep tool output
459 '
460
461 test_expect_success 'setup change in subdirectory' '
462 git checkout main &&
463 mkdir sub &&
464 echo main >sub/sub &&
465 git add sub/sub &&
466 git commit -m "added sub/sub" &&
467 git tag v1 &&
468 echo test >>file &&
469 echo test >>sub/sub &&
470 git add file sub/sub &&
471 git commit -m "modified both"
472 '
473
474 test_expect_success 'difftool -d with growing paths' '
475 a=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
476 git init growing &&
477 (
478 cd growing &&
479 echo "test -f \"\$2/b\"" | write_script .git/test-for-b.sh &&
480 one=$(printf 1 | git hash-object -w --stdin) &&
481 two=$(printf 2 | git hash-object -w --stdin) &&
482 git update-index --add \
483 --cacheinfo 100644,$one,$a --cacheinfo 100644,$two,b &&
484 tree1=$(git write-tree) &&
485 git update-index --add \
486 --cacheinfo 100644,$two,$a --cacheinfo 100644,$one,b &&
487 tree2=$(git write-tree) &&
488 git checkout -- $a &&
489 git difftool -d --extcmd .git/test-for-b.sh $tree1 $tree2
490 )
491 '
492
493 run_dir_diff_test () {
494 test_expect_success "$1 --no-symlinks" "
495 symlinks=--no-symlinks &&
496 $2
497 "
498 test_expect_success SYMLINKS "$1 --symlinks" "
499 symlinks=--symlinks &&
500 $2
501 "
502 }
503
504 run_dir_diff_test 'difftool -d' '
505 git difftool -d $symlinks --extcmd ls branch >output &&
506 grep "^sub$" output &&
507 grep "^file$" output
508 '
509
510 run_dir_diff_test 'difftool --dir-diff' '
511 git difftool --dir-diff $symlinks --extcmd ls branch >output &&
512 grep "^sub$" output &&
513 grep "^file$" output
514 '
515
516 run_dir_diff_test 'difftool --dir-diff avoids repeated slashes in TMPDIR' '
517 TMPDIR="${TMPDIR:-/tmp}////" \
518 git difftool --dir-diff $symlinks --extcmd echo branch >output &&
519 grep -v // output >actual &&
520 test_line_count = 1 actual
521 '
522
523 run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
524 git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
525 grep "^sub$" output &&
526 grep "^file$" output
527 '
528
529 run_dir_diff_test 'difftool --dir-diff branch from subdirectory' '
530 (
531 cd sub &&
532 git difftool --dir-diff $symlinks --extcmd ls branch >output &&
533 # "sub" must only exist in "right"
534 # "file" and "file2" must be listed in both "left" and "right"
535 grep "^sub$" output >sub-output &&
536 test_line_count = 1 sub-output &&
537 grep "^file$" output >file-output &&
538 test_line_count = 2 file-output &&
539 grep "^file2$" output >file2-output &&
540 test_line_count = 2 file2-output
541 )
542 '
543
544 run_dir_diff_test 'difftool --dir-diff v1 from subdirectory' '
545 (
546 cd sub &&
547 git difftool --dir-diff $symlinks --extcmd ls v1 >output &&
548 # "sub" and "file" exist in both v1 and HEAD.
549 # "file2" is unchanged.
550 grep "^sub$" output >sub-output &&
551 test_line_count = 2 sub-output &&
552 grep "^file$" output >file-output &&
553 test_line_count = 2 file-output &&
554 ! grep "^file2$" output
555 )
556 '
557
558 run_dir_diff_test 'difftool --dir-diff branch from subdirectory w/ pathspec' '
559 (
560 cd sub &&
561 git difftool --dir-diff $symlinks --extcmd ls branch -- .>output &&
562 # "sub" only exists in "right"
563 # "file" and "file2" must not be listed
564 grep "^sub$" output >sub-output &&
565 test_line_count = 1 sub-output &&
566 ! grep "^file$" output
567 )
568 '
569
570 run_dir_diff_test 'difftool --dir-diff v1 from subdirectory w/ pathspec' '
571 (
572 cd sub &&
573 git difftool --dir-diff $symlinks --extcmd ls v1 -- .>output &&
574 # "sub" exists in v1 and HEAD
575 # "file" is filtered out by the pathspec
576 grep "^sub$" output >sub-output &&
577 test_line_count = 2 sub-output &&
578 ! grep "^file$" output
579 )
580 '
581
582 run_dir_diff_test 'difftool --dir-diff from subdirectory with GIT_DIR set' '
583 (
584 GIT_DIR=$(pwd)/.git &&
585 export GIT_DIR &&
586 GIT_WORK_TREE=$(pwd) &&
587 export GIT_WORK_TREE &&
588 cd sub &&
589 git difftool --dir-diff $symlinks --extcmd ls \
590 branch -- sub >output &&
591 grep "^sub$" output &&
592 ! grep "^file$" output
593 )
594 '
595
596 run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
597 test_when_finished git reset --hard &&
598 rm file2 &&
599 git difftool --dir-diff $symlinks --extcmd ls branch main >output &&
600 grep "^file2$" output
601 '
602
603 run_dir_diff_test 'difftool --dir-diff with unmerged files' '
604 test_when_finished git reset --hard &&
605 test_config difftool.echo.cmd "echo ok" &&
606 git checkout -B conflict-a &&
607 git checkout -B conflict-b &&
608 git checkout conflict-a &&
609 echo a >>file &&
610 git add file &&
611 git commit -m conflict-a &&
612 git checkout conflict-b &&
613 echo b >>file &&
614 git add file &&
615 git commit -m conflict-b &&
616 git checkout main &&
617 git merge conflict-a &&
618 test_must_fail git merge conflict-b &&
619 cat >expect <<-EOF &&
620 ok
621 EOF
622 git difftool --dir-diff $symlinks -t echo >actual &&
623 test_cmp expect actual
624 '
625
626 write_script .git/CHECK_SYMLINKS <<\EOF
627 for f in file file2 sub/sub
628 do
629 echo "$f"
630 ls -ld "$2/$f" | sed -e 's/.* -> //'
631 done >actual
632 EOF
633
634 test_expect_success SYMLINKS 'difftool --dir-diff --symlinks without unstaged changes' '
635 cat >expect <<-EOF &&
636 file
637 $PWD/file
638 file2
639 $PWD/file2
640 sub/sub
641 $PWD/sub/sub
642 EOF
643 git difftool --dir-diff --symlinks \
644 --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
645 test_cmp expect actual
646 '
647
648 write_script modify-right-file <<\EOF
649 echo "modified content" >"$2/file"
650 EOF
651
652 run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
653 test_when_finished git reset --hard &&
654 echo "orig content" >file &&
655 git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
656 echo "modified content" >expect &&
657 test_cmp expect file
658 '
659
660 run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
661 test_when_finished git reset --hard &&
662 git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
663 echo "modified content" >expect &&
664 test_cmp expect file
665 '
666
667 run_dir_diff_test 'difftool --dir-diff with no diff' '
668 git difftool -d main main
669 '
670
671 write_script modify-file <<\EOF
672 echo "new content" >file
673 EOF
674
675 test_expect_success 'difftool --no-symlinks does not overwrite working tree file ' '
676 echo "orig content" >file &&
677 git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch &&
678 echo "new content" >expect &&
679 test_cmp expect file
680 '
681
682 write_script modify-both-files <<\EOF
683 echo "wt content" >file &&
684 echo "tmp content" >"$2/file" &&
685 echo "$2" >tmpdir
686 EOF
687
688 test_expect_success 'difftool --no-symlinks detects conflict ' '
689 (
690 TMPDIR=$TRASH_DIRECTORY &&
691 export TMPDIR &&
692 echo "orig content" >file &&
693 test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch &&
694 echo "wt content" >expect &&
695 test_cmp expect file &&
696 echo "tmp content" >expect &&
697 test_cmp expect "$(cat tmpdir)/file"
698 )
699 '
700
701 test_expect_success 'difftool properly honors gitlink and core.worktree' '
702 test_when_finished rm -rf submod/ule &&
703 test_config_global protocol.file.allow always &&
704 git submodule add ./. submod/ule &&
705 test_config -C submod/ule diff.tool checktrees &&
706 test_config -C submod/ule difftool.checktrees.cmd '\''
707 test -d "$LOCAL" && test -d "$REMOTE" && echo good
708 '\'' &&
709 (
710 cd submod/ule &&
711 echo good >expect &&
712 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
713 test_cmp expect actual &&
714 rm -f expect actual
715 )
716 '
717
718 test_expect_success SYMLINKS 'difftool --dir-diff symlinked directories' '
719 test_when_finished git reset --hard &&
720 git init dirlinks &&
721 (
722 cd dirlinks &&
723 git config diff.tool checktrees &&
724 git config difftool.checktrees.cmd "echo good" &&
725 mkdir foo &&
726 : >foo/bar &&
727 git add foo/bar &&
728 test_commit symlink-one &&
729 ln -s foo link &&
730 git add link &&
731 test_commit symlink-two &&
732 echo good >expect &&
733 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
734 test_cmp expect actual
735 )
736 '
737
738 test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
739 test_when_finished git reset --hard &&
740 touch b &&
741 ln -s b c &&
742 git add b c &&
743 test_tick &&
744 git commit -m initial &&
745 touch d &&
746 rm c &&
747 ln -s d c &&
748 cat >expect <<-EOF &&
749 c
750
751 c
752 EOF
753 git difftool --symlinks --dir-diff --extcmd ls >output &&
754 grep -v ":\$" output >actual &&
755 test_cmp expect actual &&
756
757 git difftool --no-symlinks --dir-diff --extcmd ls >output &&
758 grep -v ":\$" output >actual &&
759 test_cmp expect actual &&
760
761 # The left side contains symlink "c" that points to "b"
762 test_config difftool.cat.cmd "cat \$LOCAL/c" &&
763 printf "%s\n" b >expect &&
764
765 git difftool --symlinks --dir-diff --tool cat >actual &&
766 test_cmp expect actual &&
767
768 git difftool --symlinks --no-symlinks --dir-diff --tool cat >actual &&
769 test_cmp expect actual &&
770
771 # The right side contains symlink "c" that points to "d"
772 test_config difftool.cat.cmd "cat \$REMOTE/c" &&
773 printf "%s\n" d >expect &&
774
775 git difftool --symlinks --dir-diff --tool cat >actual &&
776 test_cmp expect actual &&
777
778 git difftool --no-symlinks --dir-diff --tool cat >actual &&
779 test_cmp expect actual &&
780
781 # Deleted symlinks
782 rm -f c &&
783 cat >expect <<-EOF &&
784 c
785
786 EOF
787 git difftool --symlinks --dir-diff --extcmd ls >output &&
788 grep -v ":\$" output >actual &&
789 test_cmp expect actual &&
790
791 git difftool --no-symlinks --dir-diff --extcmd ls >output &&
792 grep -v ":\$" output >actual &&
793 test_cmp expect actual
794 '
795
796 test_expect_success SYMLINKS 'difftool --dir-diff writes symlinks as raw text' '
797 # Start out on a branch called "branch-init".
798 git init -b branch-init symlink-files &&
799 (
800 cd symlink-files &&
801 # This test ensures that symlinks are written as raw text.
802 # The "cat" tools output link and file contents.
803 git config difftool.cat-left-link.cmd "cat \"\$LOCAL/link\"" &&
804 git config difftool.cat-left-a.cmd "cat \"\$LOCAL/file-a\"" &&
805 git config difftool.cat-right-link.cmd "cat \"\$REMOTE/link\"" &&
806 git config difftool.cat-right-b.cmd "cat \"\$REMOTE/file-b\"" &&
807
808 # Record the empty initial state so that we can come back here
809 # later and not have to consider the any cases where difftool
810 # will create symlinks back into the worktree.
811 test_tick &&
812 git commit --allow-empty -m init &&
813
814 # Create a file called "file-a" with a symlink pointing to it.
815 git switch -c branch-a &&
816 echo a >file-a &&
817 ln -s file-a link &&
818 git add file-a link &&
819 test_tick &&
820 git commit -m link-to-file-a &&
821
822 # Create a file called "file-b" and point the symlink to it.
823 git switch -c branch-b &&
824 echo b >file-b &&
825 rm link &&
826 ln -s file-b link &&
827 git add file-b link &&
828 git rm file-a &&
829 test_tick &&
830 git commit -m link-to-file-b &&
831
832 # Checkout the initial branch so that the --symlinks behavior is
833 # not activated. The two directories should be completely
834 # independent with no symlinks pointing back here.
835 git switch branch-init &&
836
837 # The left link must be "file-a" and "file-a" must contain "a".
838 echo file-a >expect &&
839 git difftool --symlinks --dir-diff --tool cat-left-link \
840 branch-a branch-b >actual &&
841 test_cmp expect actual &&
842
843 echo a >expect &&
844 git difftool --symlinks --dir-diff --tool cat-left-a \
845 branch-a branch-b >actual &&
846 test_cmp expect actual &&
847
848 # The right link must be "file-b" and "file-b" must contain "b".
849 echo file-b >expect &&
850 git difftool --symlinks --dir-diff --tool cat-right-link \
851 branch-a branch-b >actual &&
852 test_cmp expect actual &&
853
854 echo b >expect &&
855 git difftool --symlinks --dir-diff --tool cat-right-b \
856 branch-a branch-b >actual &&
857 test_cmp expect actual
858 )
859 '
860
861 test_expect_success 'add -N and difftool -d' '
862 test_when_finished git reset --hard &&
863
864 test_write_lines A B C >intent-to-add &&
865 git add -N intent-to-add &&
866 git difftool --dir-diff --extcmd ls
867 '
868
869 test_expect_success 'difftool --cached with unmerged files' '
870 test_when_finished git reset --hard &&
871
872 test_commit conflicting &&
873 test_commit conflict-a conflict.t a &&
874 git reset --hard conflicting &&
875 test_commit conflict-b conflict.t b &&
876 test_must_fail git merge conflict-a &&
877
878 git difftool --cached --no-prompt >output &&
879 test_must_be_empty output
880 '
881
882 test_expect_success 'outside worktree' '
883 echo 1 >1 &&
884 echo 2 >2 &&
885 test_expect_code 1 nongit git \
886 -c diff.tool=echo -c difftool.echo.cmd="echo \$LOCAL \$REMOTE" \
887 difftool --no-prompt --no-index ../1 ../2 >actual &&
888 echo "../1 ../2" >expect &&
889 test_cmp expect actual
890 '
891
892 test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive' '
893 difftool_test_setup &&
894 test_must_fail git difftool --gui --tool=test-tool &&
895 test_must_fail git difftool --gui --extcmd=cat &&
896 test_must_fail git difftool --tool=test-tool --extcmd=cat &&
897 test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
898 '
899
900 test_expect_success 'difftool --rotate-to' '
901 difftool_test_setup &&
902 test_when_finished git reset --hard &&
903 echo 1 >1 &&
904 echo 2 >2 &&
905 echo 4 >4 &&
906 git add 1 2 4 &&
907 git commit -a -m "124" &&
908 git difftool --no-prompt --extcmd=cat --rotate-to="2" HEAD^ >output &&
909 cat >expect <<-\EOF &&
910 2
911 4
912 1
913 EOF
914 test_cmp output expect
915 '
916
917 test_expect_success 'difftool --skip-to' '
918 difftool_test_setup &&
919 test_when_finished git reset --hard &&
920 git difftool --no-prompt --extcmd=cat --skip-to="2" HEAD^ >output &&
921 cat >expect <<-\EOF &&
922 2
923 4
924 EOF
925 test_cmp output expect
926 '
927
928 test_expect_success 'difftool --rotate/skip-to error condition' '
929 test_must_fail git difftool --no-prompt --extcmd=cat --rotate-to="3" HEAD^ &&
930 test_must_fail git difftool --no-prompt --extcmd=cat --skip-to="3" HEAD^
931 '
932 test_done