3 # Copyright (c) 2009, 2010, 2012, 2013 David Aguilar
6 test_description='git-difftool
8 Testing basic diff tool invocation
13 difftool_test_setup ()
15 test_config diff.tool test-tool &&
16 test_config difftool.test-tool.cmd 'cat "$LOCAL"' &&
17 test_config difftool.bogus-tool.cmd false
23 test "$prompt" = "Launch 'test-tool' [Y/n]? branch"
26 # Create a file on master and change it on branch
27 test_expect_success 'setup' '
30 git commit -m "added file" &&
32 git checkout -b branch master &&
34 git commit -a -m "branch changed file" &&
38 # Configure a custom difftool.<tool>.cmd and use it
39 test_expect_success '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 &&
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
52 test_expect_success '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
59 test_expect_success 'difftool ignores bad --tool values' '
62 git difftool --no-prompt --tool=bad-tool branch >actual &&
63 test_cmp expect actual
66 test_expect_success 'difftool forwards arguments to diff' '
67 difftool_test_setup &&
70 echo changes>for-diff &&
73 git difftool --cached --no-prompt -- for-diff >actual &&
74 test_cmp expect actual &&
75 git reset -- for-diff &&
79 test_expect_success 'difftool ignores exit code' '
80 test_config difftool.error.cmd false &&
81 git difftool -y -t error branch
84 test_expect_success '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
89 test_expect_success '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
94 test_expect_success '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
100 test_expect_success '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
106 test_expect_success '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
112 test_expect_success '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 &&
122 test_must_fail git difftool -y --trust-exit-code \
123 --extcmd .git/fail-right-file branch >actual &&
124 test_cmp expect actual
127 test_expect_success '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
133 test_expect_success '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 &&
139 echo branch >expect &&
140 git difftool --no-prompt --gui branch >actual &&
141 test_cmp expect actual
144 test_expect_success 'difftool --gui last setting wins' '
145 difftool_test_setup &&
147 git difftool --no-prompt --gui --no-gui >actual &&
148 test_cmp expect actual &&
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
158 test_expect_success '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
165 # Specify the diff tool using $GIT_DIFF_TOOL
166 test_expect_success '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
174 # Test the $GIT_*_TOOL variables and ensure
175 # that $GIT_DIFF_TOOL always wins unless --tool is specified
176 test_expect_success 'GIT_DIFF_TOOL overrides' '
177 difftool_test_setup &&
178 test_config diff.tool bogus-tool &&
179 test_config merge.tool bogus-tool &&
181 echo branch >expect &&
182 GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
183 test_cmp expect actual &&
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
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 '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
201 # git-difftool supports the difftool.prompt variable.
202 # Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
203 test_expect_success 'GIT_DIFFTOOL_PROMPT variable' '
204 difftool_test_setup &&
205 test_config difftool.prompt false &&
207 GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
208 prompt=$(tail -1 <output) &&
209 prompt_given "$prompt"
212 # Test that we don't have to pass --no-prompt when difftool.prompt is false
213 test_expect_success '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
221 # Test that we don't have to pass --no-prompt when mergetool.prompt is false
222 test_expect_success '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
231 # Test that the -y flag can override difftool.prompt = true
232 test_expect_success '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
240 # Test that the --prompt flag can override difftool.prompt = false
241 test_expect_success 'difftool.prompt can overridden with --prompt' '
242 difftool_test_setup &&
243 test_config difftool.prompt false &&
245 git difftool --prompt branch <input >output &&
246 prompt=$(tail -1 <output) &&
247 prompt_given "$prompt"
250 # Test that the last flag passed on the command-line wins
251 test_expect_success '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 &&
257 git difftool --no-prompt --prompt branch <input >output &&
258 prompt=$(tail -1 <output) &&
259 prompt_given "$prompt"
262 # git-difftool falls back to git-mergetool config variables
263 # so test that behavior here
264 test_expect_success '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 &&
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
278 test_expect_success '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) &&
285 test_expect_success '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
292 test_expect_success '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
299 test_expect_success '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
306 test_expect_success 'difftool --extcmd echo arg1' '
308 git difftool --no-prompt \
309 --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
310 test_cmp expect actual
313 test_expect_success '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
320 test_expect_success '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
327 # Create a second file on master and a different version on branch
328 test_expect_success 'setup with 2 files different' '
331 git commit -m "added file2" &&
333 git checkout branch &&
336 git commit -a -m "branch changed file2" &&
340 test_expect_success 'say no to the first file' '
341 (echo n && echo) >input &&
342 git difftool -x cat branch <input >output &&
345 ! grep master output &&
349 test_expect_success '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 &&
358 test_expect_success 'ending prompt input with EOF' '
359 git difftool -x cat branch </dev/null >output &&
360 ! grep master output &&
361 ! grep branch output &&
366 test_expect_success 'difftool --tool-help' '
367 git difftool --tool-help >output &&
371 test_expect_success 'setup change in subdirectory' '
372 git checkout master &&
374 echo master >sub/sub &&
376 git commit -m "added sub/sub" &&
379 echo test >>sub/sub &&
380 git add file sub/sub &&
381 git commit -m "modified both"
384 run_dir_diff_test () {
385 test_expect_success "$1 --no-symlinks" "
386 symlinks=--no-symlinks &&
389 test_expect_success SYMLINKS "$1 --symlinks" "
390 symlinks=--symlinks &&
395 run_dir_diff_test 'difftool -d' '
396 git difftool -d $symlinks --extcmd ls branch >output &&
401 run_dir_diff_test 'difftool --dir-diff' '
402 git difftool --dir-diff $symlinks --extcmd ls branch >output &&
407 run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
408 git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
413 run_dir_diff_test 'difftool --dir-diff branch from subdirectory' '
416 git difftool --dir-diff $symlinks --extcmd ls branch >output &&
417 # "sub" must only exist in "right"
418 # "file" and "file2" must be listed in both "left" and "right"
419 test "1" = $(grep sub output | wc -l) &&
420 test "2" = $(grep file"$" output | wc -l) &&
421 test "2" = $(grep file2 output | wc -l)
425 run_dir_diff_test 'difftool --dir-diff v1 from subdirectory' '
428 git difftool --dir-diff $symlinks --extcmd ls v1 >output &&
429 # "sub" and "file" exist in both v1 and HEAD.
430 # "file2" is unchanged.
431 test "2" = $(grep sub output | wc -l) &&
432 test "2" = $(grep file output | wc -l) &&
433 test "0" = $(grep file2 output | wc -l)
437 run_dir_diff_test 'difftool --dir-diff branch from subdirectory w/ pathspec' '
440 git difftool --dir-diff $symlinks --extcmd ls branch -- .>output &&
441 # "sub" only exists in "right"
442 # "file" and "file2" must not be listed
443 test "1" = $(grep sub output | wc -l) &&
444 test "0" = $(grep file output | wc -l)
448 run_dir_diff_test 'difftool --dir-diff v1 from subdirectory w/ pathspec' '
451 git difftool --dir-diff $symlinks --extcmd ls v1 -- .>output &&
452 # "sub" exists in v1 and HEAD
453 # "file" is filtered out by the pathspec
454 test "2" = $(grep sub output | wc -l) &&
455 test "0" = $(grep file output | wc -l)
459 run_dir_diff_test 'difftool --dir-diff from subdirectory with GIT_DIR set' '
461 GIT_DIR=$(pwd)/.git &&
463 GIT_WORK_TREE=$(pwd) &&
464 export GIT_WORK_TREE &&
466 git difftool --dir-diff $symlinks --extcmd ls \
467 branch -- sub >output &&
473 run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
474 test_when_finished git reset --hard &&
476 git difftool --dir-diff $symlinks --extcmd ls branch master >output &&
480 run_dir_diff_test 'difftool --dir-diff with unmerged files' '
481 test_when_finished git reset --hard &&
482 test_config difftool.echo.cmd "echo ok" &&
483 git checkout -B conflict-a &&
484 git checkout -B conflict-b &&
485 git checkout conflict-a &&
488 git commit -m conflict-a &&
489 git checkout conflict-b &&
492 git commit -m conflict-b &&
493 git checkout master &&
494 git merge conflict-a &&
495 test_must_fail git merge conflict-b &&
496 cat >expect <<-EOF &&
499 git difftool --dir-diff $symlinks -t echo >actual &&
500 test_cmp expect actual
503 write_script .git/CHECK_SYMLINKS <<\EOF
504 for f in file file2 sub/sub
507 ls -ld "$2/$f" | sed -e 's/.* -> //'
511 test_expect_success SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
512 cat >expect <<-EOF &&
520 git difftool --dir-diff --symlink \
521 --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
522 test_cmp actual expect
525 write_script modify-right-file <<\EOF
526 echo "new content" >"$2/file"
529 run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
530 test_when_finished git reset --hard &&
531 echo "orig content" >file &&
532 git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
533 echo "new content" >expect &&
537 run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
538 test_when_finished git reset --hard &&
539 git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
540 echo "new content" >expect &&
544 write_script modify-file <<\EOF
545 echo "new content" >file
548 test_expect_success 'difftool --no-symlinks does not overwrite working tree file ' '
549 echo "orig content" >file &&
550 git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch &&
551 echo "new content" >expect &&
555 write_script modify-both-files <<\EOF
556 echo "wt content" >file &&
557 echo "tmp content" >"$2/file" &&
561 test_expect_success 'difftool --no-symlinks detects conflict ' '
563 TMPDIR=$TRASH_DIRECTORY &&
565 echo "orig content" >file &&
566 test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch &&
567 echo "wt content" >expect &&
568 test_cmp expect file &&
569 echo "tmp content" >expect &&
570 test_cmp expect "$(cat tmpdir)/file"
574 test_expect_success 'difftool properly honors gitlink and core.worktree' '
575 git submodule add ./. submod/ule &&
576 test_config -C submod/ule diff.tool checktrees &&
577 test_config -C submod/ule difftool.checktrees.cmd '\''
578 test -d "$LOCAL" && test -d "$REMOTE" && echo good
583 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
584 test_cmp expect actual
588 test_expect_success SYMLINKS 'difftool --dir-diff symlinked directories' '
592 git config diff.tool checktrees &&
593 git config difftool.checktrees.cmd "echo good" &&
597 test_commit symlink-one &&
600 test_commit symlink-two &&
602 git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
603 test_cmp expect actual